blob: 6bf6cd9a92f6a3fc9acf78900d590279e6c03f2f [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 Tarreau4c7e4b72020-05-27 12:58:42 +020017#include <haproxy/api.h>
Frédéric Lécailled456aa42019-03-08 14:47:00 +010018#include <common/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020019#include <haproxy/cli.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020020#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020021#include <haproxy/http_rules.h>
Willy Tarreaud0ef4392020-06-02 09:38:52 +020022#include <haproxy/pool.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020023#include <haproxy/list.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020024#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020025#include <haproxy/peers.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020026#include <haproxy/stats-t.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020027#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020028#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020029#include <haproxy/tcp_rules.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020030#include <haproxy/tools.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020031#include <haproxy/time.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010032
Willy Tarreau8d2b7772020-05-27 10:58:19 +020033#include <import/ebmbtree.h>
34#include <import/ebsttree.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010035
Willy Tarreauaa74c4e2020-06-04 10:19:23 +020036#include <haproxy/arg.h>
Andjelko Iharosc3680ec2017-07-20 16:49:14 +020037#include <proto/log.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020038#include <proto/http_ana.h>
Willy Tarreaufc774542020-06-04 17:31:04 +020039#include <haproxy/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010040#include <proto/proxy.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020041#include <haproxy/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020042#include <proto/stream.h>
Willy Tarreau872f2ea2020-06-04 18:46:44 +020043#include <haproxy/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010044
Willy Tarreau12785782012-04-27 21:37:17 +020045/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020046static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020047
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010048struct stktable *stktables_list;
49struct eb_root stktable_by_name = EB_ROOT;
50
Olivier Houchard52dabbc2018-11-14 17:54:36 +010051#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010052
53/* This function inserts stktable <t> into the tree of known stick-table.
54 * The stick-table ID is used as the storing key so it must already have
55 * been initialized.
56 */
57void stktable_store_name(struct stktable *t)
58{
59 t->name.key = t->id;
60 ebis_insert(&stktable_by_name, &t->name);
61}
62
63struct stktable *stktable_find_by_name(const char *name)
64{
65 struct ebpt_node *node;
66 struct stktable *t;
67
68 node = ebis_lookup(&stktable_by_name, name);
69 if (node) {
70 t = container_of(node, struct stktable, name);
71 if (!strcmp(t->id, name))
72 return t;
73 }
74
75 return NULL;
76}
77
Emeric Brun3bd697e2010-01-04 15:23:48 +010078/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020079 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
80 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010081 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020082void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010083{
84 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010085 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010086}
87
88/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020089 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
90 * in table <t>.
91 * This function locks the table
92 */
93void stksess_free(struct stktable *t, struct stksess *ts)
94{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010095 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020096 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010097 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020098}
99
100/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200101 * Kill an stksess (only if its ref_cnt is zero).
102 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200103int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200104{
105 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200106 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200107
108 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200109 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200110 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200111 __stksess_free(t, ts);
112 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113}
114
115/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200116 * Decrease the refcount if decrefcnt is not 0.
117 * and try to kill the stksess
118 * This function locks the table
119 */
120int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
121{
122 int ret;
123
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100124 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200125 if (decrefcnt)
126 ts->ref_cnt--;
127 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100128 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200129
130 return ret;
131}
132
133/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200134 * Initialize or update the key in the sticky session <ts> present in table <t>
135 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100136 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200137void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100138{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200139 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200140 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100141 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200142 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
143 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100144 }
145}
146
147
148/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200149 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
150 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100151 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200152static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153{
Willy Tarreau393379c2010-06-06 12:11:37 +0200154 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200155 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200156 ts->key.node.leaf_p = NULL;
157 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200158 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200159 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100160 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100161 return ts;
162}
163
164/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200165 * Trash oldest <to_batch> sticky sessions from table <t>
166 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100167 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200168int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100169{
170 struct stksess *ts;
171 struct eb32_node *eb;
172 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200173 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100174
175 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
176
177 while (batched < to_batch) {
178
179 if (unlikely(!eb)) {
180 /* we might have reached the end of the tree, typically because
181 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200182 * half. Let's loop back to the beginning of the tree now if we
183 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200185 if (looped)
186 break;
187 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100188 eb = eb32_first(&t->exps);
189 if (likely(!eb))
190 break;
191 }
192
193 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200194 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100195 eb = eb32_next(eb);
196
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200197 /* don't delete an entry which is currently referenced */
198 if (ts->ref_cnt)
199 continue;
200
Willy Tarreau86257dc2010-06-06 12:57:10 +0200201 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100202
Willy Tarreau86257dc2010-06-06 12:57:10 +0200203 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100204 if (!tick_isset(ts->expire))
205 continue;
206
Willy Tarreau86257dc2010-06-06 12:57:10 +0200207 ts->exp.key = ts->expire;
208 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100209
Willy Tarreau86257dc2010-06-06 12:57:10 +0200210 if (!eb || eb->key > ts->exp.key)
211 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100212
213 continue;
214 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100215
Willy Tarreauaea940e2010-06-06 11:56:36 +0200216 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200217 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200218 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200219 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100220 batched++;
221 }
222
223 return batched;
224}
225
226/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200227 * Trash oldest <to_batch> sticky sessions from table <t>
228 * Returns number of trashed sticky sessions.
229 * This function locks the table
230 */
231int stktable_trash_oldest(struct stktable *t, int to_batch)
232{
233 int ret;
234
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100235 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200236 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100237 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200238
239 return ret;
240}
241/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200242 * Allocate and initialise a new sticky session.
243 * The new sticky session is returned or NULL in case of lack of memory.
244 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200245 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
246 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100247 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200248struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100249{
250 struct stksess *ts;
251
252 if (unlikely(t->current == t->size)) {
253 if ( t->nopurge )
254 return NULL;
255
Emeric Brun819fc6f2017-06-13 19:37:32 +0200256 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100257 return NULL;
258 }
259
Willy Tarreaubafbe012017-11-24 17:34:44 +0100260 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100261 if (ts) {
262 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100263 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200264 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200265 if (key)
266 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100267 }
268
269 return ts;
270}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200271/*
272 * Allocate and initialise a new sticky session.
273 * The new sticky session is returned or NULL in case of lack of memory.
274 * Sticky sessions should only be allocated this way, and must be freed using
275 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
276 * is not NULL, it is assigned to the new session.
277 * This function locks the table
278 */
279struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
280{
281 struct stksess *ts;
282
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100283 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200284 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100285 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200286
287 return ts;
288}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100289
290/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200291 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200292 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100293 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200294struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100295{
296 struct ebmb_node *eb;
297
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200298 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200299 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 +0100300 else
301 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
302
303 if (unlikely(!eb)) {
304 /* no session found */
305 return NULL;
306 }
307
Willy Tarreau86257dc2010-06-06 12:57:10 +0200308 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100309}
310
Emeric Brun819fc6f2017-06-13 19:37:32 +0200311/*
312 * Looks in table <t> for a sticky session matching key <key>.
313 * Returns pointer on requested sticky session or NULL if none was found.
314 * The refcount of the found entry is increased and this function
315 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200316 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200317struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200318{
319 struct stksess *ts;
320
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100321 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200322 ts = __stktable_lookup_key(t, key);
323 if (ts)
324 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100325 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200326
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200327 return ts;
328}
329
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200330/*
331 * Looks in table <t> for a sticky session with same key as <ts>.
332 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100333 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200334struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100336 struct ebmb_node *eb;
337
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200338 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200339 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100340 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200341 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100342
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200343 if (unlikely(!eb))
344 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100345
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200346 return ebmb_entry(eb, struct stksess, key);
347}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100348
Emeric Brun819fc6f2017-06-13 19:37:32 +0200349/*
350 * Looks in table <t> for a sticky session with same key as <ts>.
351 * Returns pointer on requested sticky session or NULL if none was found.
352 * The refcount of the found entry is increased and this function
353 * is protected using the table lock
354 */
355struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
356{
357 struct stksess *lts;
358
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100359 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200360 lts = __stktable_lookup(t, ts);
361 if (lts)
362 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100363 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200364
365 return lts;
366}
367
Willy Tarreaucb183642010-06-06 17:58:34 +0200368/* Update the expiration timer for <ts> but do not touch its expiration node.
369 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200370 * The node will be also inserted into the update tree if needed, at a position
371 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200372 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200373void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200374{
Emeric Brun85e77c72010-09-23 18:16:52 +0200375 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200376 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200377 if (t->expire) {
378 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
379 task_queue(t->exp_task);
380 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200381
Emeric Brun819fc6f2017-06-13 19:37:32 +0200382 /* If sync is enabled */
383 if (t->sync_task) {
384 if (local) {
385 /* If this entry is not in the tree
386 or not scheduled for at least one peer */
387 if (!ts->upd.node.leaf_p
388 || (int)(t->commitupdate - ts->upd.key) >= 0
389 || (int)(ts->upd.key - t->localupdate) >= 0) {
390 ts->upd.key = ++t->update;
391 t->localupdate = t->update;
392 eb32_delete(&ts->upd);
393 eb = eb32_insert(&t->updates, &ts->upd);
394 if (eb != &ts->upd) {
395 eb32_delete(eb);
396 eb32_insert(&t->updates, &ts->upd);
397 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200398 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200399 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200400 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200401 else {
402 /* If this entry is not in the tree */
403 if (!ts->upd.node.leaf_p) {
404 ts->upd.key= (++t->update)+(2147483648U);
405 eb = eb32_insert(&t->updates, &ts->upd);
406 if (eb != &ts->upd) {
407 eb32_delete(eb);
408 eb32_insert(&t->updates, &ts->upd);
409 }
410 }
411 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200412 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200413}
414
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200415/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200416 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200417 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200418 * The node will be also inserted into the update tree if needed, at a position
419 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200420 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200421void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
422{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100423 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200424 __stktable_touch_with_exp(t, ts, 0, ts->expire);
425 if (decrefcnt)
426 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100427 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200428}
429
430/* Update the expiration timer for <ts> but do not touch its expiration node.
431 * The table's expiration timer is updated using the date of expiration coming from
432 * <t> stick-table configuration.
433 * The node will be also inserted into the update tree if needed, at a position
434 * considering the update was made locally
435 */
436void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200437{
438 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
439
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100440 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200441 __stktable_touch_with_exp(t, ts, 1, expire);
442 if (decrefcnt)
443 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100444 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200445}
Willy Tarreau43e90352018-06-27 06:25:57 +0200446/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
447static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200448{
Willy Tarreau43e90352018-06-27 06:25:57 +0200449 if (!ts)
450 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100451 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200452 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100453 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200454}
455
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200456/* Insert new sticky session <ts> in the table. It is assumed that it does not
457 * yet exist (the caller must check this). The table's timeout is updated if it
458 * is set. <ts> is returned.
459 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200461{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100462
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200463 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200464 ts->exp.key = ts->expire;
465 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200466 if (t->expire) {
467 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
468 task_queue(t->exp_task);
469 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200470}
471
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200472/* Returns a valid or initialized stksess for the specified stktable_key in the
473 * specified table, or NULL if the key was NULL, or if no entry was found nor
474 * could be created. The entry's expiration is updated.
475 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200476struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200477{
478 struct stksess *ts;
479
480 if (!key)
481 return NULL;
482
Emeric Brun819fc6f2017-06-13 19:37:32 +0200483 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200484 if (ts == NULL) {
485 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200486 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200487 if (!ts)
488 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200489 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200490 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200491 return ts;
492}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200493/* Returns a valid or initialized stksess for the specified stktable_key in the
494 * specified table, or NULL if the key was NULL, or if no entry was found nor
495 * could be created. The entry's expiration is updated.
496 * This function locks the table, and the refcount of the entry is increased.
497 */
498struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
499{
500 struct stksess *ts;
501
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100502 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200503 ts = __stktable_get_entry(table, key);
504 if (ts)
505 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100506 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200507
508 return ts;
509}
510
511/* Lookup for an entry with the same key and store the submitted
512 * stksess if not found.
513 */
514struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
515{
516 struct stksess *ts;
517
518 ts = __stktable_lookup(table, nts);
519 if (ts == NULL) {
520 ts = nts;
521 __stktable_store(table, ts);
522 }
523 return ts;
524}
525
526/* Lookup for an entry with the same key and store the submitted
527 * stksess if not found.
528 * This function locks the table, and the refcount of the entry is increased.
529 */
530struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
531{
532 struct stksess *ts;
533
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100534 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200535 ts = __stktable_set_entry(table, nts);
536 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100537 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200538
Emeric Brun819fc6f2017-06-13 19:37:32 +0200539 return ts;
540}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100541/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200542 * Trash expired sticky sessions from table <t>. The next expiration date is
543 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100544 */
545static int stktable_trash_expired(struct stktable *t)
546{
547 struct stksess *ts;
548 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200549 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100550
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100551 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100552 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
553
554 while (1) {
555 if (unlikely(!eb)) {
556 /* we might have reached the end of the tree, typically because
557 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200558 * half. Let's loop back to the beginning of the tree now if we
559 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100560 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200561 if (looped)
562 break;
563 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100564 eb = eb32_first(&t->exps);
565 if (likely(!eb))
566 break;
567 }
568
569 if (likely(tick_is_lt(now_ms, eb->key))) {
570 /* timer not expired yet, revisit it later */
571 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100572 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100573 }
574
575 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200576 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100577 eb = eb32_next(eb);
578
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200579 /* don't delete an entry which is currently referenced */
580 if (ts->ref_cnt)
581 continue;
582
Willy Tarreau86257dc2010-06-06 12:57:10 +0200583 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100584
585 if (!tick_is_expired(ts->expire, now_ms)) {
586 if (!tick_isset(ts->expire))
587 continue;
588
Willy Tarreau86257dc2010-06-06 12:57:10 +0200589 ts->exp.key = ts->expire;
590 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100591
Willy Tarreau86257dc2010-06-06 12:57:10 +0200592 if (!eb || eb->key > ts->exp.key)
593 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100594 continue;
595 }
596
597 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200598 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200599 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200600 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100601 }
602
603 /* We have found no task to expire in any tree */
604 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100605out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100606 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100607 return t->exp_next;
608}
609
610/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200611 * Task processing function to trash expired sticky sessions. A pointer to the
612 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100613 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200614static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100615{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200616 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100617
618 task->expire = stktable_trash_expired(t);
619 return task;
620}
621
Willy Tarreauaea940e2010-06-06 11:56:36 +0200622/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100623int stktable_init(struct stktable *t)
624{
625 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200626 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100627 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100628 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100629 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100631 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 +0100632
633 t->exp_next = TICK_ETERNITY;
634 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200635 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200636 if (!t->exp_task)
637 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639 t->exp_task->context = (void *)t;
640 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200641 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200642 peers_register_table(t->peers.p, t);
643 }
644
Emeric Brun3bd697e2010-01-04 15:23:48 +0100645 return t->pool != NULL;
646 }
647 return 1;
648}
649
650/*
651 * Configuration keywords of known table types
652 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200653struct stktable_type stktable_types[SMP_TYPES] = {
654 [SMP_T_SINT] = { "integer", 0, 4 },
655 [SMP_T_IPV4] = { "ip", 0, 4 },
656 [SMP_T_IPV6] = { "ipv6", 0, 16 },
657 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
658 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
659};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100660
661/*
662 * Parse table type configuration.
663 * Returns 0 on successful parsing, else 1.
664 * <myidx> is set at next configuration <args> index.
665 */
666int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
667{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200668 for (*type = 0; *type < SMP_TYPES; (*type)++) {
669 if (!stktable_types[*type].kw)
670 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100671 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
672 continue;
673
674 *key_size = stktable_types[*type].default_size;
675 (*myidx)++;
676
Willy Tarreauaea940e2010-06-06 11:56:36 +0200677 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100678 if (strcmp("len", args[*myidx]) == 0) {
679 (*myidx)++;
680 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200681 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100682 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200683 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200684 /* null terminated string needs +1 for '\0'. */
685 (*key_size)++;
686 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 (*myidx)++;
688 }
689 }
690 return 0;
691 }
692 return 1;
693}
694
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100695/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100696 * Parse a line with <linenum> as number in <file> configuration file to configure
697 * the stick-table with <t> as address and <id> as ID.
698 * <peers> provides the "peers" section pointer only if this function is called
699 * from a "peers" section.
700 * <nid> is the stick-table name which is sent over the network. It must be equal
701 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
702 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500703 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100704 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
705 */
706int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100707 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100708{
709 int err_code = 0;
710 int idx = 1;
711 unsigned int val;
712
713 if (!id || !*id) {
714 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
715 err_code |= ERR_ALERT | ERR_ABORT;
716 goto out;
717 }
718
719 /* Store the "peers" section if this function is called from a "peers" section. */
720 if (peers) {
721 t->peers.p = peers;
722 idx++;
723 }
724
725 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100726 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100727 t->type = (unsigned int)-1;
728 t->conf.file = file;
729 t->conf.line = linenum;
730
731 while (*args[idx]) {
732 const char *err;
733
734 if (strcmp(args[idx], "size") == 0) {
735 idx++;
736 if (!*(args[idx])) {
737 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
738 file, linenum, args[0], args[idx-1]);
739 err_code |= ERR_ALERT | ERR_FATAL;
740 goto out;
741 }
742 if ((err = parse_size_err(args[idx], &t->size))) {
743 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
744 file, linenum, args[0], *err, args[idx-1]);
745 err_code |= ERR_ALERT | ERR_FATAL;
746 goto out;
747 }
748 idx++;
749 }
750 /* This argument does not exit in "peers" section. */
751 else if (!peers && strcmp(args[idx], "peers") == 0) {
752 idx++;
753 if (!*(args[idx])) {
754 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
755 file, linenum, args[0], args[idx-1]);
756 err_code |= ERR_ALERT | ERR_FATAL;
757 goto out;
758 }
759 t->peers.name = strdup(args[idx++]);
760 }
761 else if (strcmp(args[idx], "expire") == 0) {
762 idx++;
763 if (!*(args[idx])) {
764 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
765 file, linenum, args[0], args[idx-1]);
766 err_code |= ERR_ALERT | ERR_FATAL;
767 goto out;
768 }
769 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200770 if (err == PARSE_TIME_OVER) {
771 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
772 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100773 err_code |= ERR_ALERT | ERR_FATAL;
774 goto out;
775 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200776 else if (err == PARSE_TIME_UNDER) {
777 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
778 file, linenum, args[0], args[idx], args[idx-1]);
779 err_code |= ERR_ALERT | ERR_FATAL;
780 goto out;
781 }
782 else if (err) {
783 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
784 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100785 err_code |= ERR_ALERT | ERR_FATAL;
786 goto out;
787 }
788 t->expire = val;
789 idx++;
790 }
791 else if (strcmp(args[idx], "nopurge") == 0) {
792 t->nopurge = 1;
793 idx++;
794 }
795 else if (strcmp(args[idx], "type") == 0) {
796 idx++;
797 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
798 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
799 file, linenum, args[0], args[idx]);
800 err_code |= ERR_ALERT | ERR_FATAL;
801 goto out;
802 }
803 /* idx already points to next arg */
804 }
805 else if (strcmp(args[idx], "store") == 0) {
806 int type, err;
807 char *cw, *nw, *sa;
808
809 idx++;
810 nw = args[idx];
811 while (*nw) {
812 /* the "store" keyword supports a comma-separated list */
813 cw = nw;
814 sa = NULL; /* store arg */
815 while (*nw && *nw != ',') {
816 if (*nw == '(') {
817 *nw = 0;
818 sa = ++nw;
819 while (*nw != ')') {
820 if (!*nw) {
821 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
822 file, linenum, args[0], cw);
823 err_code |= ERR_ALERT | ERR_FATAL;
824 goto out;
825 }
826 nw++;
827 }
828 *nw = '\0';
829 }
830 nw++;
831 }
832 if (*nw)
833 *nw++ = '\0';
834 type = stktable_get_data_type(cw);
835 if (type < 0) {
836 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
837 file, linenum, args[0], cw);
838 err_code |= ERR_ALERT | ERR_FATAL;
839 goto out;
840 }
841
842 err = stktable_alloc_data_type(t, type, sa);
843 switch (err) {
844 case PE_NONE: break;
845 case PE_EXIST:
846 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
847 file, linenum, args[0], cw);
848 err_code |= ERR_WARN;
849 break;
850
851 case PE_ARG_MISSING:
852 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
853 file, linenum, args[0], cw);
854 err_code |= ERR_ALERT | ERR_FATAL;
855 goto out;
856
857 case PE_ARG_NOT_USED:
858 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
859 file, linenum, args[0], cw);
860 err_code |= ERR_ALERT | ERR_FATAL;
861 goto out;
862
863 default:
864 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
865 file, linenum, args[0], cw);
866 err_code |= ERR_ALERT | ERR_FATAL;
867 goto out;
868 }
869 }
870 idx++;
871 }
872 else {
873 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
874 file, linenum, args[0], args[idx]);
875 err_code |= ERR_ALERT | ERR_FATAL;
876 goto out;
877 }
878 }
879
880 if (!t->size) {
881 ha_alert("parsing [%s:%d] : %s: missing size.\n",
882 file, linenum, args[0]);
883 err_code |= ERR_ALERT | ERR_FATAL;
884 goto out;
885 }
886
887 if (t->type == (unsigned int)-1) {
888 ha_alert("parsing [%s:%d] : %s: missing type.\n",
889 file, linenum, args[0]);
890 err_code |= ERR_ALERT | ERR_FATAL;
891 goto out;
892 }
893
894 out:
895 return err_code;
896}
897
Willy Tarreau8fed9032014-07-03 17:02:46 +0200898/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200899 * Note that the sample *is* modified and that the returned key may point
900 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200901 * Returns NULL if the sample could not be converted (eg: no matching type),
902 * otherwise a pointer to the static stktable_key filled with what is needed
903 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200904 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200905struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200906{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200907 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200908 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200909 return NULL;
910
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200911 /* Fill static_table_key. */
912 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200913
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200914 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200915 static_table_key.key = &smp->data.u.ipv4;
916 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200917 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200918
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200919 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200920 static_table_key.key = &smp->data.u.ipv6;
921 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200922 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200923
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200924 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200925 /* The stick table require a 32bit unsigned int, "sint" is a
926 * signed 64 it, so we can convert it inplace.
927 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200928 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200929 static_table_key.key = &smp->data.u.sint;
930 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200931 break;
932
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200933 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200934 if (!smp_make_safe(smp))
935 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200936 static_table_key.key = smp->data.u.str.area;
937 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200938 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200939
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200940 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200941 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200942 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200943 if (!smp_make_rw(smp))
944 return NULL;
945
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200946 if (smp->data.u.str.size < t->key_size)
947 if (!smp_dup(smp))
948 return NULL;
949 if (smp->data.u.str.size < t->key_size)
950 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200951 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
952 t->key_size - smp->data.u.str.data);
953 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200954 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200955 static_table_key.key = smp->data.u.str.area;
956 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200957 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200958
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200959 default: /* impossible case. */
960 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200961 }
962
Christopher Fauletca20d022017-08-29 15:30:31 +0200963 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200964}
965
966/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200967 * Process a fetch + format conversion as defined by the sample expression <expr>
968 * on request or response considering the <opt> parameter. Returns either NULL if
969 * no key could be extracted, or a pointer to the converted result stored in
970 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
971 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200972 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
973 * without SMP_OPT_FINAL). The output will be usable like this :
974 *
975 * return MAY_CHANGE FINAL Meaning for the sample
976 * NULL 0 * Not present and will never be (eg: header)
977 * NULL 1 0 Not present or unstable, could change (eg: req_len)
978 * NULL 1 1 Not present, will not change anymore
979 * smp 0 * Present and will not change (eg: header)
980 * smp 1 0 not possible
981 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200982 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200983struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200984 unsigned int opt, struct sample_expr *expr, struct sample *smp)
985{
986 if (smp)
987 memset(smp, 0, sizeof(*smp));
988
Willy Tarreau192252e2015-04-04 01:47:55 +0200989 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200990 if (!smp)
991 return NULL;
992
993 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
994 return NULL; /* we can only use stable samples */
995
996 return smp_to_stkey(smp, t);
997}
998
999/*
Willy Tarreau12785782012-04-27 21:37:17 +02001000 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001001 * type <table_type>, otherwise zero. Used in configuration check.
1002 */
Willy Tarreau12785782012-04-27 21:37:17 +02001003int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001004{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001005 int out_type;
1006
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001007 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001008 return 0;
1009
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001010 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001011
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001012 /* Convert sample. */
1013 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001014 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001015
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001016 return 1;
1017}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001018
Willy Tarreauedee1d62014-07-15 16:44:27 +02001019/* Extra data types processing : after the last one, some room may remain
1020 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1021 * at run time.
1022 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001023struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001024 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001025 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001026 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001027 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001028 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1029 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1030 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1031 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1032 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1033 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1034 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1035 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1036 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1037 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1038 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1039 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1040 [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 +01001041 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1042 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Frédéric Lécaille5ad57ea2019-05-17 10:08:29 +02001043 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001044};
1045
Willy Tarreauedee1d62014-07-15 16:44:27 +02001046/* Registers stick-table extra data type with index <idx>, name <name>, type
1047 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1048 * index is automatically allocated. The allocated index is returned, or -1 if
1049 * no free index was found or <name> was already registered. The <name> is used
1050 * directly as a pointer, so if it's not stable, the caller must allocate it.
1051 */
1052int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1053{
1054 if (idx < 0) {
1055 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1056 if (!stktable_data_types[idx].name)
1057 break;
1058
1059 if (strcmp(stktable_data_types[idx].name, name) == 0)
1060 return -1;
1061 }
1062 }
1063
1064 if (idx >= STKTABLE_DATA_TYPES)
1065 return -1;
1066
1067 if (stktable_data_types[idx].name != NULL)
1068 return -1;
1069
1070 stktable_data_types[idx].name = name;
1071 stktable_data_types[idx].std_type = std_type;
1072 stktable_data_types[idx].arg_type = arg_type;
1073 return idx;
1074}
1075
Willy Tarreau08d5f982010-06-06 13:34:54 +02001076/*
1077 * Returns the data type number for the stktable_data_type whose name is <name>,
1078 * or <0 if not found.
1079 */
1080int stktable_get_data_type(char *name)
1081{
1082 int type;
1083
1084 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001085 if (!stktable_data_types[type].name)
1086 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001087 if (strcmp(name, stktable_data_types[type].name) == 0)
1088 return type;
1089 }
1090 return -1;
1091}
1092
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001093/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1094 * it up into this table. Returns true if found, false otherwise. The input
1095 * type is STR so that input samples are converted to string (since all types
1096 * can be converted to strings), then the function casts the string again into
1097 * the table's type. This is a double conversion, but in the future we might
1098 * support automatic input types to perform the cast on the fly.
1099 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001100static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001101{
1102 struct stktable *t;
1103 struct stktable_key *key;
1104 struct stksess *ts;
1105
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001106 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001107
1108 key = smp_to_stkey(smp, t);
1109 if (!key)
1110 return 0;
1111
1112 ts = stktable_lookup_key(t, key);
1113
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001114 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001115 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001116 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001117 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001118 return 1;
1119}
1120
1121/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1122 * it up into this table. Returns the data rate received from clients in bytes/s
1123 * if the key is present in the table, otherwise zero, so that comparisons can
1124 * be easily performed. If the inspected parameter is not stored in the table,
1125 * <not found> is returned.
1126 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001127static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001128{
1129 struct stktable *t;
1130 struct stktable_key *key;
1131 struct stksess *ts;
1132 void *ptr;
1133
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001134 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001135
1136 key = smp_to_stkey(smp, t);
1137 if (!key)
1138 return 0;
1139
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001140 ts = stktable_lookup_key(t, key);
1141
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001142 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001143 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001144 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001145
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001146 if (!ts) /* key not present */
1147 return 1;
1148
1149 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001150 if (ptr)
1151 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1152 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001153
Daniel Corbett3e60b112018-05-27 09:47:12 -04001154 stktable_release(t, ts);
1155 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001156}
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 cumulated number of connections for the key
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_conn_cnt(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_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001187 if (ptr)
1188 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001189
Daniel Corbett3e60b112018-05-27 09:47:12 -04001190 stktable_release(t, ts);
1191 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001192}
1193
1194/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1195 * it up into this table. Returns the number of concurrent connections for the
1196 * key if the key is present in the table, otherwise zero, so that comparisons
1197 * can be easily performed. If the inspected parameter is not stored in the
1198 * table, <not found> is returned.
1199 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001200static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001201{
1202 struct stktable *t;
1203 struct stktable_key *key;
1204 struct stksess *ts;
1205 void *ptr;
1206
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001207 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001208
1209 key = smp_to_stkey(smp, t);
1210 if (!key)
1211 return 0;
1212
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001213 ts = stktable_lookup_key(t, key);
1214
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001215 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001216 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001217 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001218
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001219 if (!ts) /* key not present */
1220 return 1;
1221
1222 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001223 if (ptr)
1224 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001225
Daniel Corbett3e60b112018-05-27 09:47:12 -04001226 stktable_release(t, ts);
1227 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001228}
1229
1230/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1231 * it up into this table. Returns the rate of incoming connections from the key
1232 * if the key is present in the table, otherwise zero, so that comparisons can
1233 * be easily performed. If the inspected parameter is not stored in the table,
1234 * <not found> is returned.
1235 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001236static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001237{
1238 struct stktable *t;
1239 struct stktable_key *key;
1240 struct stksess *ts;
1241 void *ptr;
1242
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001243 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001244
1245 key = smp_to_stkey(smp, t);
1246 if (!key)
1247 return 0;
1248
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001249 ts = stktable_lookup_key(t, key);
1250
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001252 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001253 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001255 if (!ts) /* key not present */
1256 return 1;
1257
1258 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001259 if (ptr)
1260 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1261 t->data_arg[STKTABLE_DT_CONN_RATE].u);
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 data rate sent to clients in bytes/s
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_bytes_out_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_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001296 if (ptr)
1297 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1298 t->data_arg[STKTABLE_DT_BYTES_OUT_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
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001305 * it up into this table. Returns the value of the GPT0 tag for the key
1306 * if the key is present in the table, otherwise false, so that comparisons can
1307 * be easily performed. If the inspected parameter is not stored in the table,
1308 * <not found> is returned.
1309 */
1310static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1311{
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;
Thierry FOURNIER236657b2015-08-19 08:25:14 +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
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001325 smp->flags = SMP_F_VOL_TEST;
1326 smp->data.type = SMP_T_SINT;
1327 smp->data.u.sint = 0;
1328
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001329 if (!ts) /* key not present */
1330 return 1;
1331
1332 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001333 if (ptr)
1334 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001335
Daniel Corbett3e60b112018-05-27 09:47:12 -04001336 stktable_release(t, ts);
1337 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001338}
1339
1340/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341 * it up into this table. Returns the value of the GPC0 counter for the key
1342 * if the key is present in the table, otherwise zero, so that comparisons can
1343 * be easily performed. If the inspected parameter is not stored in the table,
1344 * <not found> is returned.
1345 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001346static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347{
1348 struct stktable *t;
1349 struct stktable_key *key;
1350 struct stksess *ts;
1351 void *ptr;
1352
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001353 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354
1355 key = smp_to_stkey(smp, t);
1356 if (!key)
1357 return 0;
1358
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001359 ts = stktable_lookup_key(t, key);
1360
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001362 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001363 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001364
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001365 if (!ts) /* key not present */
1366 return 1;
1367
1368 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001369 if (ptr)
1370 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371
Daniel Corbett3e60b112018-05-27 09:47:12 -04001372 stktable_release(t, ts);
1373 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001374}
1375
1376/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1377 * it up into this table. Returns the event rate of the GPC0 counter for the key
1378 * if the key is present in the table, otherwise zero, so that comparisons can
1379 * be easily performed. If the inspected parameter is not stored in the table,
1380 * <not found> is returned.
1381 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001382static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001383{
1384 struct stktable *t;
1385 struct stktable_key *key;
1386 struct stksess *ts;
1387 void *ptr;
1388
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001389 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001390
1391 key = smp_to_stkey(smp, t);
1392 if (!key)
1393 return 0;
1394
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001395 ts = stktable_lookup_key(t, key);
1396
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001397 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001398 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001399 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001401 if (!ts) /* key not present */
1402 return 1;
1403
1404 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001405 if (ptr)
1406 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1407 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
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
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001414 * it up into this table. Returns the value of the GPC1 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 */
1419static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1420{
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;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001427
1428 key = smp_to_stkey(smp, t);
1429 if (!key)
1430 return 0;
1431
1432 ts = stktable_lookup_key(t, key);
1433
1434 smp->flags = SMP_F_VOL_TEST;
1435 smp->data.type = SMP_T_SINT;
1436 smp->data.u.sint = 0;
1437
1438 if (!ts) /* key not present */
1439 return 1;
1440
1441 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001442 if (ptr)
1443 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001444
Daniel Corbett3e60b112018-05-27 09:47:12 -04001445 stktable_release(t, ts);
1446 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001447}
1448
1449/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1450 * it up into this table. Returns the event rate of the GPC1 counter for the key
1451 * if the key is present in the table, otherwise zero, so that comparisons can
1452 * be easily performed. If the inspected parameter is not stored in the table,
1453 * <not found> is returned.
1454 */
1455static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1456{
1457 struct stktable *t;
1458 struct stktable_key *key;
1459 struct stksess *ts;
1460 void *ptr;
1461
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001462 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001463
1464 key = smp_to_stkey(smp, t);
1465 if (!key)
1466 return 0;
1467
1468 ts = stktable_lookup_key(t, key);
1469
1470 smp->flags = SMP_F_VOL_TEST;
1471 smp->data.type = SMP_T_SINT;
1472 smp->data.u.sint = 0;
1473
1474 if (!ts) /* key not present */
1475 return 1;
1476
1477 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001478 if (ptr)
1479 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1480 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
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
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001487 * it up into this table. Returns the cumulated number of HTTP request errors
1488 * for the key if the key is present in the table, otherwise zero, so that
1489 * comparisons can be easily performed. If the inspected parameter is not stored
1490 * in the table, <not found> is returned.
1491 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001492static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001493{
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;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001500
1501 key = smp_to_stkey(smp, t);
1502 if (!key)
1503 return 0;
1504
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001505 ts = stktable_lookup_key(t, key);
1506
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001507 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001508 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001509 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001510
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001511 if (!ts) /* key not present */
1512 return 1;
1513
1514 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001515 if (ptr)
1516 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001517
Daniel Corbett3e60b112018-05-27 09:47:12 -04001518 stktable_release(t, ts);
1519 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001520}
1521
1522/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1523 * it up into this table. Returns the HTTP request error rate the key
1524 * if the key is present in the table, otherwise zero, so that comparisons can
1525 * be easily performed. If the inspected parameter is not stored in the table,
1526 * <not found> is returned.
1527 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001528static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001529{
1530 struct stktable *t;
1531 struct stktable_key *key;
1532 struct stksess *ts;
1533 void *ptr;
1534
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001535 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001536
1537 key = smp_to_stkey(smp, t);
1538 if (!key)
1539 return 0;
1540
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001541 ts = stktable_lookup_key(t, key);
1542
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001543 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001544 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001545 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001546
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001547 if (!ts) /* key not present */
1548 return 1;
1549
1550 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001551 if (ptr)
1552 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1553 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
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 cumulated number of HTTP request for the
1561 * key if the key is present in the table, otherwise zero, so that comparisons
1562 * can be easily performed. If the inspected parameter is not stored in the
1563 * table, <not found> is returned.
1564 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001565static int sample_conv_table_http_req_cnt(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_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001588 if (ptr)
1589 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001590
Daniel Corbett3e60b112018-05-27 09:47:12 -04001591 stktable_release(t, ts);
1592 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593}
1594
1595/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1596 * it up into this table. Returns the HTTP request rate the key if the key is
1597 * present in the table, otherwise zero, so that comparisons can be easily
1598 * performed. If the inspected parameter is not stored in the table, <not found>
1599 * is returned.
1600 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001601static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001602{
1603 struct stktable *t;
1604 struct stktable_key *key;
1605 struct stksess *ts;
1606 void *ptr;
1607
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001608 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001609
1610 key = smp_to_stkey(smp, t);
1611 if (!key)
1612 return 0;
1613
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001614 ts = stktable_lookup_key(t, key);
1615
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001616 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001617 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001618 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001619
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001620 if (!ts) /* key not present */
1621 return 1;
1622
1623 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001624 if (ptr)
1625 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1626 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
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 volume of datareceived from clients in kbytes
1634 * if the key is present in the table, otherwise zero, so that comparisons can
1635 * be easily performed. If the inspected parameter is not stored in the table,
1636 * <not found> is returned.
1637 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001638static int sample_conv_table_kbytes_in(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_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001661 if (ptr)
1662 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001663
Daniel Corbett3e60b112018-05-27 09:47:12 -04001664 stktable_release(t, ts);
1665 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001666}
1667
1668/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1669 * it up into this table. Returns the volume of data sent to clients in kbytes
1670 * if the key is present in the table, otherwise zero, so that comparisons can
1671 * be easily performed. If the inspected parameter is not stored in the table,
1672 * <not found> is returned.
1673 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001674static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001675{
1676 struct stktable *t;
1677 struct stktable_key *key;
1678 struct stksess *ts;
1679 void *ptr;
1680
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001681 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001682
1683 key = smp_to_stkey(smp, t);
1684 if (!key)
1685 return 0;
1686
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001687 ts = stktable_lookup_key(t, key);
1688
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001689 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001690 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001691 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001692
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001693 if (!ts) /* key not present */
1694 return 1;
1695
1696 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001697 if (ptr)
1698 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001699
Daniel Corbett3e60b112018-05-27 09:47:12 -04001700 stktable_release(t, ts);
1701 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001702}
1703
1704/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1705 * it up into this table. Returns the server ID associated with the key if the
1706 * key is present in the table, otherwise zero, so that comparisons can be
1707 * easily performed. If the inspected parameter is not stored in the table,
1708 * <not found> is returned.
1709 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001710static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001711{
1712 struct stktable *t;
1713 struct stktable_key *key;
1714 struct stksess *ts;
1715 void *ptr;
1716
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001717 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001718
1719 key = smp_to_stkey(smp, t);
1720 if (!key)
1721 return 0;
1722
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001723 ts = stktable_lookup_key(t, key);
1724
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001725 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001726 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001727 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001728
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001729 if (!ts) /* key not present */
1730 return 1;
1731
1732 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001733 if (ptr)
1734 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001735
Daniel Corbett3e60b112018-05-27 09:47:12 -04001736 stktable_release(t, ts);
1737 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001738}
1739
1740/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1741 * it up into this table. Returns the cumulated number of sessions for the
1742 * key if the key is present in the table, otherwise zero, so that comparisons
1743 * can be easily performed. If the inspected parameter is not stored in the
1744 * table, <not found> is returned.
1745 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001746static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001747{
1748 struct stktable *t;
1749 struct stktable_key *key;
1750 struct stksess *ts;
1751 void *ptr;
1752
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001753 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001754
1755 key = smp_to_stkey(smp, t);
1756 if (!key)
1757 return 0;
1758
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001759 ts = stktable_lookup_key(t, key);
1760
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001761 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001762 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001763 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001764
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001765 if (!ts) /* key not present */
1766 return 1;
1767
1768 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001769 if (ptr)
1770 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771
Daniel Corbett3e60b112018-05-27 09:47:12 -04001772 stktable_release(t, ts);
1773 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001774}
1775
1776/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1777 * it up into this table. Returns the session rate the key if the key is
1778 * present in the table, otherwise zero, so that comparisons can be easily
1779 * performed. If the inspected parameter is not stored in the table, <not found>
1780 * is returned.
1781 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001782static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001783{
1784 struct stktable *t;
1785 struct stktable_key *key;
1786 struct stksess *ts;
1787 void *ptr;
1788
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001789 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001790
1791 key = smp_to_stkey(smp, t);
1792 if (!key)
1793 return 0;
1794
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001795 ts = stktable_lookup_key(t, key);
1796
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001797 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001798 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001799 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801 if (!ts) /* key not present */
1802 return 1;
1803
1804 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001805 if (ptr)
1806 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1807 t->data_arg[STKTABLE_DT_SESS_RATE].u);
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 amount of concurrent connections tracking
1815 * the same key if the key is present in the table, otherwise zero, so that
1816 * comparisons can be easily performed. If the inspected parameter is not
1817 * stored in the table, <not found> is returned.
1818 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001819static int sample_conv_table_trackers(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
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001825 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001826
1827 key = smp_to_stkey(smp, t);
1828 if (!key)
1829 return 0;
1830
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001831 ts = stktable_lookup_key(t, key);
1832
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001833 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001834 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001835 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001836
Tim Duesterhus65189c12018-06-26 15:57:29 +02001837 if (!ts)
1838 return 1;
1839
1840 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001841
Daniel Corbett3e60b112018-05-27 09:47:12 -04001842 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001843 return 1;
1844}
1845
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001846/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001847static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001848 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001849{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001850 struct stksess *ts;
1851 struct stkctr *stkctr;
1852
1853 /* Extract the stksess, return OK if no stksess available. */
1854 if (s)
1855 stkctr = &s->stkctr[rule->arg.gpc.sc];
1856 else
1857 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001858
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001859 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001860 if (ts) {
1861 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001862
Willy Tarreau79c1e912016-01-25 14:54:45 +01001863 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1864 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001865 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1866 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001867 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001868
1869 if (ptr1)
1870 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001871 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001872
Emeric Brun819fc6f2017-06-13 19:37:32 +02001873 if (ptr2)
1874 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001875
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001876 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001877
1878 /* If data was modified, we need to touch to re-schedule sync */
1879 stktable_touch_local(stkctr->table, ts, 0);
1880 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001881 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001882 return ACT_RET_CONT;
1883}
1884
1885/* This function is a common parser for using variables. It understands
1886 * the formats:
1887 *
1888 * sc-inc-gpc0(<stick-table ID>)
1889 *
1890 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1891 * it returns 1 and the variable <expr> is filled with the pointer to the
1892 * expression to execute.
1893 */
1894static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1895 struct act_rule *rule, char **err)
1896{
1897 const char *cmd_name = args[*arg-1];
1898 char *error;
1899
1900 cmd_name += strlen("sc-inc-gpc0");
1901 if (*cmd_name == '\0') {
1902 /* default stick table id. */
1903 rule->arg.gpc.sc = 0;
1904 } else {
1905 /* parse the stick table id. */
1906 if (*cmd_name != '(') {
1907 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1908 return ACT_RET_PRS_ERR;
1909 }
1910 cmd_name++; /* jump the '(' */
1911 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1912 if (*error != ')') {
1913 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1914 return ACT_RET_PRS_ERR;
1915 }
1916
Christopher Faulet28436e22019-12-18 10:25:46 +01001917 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001918 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001919 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001920 return ACT_RET_PRS_ERR;
1921 }
1922 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001923 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001924 rule->action_ptr = action_inc_gpc0;
1925 return ACT_RET_PRS_OK;
1926}
1927
1928/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001929static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1930 struct session *sess, struct stream *s, int flags)
1931{
1932 struct stksess *ts;
1933 struct stkctr *stkctr;
1934
1935 /* Extract the stksess, return OK if no stksess available. */
1936 if (s)
1937 stkctr = &s->stkctr[rule->arg.gpc.sc];
1938 else
1939 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1940
1941 ts = stkctr_entry(stkctr);
1942 if (ts) {
1943 void *ptr1, *ptr2;
1944
1945 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1946 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1947 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1948 if (ptr1 || ptr2) {
1949 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1950
1951 if (ptr1)
1952 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1953 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1954
1955 if (ptr2)
1956 stktable_data_cast(ptr2, gpc1)++;
1957
1958 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1959
1960 /* If data was modified, we need to touch to re-schedule sync */
1961 stktable_touch_local(stkctr->table, ts, 0);
1962 }
1963 }
1964 return ACT_RET_CONT;
1965}
1966
1967/* This function is a common parser for using variables. It understands
1968 * the formats:
1969 *
1970 * sc-inc-gpc1(<stick-table ID>)
1971 *
1972 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1973 * it returns 1 and the variable <expr> is filled with the pointer to the
1974 * expression to execute.
1975 */
1976static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1977 struct act_rule *rule, char **err)
1978{
1979 const char *cmd_name = args[*arg-1];
1980 char *error;
1981
1982 cmd_name += strlen("sc-inc-gpc1");
1983 if (*cmd_name == '\0') {
1984 /* default stick table id. */
1985 rule->arg.gpc.sc = 0;
1986 } else {
1987 /* parse the stick table id. */
1988 if (*cmd_name != '(') {
1989 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1990 return ACT_RET_PRS_ERR;
1991 }
1992 cmd_name++; /* jump the '(' */
1993 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1994 if (*error != ')') {
1995 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1996 return ACT_RET_PRS_ERR;
1997 }
1998
Christopher Faulet28436e22019-12-18 10:25:46 +01001999 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002000 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002001 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002002 return ACT_RET_PRS_ERR;
2003 }
2004 }
2005 rule->action = ACT_CUSTOM;
2006 rule->action_ptr = action_inc_gpc1;
2007 return ACT_RET_PRS_OK;
2008}
2009
2010/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002011static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002012 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002013{
2014 void *ptr;
2015 struct stksess *ts;
2016 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002017 unsigned int value = 0;
2018 struct sample *smp;
2019 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002020
2021 /* Extract the stksess, return OK if no stksess available. */
2022 if (s)
2023 stkctr = &s->stkctr[rule->arg.gpt.sc];
2024 else
2025 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002026
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002027 ts = stkctr_entry(stkctr);
2028 if (!ts)
2029 return ACT_RET_CONT;
2030
2031 /* Store the sample in the required sc, and ignore errors. */
2032 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002033 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002034 if (!rule->arg.gpt.expr)
2035 value = (unsigned int)(rule->arg.gpt.value);
2036 else {
2037 switch (rule->from) {
2038 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2039 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2040 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2041 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2042 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2043 default:
2044 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2045 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2046 ha_alert("stick table: internal error while executing setting gpt0.\n");
2047 return ACT_RET_CONT;
2048 }
2049
2050 /* Fetch and cast the expression. */
2051 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2052 if (!smp) {
2053 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2054 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2055 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2056 return ACT_RET_CONT;
2057 }
2058 value = (unsigned int)(smp->data.u.sint);
2059 }
2060
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002061 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002062
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002063 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002064
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002065 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002066
2067 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002068 }
2069
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002070 return ACT_RET_CONT;
2071}
2072
2073/* This function is a common parser for using variables. It understands
2074 * the format:
2075 *
2076 * set-gpt0(<stick-table ID>) <expression>
2077 *
2078 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2079 * it returns 1 and the variable <expr> is filled with the pointer to the
2080 * expression to execute.
2081 */
2082static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2083 struct act_rule *rule, char **err)
2084
2085
2086{
2087 const char *cmd_name = args[*arg-1];
2088 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002089 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002090
2091 cmd_name += strlen("sc-set-gpt0");
2092 if (*cmd_name == '\0') {
2093 /* default stick table id. */
2094 rule->arg.gpt.sc = 0;
2095 } else {
2096 /* parse the stick table id. */
2097 if (*cmd_name != '(') {
2098 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2099 return ACT_RET_PRS_ERR;
2100 }
2101 cmd_name++; /* jump the '(' */
2102 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2103 if (*error != ')') {
2104 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2105 return ACT_RET_PRS_ERR;
2106 }
2107
Christopher Faulet28436e22019-12-18 10:25:46 +01002108 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002109 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002110 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002111 return ACT_RET_PRS_ERR;
2112 }
2113 }
2114
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002115 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002116 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2117 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002118 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002119 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002120 if (!rule->arg.gpt.expr)
2121 return ACT_RET_PRS_ERR;
2122
2123 switch (rule->from) {
2124 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2125 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2126 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2127 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2128 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2129 default:
2130 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2131 return ACT_RET_PRS_ERR;
2132 }
2133 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2134 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2135 sample_src_names(rule->arg.gpt.expr->fetch->use));
2136 free(rule->arg.gpt.expr);
2137 return ACT_RET_PRS_ERR;
2138 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002139 }
2140 (*arg)++;
2141
Thierry FOURNIER42148732015-09-02 17:17:33 +02002142 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002143 rule->action_ptr = action_set_gpt0;
2144
2145 return ACT_RET_PRS_OK;
2146}
2147
Willy Tarreau7d562212016-11-25 16:10:05 +01002148/* set temp integer to the number of used entries in the table pointed to by expr.
2149 * Accepts exactly 1 argument of type table.
2150 */
2151static int
2152smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2153{
2154 smp->flags = SMP_F_VOL_TEST;
2155 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002156 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002157 return 1;
2158}
2159
2160/* set temp integer to the number of free entries in the table pointed to by expr.
2161 * Accepts exactly 1 argument of type table.
2162 */
2163static int
2164smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2165{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002166 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002167
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002168 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002169 smp->flags = SMP_F_VOL_TEST;
2170 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002171 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002172 return 1;
2173}
2174
2175/* Returns a pointer to a stkctr depending on the fetch keyword name.
2176 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2177 * sc[0-9]_* will return a pointer to the respective field in the
2178 * stream <l4>. sc_* requires an UINT argument specifying the stick
2179 * counter number. src_* will fill a locally allocated structure with
2180 * the table and entry corresponding to what is specified with src_*.
2181 * NULL may be returned if the designated stkctr is not tracked. For
2182 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2183 * passed. When present, the currently tracked key is then looked up
2184 * in the specified table instead of the current table. The purpose is
2185 * to be able to convery multiple values per key (eg: have gpc0 from
2186 * multiple tables). <strm> is allowed to be NULL, in which case only
2187 * the session will be consulted.
2188 */
2189struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002190smp_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 +01002191{
Willy Tarreau7d562212016-11-25 16:10:05 +01002192 struct stkctr *stkptr;
2193 struct stksess *stksess;
2194 unsigned int num = kw[2] - '0';
2195 int arg = 0;
2196
2197 if (num == '_' - '0') {
2198 /* sc_* variant, args[0] = ctr# (mandatory) */
2199 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002200 }
2201 else if (num > 9) { /* src_* variant, args[0] = table */
2202 struct stktable_key *key;
2203 struct connection *conn = objt_conn(sess->origin);
2204 struct sample smp;
2205
2206 if (!conn)
2207 return NULL;
2208
Joseph Herlant5662fa42018-11-15 13:43:28 -08002209 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002210 smp.px = NULL;
2211 smp.sess = sess;
2212 smp.strm = strm;
2213 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2214 return NULL;
2215
2216 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002217 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002218 if (!key)
2219 return NULL;
2220
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002221 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002222 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2223 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002224 }
2225
2226 /* Here, <num> contains the counter number from 0 to 9 for
2227 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2228 * args[arg] is the first optional argument. We first lookup the
2229 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002230 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002231 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002232 if (num >= MAX_SESS_STKCTR)
2233 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002234
2235 if (strm)
2236 stkptr = &strm->stkctr[num];
2237 if (!strm || !stkctr_entry(stkptr)) {
2238 stkptr = &sess->stkctr[num];
2239 if (!stkctr_entry(stkptr))
2240 return NULL;
2241 }
2242
2243 stksess = stkctr_entry(stkptr);
2244 if (!stksess)
2245 return NULL;
2246
2247 if (unlikely(args[arg].type == ARGT_TAB)) {
2248 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002249 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002250 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2251 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002252 }
2253 return stkptr;
2254}
2255
2256/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2257 * the entry if it doesn't exist yet. This is needed for a few fetch
2258 * functions which need to create an entry, such as src_inc_gpc* and
2259 * src_clr_gpc*.
2260 */
2261struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002262smp_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 +01002263{
Willy Tarreau7d562212016-11-25 16:10:05 +01002264 struct stktable_key *key;
2265 struct connection *conn = objt_conn(sess->origin);
2266 struct sample smp;
2267
2268 if (strncmp(kw, "src_", 4) != 0)
2269 return NULL;
2270
2271 if (!conn)
2272 return NULL;
2273
Joseph Herlant5662fa42018-11-15 13:43:28 -08002274 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002275 smp.px = NULL;
2276 smp.sess = sess;
2277 smp.strm = strm;
2278 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2279 return NULL;
2280
2281 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002282 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002283 if (!key)
2284 return NULL;
2285
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002286 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002287 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2288 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002289}
2290
2291/* set return a boolean indicating if the requested stream counter is
2292 * currently being tracked or not.
2293 * Supports being called as "sc[0-9]_tracked" only.
2294 */
2295static int
2296smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2297{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002298 struct stkctr tmpstkctr;
2299 struct stkctr *stkctr;
2300
Willy Tarreau7d562212016-11-25 16:10:05 +01002301 smp->flags = SMP_F_VOL_TEST;
2302 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002303 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2304 smp->data.u.sint = !!stkctr;
2305
2306 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002307 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002308 stktable_release(stkctr->table, stkctr_entry(stkctr));
2309
Willy Tarreau7d562212016-11-25 16:10:05 +01002310 return 1;
2311}
2312
2313/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2314 * frontend counters or from the src.
2315 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2316 * zero is returned if the key is new.
2317 */
2318static int
2319smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2320{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002321 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002322 struct stkctr *stkctr;
2323
Emeric Brun819fc6f2017-06-13 19:37:32 +02002324 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002325 if (!stkctr)
2326 return 0;
2327
2328 smp->flags = SMP_F_VOL_TEST;
2329 smp->data.type = SMP_T_SINT;
2330 smp->data.u.sint = 0;
2331
Emeric Brun819fc6f2017-06-13 19:37:32 +02002332 if (stkctr_entry(stkctr)) {
2333 void *ptr;
2334
2335 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2336 if (!ptr) {
2337 if (stkctr == &tmpstkctr)
2338 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002339 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002340 }
2341
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002342 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002343
Willy Tarreau7d562212016-11-25 16:10:05 +01002344 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002345
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002346 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002347
2348 if (stkctr == &tmpstkctr)
2349 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002350 }
2351 return 1;
2352}
2353
2354/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2355 * frontend counters or from the src.
2356 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2357 * zero is returned if the key is new.
2358 */
2359static int
2360smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2361{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002362 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002363 struct stkctr *stkctr;
2364
Emeric Brun819fc6f2017-06-13 19:37:32 +02002365 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002366 if (!stkctr)
2367 return 0;
2368
2369 smp->flags = SMP_F_VOL_TEST;
2370 smp->data.type = SMP_T_SINT;
2371 smp->data.u.sint = 0;
2372
2373 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002374 void *ptr;
2375
2376 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2377 if (!ptr) {
2378 if (stkctr == &tmpstkctr)
2379 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002380 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002381 }
2382
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002383 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002384
Willy Tarreau7d562212016-11-25 16:10:05 +01002385 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002386
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002387 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002388
2389 if (stkctr == &tmpstkctr)
2390 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002391 }
2392 return 1;
2393}
2394
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002395/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2396 * frontend counters or from the src.
2397 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2398 * zero is returned if the key is new.
2399 */
2400static int
2401smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2402{
2403 struct stkctr tmpstkctr;
2404 struct stkctr *stkctr;
2405
2406 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2407 if (!stkctr)
2408 return 0;
2409
2410 smp->flags = SMP_F_VOL_TEST;
2411 smp->data.type = SMP_T_SINT;
2412 smp->data.u.sint = 0;
2413
2414 if (stkctr_entry(stkctr) != NULL) {
2415 void *ptr;
2416
2417 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2418 if (!ptr) {
2419 if (stkctr == &tmpstkctr)
2420 stktable_release(stkctr->table, stkctr_entry(stkctr));
2421 return 0; /* parameter not stored */
2422 }
2423
2424 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2425
2426 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2427
2428 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2429
2430 if (stkctr == &tmpstkctr)
2431 stktable_release(stkctr->table, stkctr_entry(stkctr));
2432 }
2433 return 1;
2434}
2435
Willy Tarreau7d562212016-11-25 16:10:05 +01002436/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2437 * tracked frontend counters or from the src.
2438 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2439 * Value zero is returned if the key is new.
2440 */
2441static int
2442smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2443{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002444 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002445 struct stkctr *stkctr;
2446
Emeric Brun819fc6f2017-06-13 19:37:32 +02002447 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002448 if (!stkctr)
2449 return 0;
2450
2451 smp->flags = SMP_F_VOL_TEST;
2452 smp->data.type = SMP_T_SINT;
2453 smp->data.u.sint = 0;
2454 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002455 void *ptr;
2456
2457 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2458 if (!ptr) {
2459 if (stkctr == &tmpstkctr)
2460 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002461 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002462 }
2463
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002464 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002465
Willy Tarreau7d562212016-11-25 16:10:05 +01002466 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2467 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002468
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002469 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002470
2471 if (stkctr == &tmpstkctr)
2472 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002473 }
2474 return 1;
2475}
2476
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002477/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2478 * tracked frontend counters or from the src.
2479 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2480 * Value zero is returned if the key is new.
2481 */
2482static int
2483smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2484{
2485 struct stkctr tmpstkctr;
2486 struct stkctr *stkctr;
2487
2488 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2489 if (!stkctr)
2490 return 0;
2491
2492 smp->flags = SMP_F_VOL_TEST;
2493 smp->data.type = SMP_T_SINT;
2494 smp->data.u.sint = 0;
2495 if (stkctr_entry(stkctr) != NULL) {
2496 void *ptr;
2497
2498 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2499 if (!ptr) {
2500 if (stkctr == &tmpstkctr)
2501 stktable_release(stkctr->table, stkctr_entry(stkctr));
2502 return 0; /* parameter not stored */
2503 }
2504
2505 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2506
2507 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2508 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2509
2510 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2511
2512 if (stkctr == &tmpstkctr)
2513 stktable_release(stkctr->table, stkctr_entry(stkctr));
2514 }
2515 return 1;
2516}
2517
Willy Tarreau7d562212016-11-25 16:10:05 +01002518/* Increment the General Purpose Counter 0 value from the stream's tracked
2519 * frontend counters and return it into temp integer.
2520 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2521 */
2522static int
2523smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2524{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002525 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002526 struct stkctr *stkctr;
2527
Emeric Brun819fc6f2017-06-13 19:37:32 +02002528 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002529 if (!stkctr)
2530 return 0;
2531
2532 smp->flags = SMP_F_VOL_TEST;
2533 smp->data.type = SMP_T_SINT;
2534 smp->data.u.sint = 0;
2535
Emeric Brun819fc6f2017-06-13 19:37:32 +02002536 if (!stkctr_entry(stkctr))
2537 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002538
2539 if (stkctr && stkctr_entry(stkctr)) {
2540 void *ptr1,*ptr2;
2541
Emeric Brun819fc6f2017-06-13 19:37:32 +02002542
Willy Tarreau7d562212016-11-25 16:10:05 +01002543 /* First, update gpc0_rate if it's tracked. Second, update its
2544 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2545 */
2546 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002547 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002548 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002549 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002550
Emeric Brun819fc6f2017-06-13 19:37:32 +02002551 if (ptr1) {
2552 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2553 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2554 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2555 }
2556
2557 if (ptr2)
2558 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2559
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002560 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002561
2562 /* If data was modified, we need to touch to re-schedule sync */
2563 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2564 }
2565 else if (stkctr == &tmpstkctr)
2566 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002567 }
2568 return 1;
2569}
2570
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002571/* Increment the General Purpose Counter 1 value from the stream's tracked
2572 * frontend counters and return it into temp integer.
2573 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2574 */
2575static int
2576smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2577{
2578 struct stkctr tmpstkctr;
2579 struct stkctr *stkctr;
2580
2581 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2582 if (!stkctr)
2583 return 0;
2584
2585 smp->flags = SMP_F_VOL_TEST;
2586 smp->data.type = SMP_T_SINT;
2587 smp->data.u.sint = 0;
2588
2589 if (!stkctr_entry(stkctr))
2590 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2591
2592 if (stkctr && stkctr_entry(stkctr)) {
2593 void *ptr1,*ptr2;
2594
2595
2596 /* First, update gpc1_rate if it's tracked. Second, update its
2597 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2598 */
2599 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2600 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2601 if (ptr1 || ptr2) {
2602 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2603
2604 if (ptr1) {
2605 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2606 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2607 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2608 }
2609
2610 if (ptr2)
2611 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2612
2613 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2614
2615 /* If data was modified, we need to touch to re-schedule sync */
2616 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2617 }
2618 else if (stkctr == &tmpstkctr)
2619 stktable_release(stkctr->table, stkctr_entry(stkctr));
2620 }
2621 return 1;
2622}
2623
Willy Tarreau7d562212016-11-25 16:10:05 +01002624/* Clear the General Purpose Counter 0 value from the stream's tracked
2625 * frontend counters and return its previous value into temp integer.
2626 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2627 */
2628static int
2629smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2630{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002631 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002632 struct stkctr *stkctr;
2633
Emeric Brun819fc6f2017-06-13 19:37:32 +02002634 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002635 if (!stkctr)
2636 return 0;
2637
2638 smp->flags = SMP_F_VOL_TEST;
2639 smp->data.type = SMP_T_SINT;
2640 smp->data.u.sint = 0;
2641
Emeric Brun819fc6f2017-06-13 19:37:32 +02002642 if (!stkctr_entry(stkctr))
2643 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002644
Emeric Brun819fc6f2017-06-13 19:37:32 +02002645 if (stkctr && stkctr_entry(stkctr)) {
2646 void *ptr;
2647
2648 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2649 if (!ptr) {
2650 if (stkctr == &tmpstkctr)
2651 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002652 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002653 }
2654
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002655 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002656
Willy Tarreau7d562212016-11-25 16:10:05 +01002657 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2658 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002659
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002660 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002661
Willy Tarreau7d562212016-11-25 16:10:05 +01002662 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002663 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002664 }
2665 return 1;
2666}
2667
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002668/* Clear the General Purpose Counter 1 value from the stream's tracked
2669 * frontend counters and return its previous value into temp integer.
2670 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2671 */
2672static int
2673smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2674{
2675 struct stkctr tmpstkctr;
2676 struct stkctr *stkctr;
2677
2678 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2679 if (!stkctr)
2680 return 0;
2681
2682 smp->flags = SMP_F_VOL_TEST;
2683 smp->data.type = SMP_T_SINT;
2684 smp->data.u.sint = 0;
2685
2686 if (!stkctr_entry(stkctr))
2687 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2688
2689 if (stkctr && stkctr_entry(stkctr)) {
2690 void *ptr;
2691
2692 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2693 if (!ptr) {
2694 if (stkctr == &tmpstkctr)
2695 stktable_release(stkctr->table, stkctr_entry(stkctr));
2696 return 0; /* parameter not stored */
2697 }
2698
2699 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2700
2701 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2702 stktable_data_cast(ptr, gpc1) = 0;
2703
2704 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2705
2706 /* If data was modified, we need to touch to re-schedule sync */
2707 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2708 }
2709 return 1;
2710}
2711
Willy Tarreau7d562212016-11-25 16:10:05 +01002712/* set <smp> to the cumulated number of connections from the stream's tracked
2713 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2714 * "src_conn_cnt" only.
2715 */
2716static int
2717smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2718{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002719 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002720 struct stkctr *stkctr;
2721
Emeric Brun819fc6f2017-06-13 19:37:32 +02002722 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002723 if (!stkctr)
2724 return 0;
2725
2726 smp->flags = SMP_F_VOL_TEST;
2727 smp->data.type = SMP_T_SINT;
2728 smp->data.u.sint = 0;
2729 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730 void *ptr;
2731
2732 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2733 if (!ptr) {
2734 if (stkctr == &tmpstkctr)
2735 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002736 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002737 }
2738
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002739 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002740
Willy Tarreau7d562212016-11-25 16:10:05 +01002741 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002742
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002743 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002744
2745 if (stkctr == &tmpstkctr)
2746 stktable_release(stkctr->table, stkctr_entry(stkctr));
2747
2748
Willy Tarreau7d562212016-11-25 16:10:05 +01002749 }
2750 return 1;
2751}
2752
2753/* set <smp> to the connection rate from the stream's tracked frontend
2754 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2755 * only.
2756 */
2757static int
2758smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2759{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002760 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002761 struct stkctr *stkctr;
2762
Emeric Brun819fc6f2017-06-13 19:37:32 +02002763 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002764 if (!stkctr)
2765 return 0;
2766
2767 smp->flags = SMP_F_VOL_TEST;
2768 smp->data.type = SMP_T_SINT;
2769 smp->data.u.sint = 0;
2770 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771 void *ptr;
2772
2773 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2774 if (!ptr) {
2775 if (stkctr == &tmpstkctr)
2776 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002777 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002778 }
2779
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002780 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002781
Willy Tarreau7d562212016-11-25 16:10:05 +01002782 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2783 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002784
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002785 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002786
2787 if (stkctr == &tmpstkctr)
2788 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002789 }
2790 return 1;
2791}
2792
2793/* set temp integer to the number of connections from the stream's source address
2794 * in the table pointed to by expr, after updating it.
2795 * Accepts exactly 1 argument of type table.
2796 */
2797static int
2798smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2799{
2800 struct connection *conn = objt_conn(smp->sess->origin);
2801 struct stksess *ts;
2802 struct stktable_key *key;
2803 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002804 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002805
2806 if (!conn)
2807 return 0;
2808
Joseph Herlant5662fa42018-11-15 13:43:28 -08002809 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002810 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2811 return 0;
2812
2813 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002814 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002815 if (!key)
2816 return 0;
2817
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002818 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002819
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002820 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002821 /* entry does not exist and could not be created */
2822 return 0;
2823
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002824 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002825 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002826 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002828
2829 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002830
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002831 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002832
Willy Tarreau7d562212016-11-25 16:10:05 +01002833 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002834
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002835 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002836
Willy Tarreau7d562212016-11-25 16:10:05 +01002837 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002838
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002839 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002840
2841 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002842 return 1;
2843}
2844
2845/* set <smp> to the number of concurrent connections from the stream's tracked
2846 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2847 * "src_conn_cur" only.
2848 */
2849static int
2850smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2851{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002852 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002853 struct stkctr *stkctr;
2854
Emeric Brun819fc6f2017-06-13 19:37:32 +02002855 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 if (!stkctr)
2857 return 0;
2858
2859 smp->flags = SMP_F_VOL_TEST;
2860 smp->data.type = SMP_T_SINT;
2861 smp->data.u.sint = 0;
2862 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002863 void *ptr;
2864
2865 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2866 if (!ptr) {
2867 if (stkctr == &tmpstkctr)
2868 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002869 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002870 }
2871
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002872 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002873
Willy Tarreau7d562212016-11-25 16:10:05 +01002874 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002875
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002876 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877
2878 if (stkctr == &tmpstkctr)
2879 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002880 }
2881 return 1;
2882}
2883
2884/* set <smp> to the cumulated number of streams from the stream's tracked
2885 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2886 * "src_sess_cnt" only.
2887 */
2888static int
2889smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2890{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002891 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002892 struct stkctr *stkctr;
2893
Emeric Brun819fc6f2017-06-13 19:37:32 +02002894 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 if (!stkctr)
2896 return 0;
2897
2898 smp->flags = SMP_F_VOL_TEST;
2899 smp->data.type = SMP_T_SINT;
2900 smp->data.u.sint = 0;
2901 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002902 void *ptr;
2903
2904 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2905 if (!ptr) {
2906 if (stkctr == &tmpstkctr)
2907 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002908 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002909 }
2910
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002911 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002912
Willy Tarreau7d562212016-11-25 16:10:05 +01002913 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002914
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002915 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916
2917 if (stkctr == &tmpstkctr)
2918 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002919 }
2920 return 1;
2921}
2922
2923/* set <smp> to the stream rate from the stream's tracked frontend counters.
2924 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2925 */
2926static int
2927smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2928{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002929 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002930 struct stkctr *stkctr;
2931
Emeric Brun819fc6f2017-06-13 19:37:32 +02002932 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 if (!stkctr)
2934 return 0;
2935
2936 smp->flags = SMP_F_VOL_TEST;
2937 smp->data.type = SMP_T_SINT;
2938 smp->data.u.sint = 0;
2939 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002940 void *ptr;
2941
2942 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2943 if (!ptr) {
2944 if (stkctr == &tmpstkctr)
2945 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002946 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002947 }
2948
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002949 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002950
Willy Tarreau7d562212016-11-25 16:10:05 +01002951 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2952 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002953
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002954 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955
2956 if (stkctr == &tmpstkctr)
2957 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002958 }
2959 return 1;
2960}
2961
2962/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2963 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2964 * "src_http_req_cnt" only.
2965 */
2966static int
2967smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2968{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002969 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002970 struct stkctr *stkctr;
2971
Emeric Brun819fc6f2017-06-13 19:37:32 +02002972 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002973 if (!stkctr)
2974 return 0;
2975
2976 smp->flags = SMP_F_VOL_TEST;
2977 smp->data.type = SMP_T_SINT;
2978 smp->data.u.sint = 0;
2979 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002980 void *ptr;
2981
2982 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2983 if (!ptr) {
2984 if (stkctr == &tmpstkctr)
2985 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002986 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002987 }
2988
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002989 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002990
Willy Tarreau7d562212016-11-25 16:10:05 +01002991 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002993 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002994
2995 if (stkctr == &tmpstkctr)
2996 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002997 }
2998 return 1;
2999}
3000
3001/* set <smp> to the HTTP request rate from the stream's tracked frontend
3002 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3003 * "src_http_req_rate" only.
3004 */
3005static int
3006smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3007{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003008 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003009 struct stkctr *stkctr;
3010
Emeric Brun819fc6f2017-06-13 19:37:32 +02003011 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003012 if (!stkctr)
3013 return 0;
3014
3015 smp->flags = SMP_F_VOL_TEST;
3016 smp->data.type = SMP_T_SINT;
3017 smp->data.u.sint = 0;
3018 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003019 void *ptr;
3020
3021 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3022 if (!ptr) {
3023 if (stkctr == &tmpstkctr)
3024 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003025 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003026 }
3027
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003028 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003029
Willy Tarreau7d562212016-11-25 16:10:05 +01003030 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3031 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003032
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003033 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003034
3035 if (stkctr == &tmpstkctr)
3036 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003037 }
3038 return 1;
3039}
3040
3041/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3042 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3043 * "src_http_err_cnt" only.
3044 */
3045static int
3046smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3047{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003048 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003049 struct stkctr *stkctr;
3050
Emeric Brun819fc6f2017-06-13 19:37:32 +02003051 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003052 if (!stkctr)
3053 return 0;
3054
3055 smp->flags = SMP_F_VOL_TEST;
3056 smp->data.type = SMP_T_SINT;
3057 smp->data.u.sint = 0;
3058 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003059 void *ptr;
3060
3061 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3062 if (!ptr) {
3063 if (stkctr == &tmpstkctr)
3064 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003065 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003066 }
3067
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003068 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003069
Willy Tarreau7d562212016-11-25 16:10:05 +01003070 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003071
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003072 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003073
3074 if (stkctr == &tmpstkctr)
3075 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003076 }
3077 return 1;
3078}
3079
3080/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3081 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3082 * "src_http_err_rate" only.
3083 */
3084static int
3085smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3086{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003087 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003088 struct stkctr *stkctr;
3089
Emeric Brun819fc6f2017-06-13 19:37:32 +02003090 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003091 if (!stkctr)
3092 return 0;
3093
3094 smp->flags = SMP_F_VOL_TEST;
3095 smp->data.type = SMP_T_SINT;
3096 smp->data.u.sint = 0;
3097 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003098 void *ptr;
3099
3100 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3101 if (!ptr) {
3102 if (stkctr == &tmpstkctr)
3103 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003104 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003105 }
3106
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003107 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003108
Willy Tarreau7d562212016-11-25 16:10:05 +01003109 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3110 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003111
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003112 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003113
3114 if (stkctr == &tmpstkctr)
3115 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003116 }
3117 return 1;
3118}
3119
3120/* set <smp> to the number of kbytes received from clients, as found in the
3121 * stream's tracked frontend counters. Supports being called as
3122 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3123 */
3124static int
3125smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3126{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003128 struct stkctr *stkctr;
3129
Emeric Brun819fc6f2017-06-13 19:37:32 +02003130 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003131 if (!stkctr)
3132 return 0;
3133
3134 smp->flags = SMP_F_VOL_TEST;
3135 smp->data.type = SMP_T_SINT;
3136 smp->data.u.sint = 0;
3137 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003138 void *ptr;
3139
3140 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3141 if (!ptr) {
3142 if (stkctr == &tmpstkctr)
3143 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003144 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003145 }
3146
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003147 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003148
Willy Tarreau7d562212016-11-25 16:10:05 +01003149 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003150
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003151 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003152
3153 if (stkctr == &tmpstkctr)
3154 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003155 }
3156 return 1;
3157}
3158
3159/* set <smp> to the data rate received from clients in bytes/s, as found
3160 * in the stream's tracked frontend counters. Supports being called as
3161 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3162 */
3163static int
3164smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3165{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003166 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003167 struct stkctr *stkctr;
3168
Emeric Brun819fc6f2017-06-13 19:37:32 +02003169 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003170 if (!stkctr)
3171 return 0;
3172
3173 smp->flags = SMP_F_VOL_TEST;
3174 smp->data.type = SMP_T_SINT;
3175 smp->data.u.sint = 0;
3176 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003177 void *ptr;
3178
3179 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3180 if (!ptr) {
3181 if (stkctr == &tmpstkctr)
3182 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003183 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003184 }
3185
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003186 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003187
Willy Tarreau7d562212016-11-25 16:10:05 +01003188 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3189 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003190
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003191 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003192
3193 if (stkctr == &tmpstkctr)
3194 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003195 }
3196 return 1;
3197}
3198
3199/* set <smp> to the number of kbytes sent to clients, as found in the
3200 * stream's tracked frontend counters. Supports being called as
3201 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3202 */
3203static int
3204smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3205{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003206 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003207 struct stkctr *stkctr;
3208
Emeric Brun819fc6f2017-06-13 19:37:32 +02003209 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003210 if (!stkctr)
3211 return 0;
3212
3213 smp->flags = SMP_F_VOL_TEST;
3214 smp->data.type = SMP_T_SINT;
3215 smp->data.u.sint = 0;
3216 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217 void *ptr;
3218
3219 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3220 if (!ptr) {
3221 if (stkctr == &tmpstkctr)
3222 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003223 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003224 }
3225
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003226 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227
Willy Tarreau7d562212016-11-25 16:10:05 +01003228 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003229
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003230 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003231
3232 if (stkctr == &tmpstkctr)
3233 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003234 }
3235 return 1;
3236}
3237
3238/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3239 * stream's tracked frontend counters. Supports being called as
3240 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3241 */
3242static int
3243smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3244{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003245 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003246 struct stkctr *stkctr;
3247
Emeric Brun819fc6f2017-06-13 19:37:32 +02003248 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003249 if (!stkctr)
3250 return 0;
3251
3252 smp->flags = SMP_F_VOL_TEST;
3253 smp->data.type = SMP_T_SINT;
3254 smp->data.u.sint = 0;
3255 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003256 void *ptr;
3257
3258 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3259 if (!ptr) {
3260 if (stkctr == &tmpstkctr)
3261 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003262 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003263 }
3264
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003265 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003266
Willy Tarreau7d562212016-11-25 16:10:05 +01003267 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3268 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003269
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003270 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003271
3272 if (stkctr == &tmpstkctr)
3273 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003274 }
3275 return 1;
3276}
3277
3278/* set <smp> to the number of active trackers on the SC entry in the stream's
3279 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3280 */
3281static int
3282smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3283{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003284 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003285 struct stkctr *stkctr;
3286
Emeric Brun819fc6f2017-06-13 19:37:32 +02003287 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003288 if (!stkctr)
3289 return 0;
3290
3291 smp->flags = SMP_F_VOL_TEST;
3292 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003293 if (stkctr == &tmpstkctr) {
3294 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3295 stktable_release(stkctr->table, stkctr_entry(stkctr));
3296 }
3297 else {
3298 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3299 }
3300
Willy Tarreau7d562212016-11-25 16:10:05 +01003301 return 1;
3302}
3303
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003304
3305/* The functions below are used to manipulate table contents from the CLI.
3306 * There are 3 main actions, "clear", "set" and "show". The code is shared
3307 * between all actions, and the action is encoded in the void *private in
3308 * the appctx as well as in the keyword registration, among one of the
3309 * following values.
3310 */
3311
3312enum {
3313 STK_CLI_ACT_CLR,
3314 STK_CLI_ACT_SET,
3315 STK_CLI_ACT_SHOW,
3316};
3317
3318/* Dump the status of a table to a stream interface's
3319 * read buffer. It returns 0 if the output buffer is full
3320 * and needs to be called again, otherwise non-zero.
3321 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003322static int table_dump_head_to_buffer(struct buffer *msg,
3323 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003324 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003325{
3326 struct stream *s = si_strm(si);
3327
3328 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003329 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003330
3331 /* any other information should be dumped here */
3332
William Lallemand07a62f72017-05-24 00:57:40 +02003333 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003334 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3335
Willy Tarreau06d80a92017-10-19 14:32:15 +02003336 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003337 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003338 return 0;
3339 }
3340
3341 return 1;
3342}
3343
3344/* Dump a table entry to a stream interface's
3345 * read buffer. It returns 0 if the output buffer is full
3346 * and needs to be called again, otherwise non-zero.
3347 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003348static int table_dump_entry_to_buffer(struct buffer *msg,
3349 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003350 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003351{
3352 int dt;
3353
3354 chunk_appendf(msg, "%p:", entry);
3355
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003356 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003357 char addr[INET_ADDRSTRLEN];
3358 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3359 chunk_appendf(msg, " key=%s", addr);
3360 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003361 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003362 char addr[INET6_ADDRSTRLEN];
3363 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3364 chunk_appendf(msg, " key=%s", addr);
3365 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003366 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003367 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003368 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003369 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003370 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003371 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003372 }
3373 else {
3374 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003375 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003376 }
3377
3378 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3379
3380 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3381 void *ptr;
3382
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003383 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003384 continue;
3385 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003386 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003387 else
3388 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3389
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003390 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003391 switch (stktable_data_types[dt].std_type) {
3392 case STD_T_SINT:
3393 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3394 break;
3395 case STD_T_UINT:
3396 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3397 break;
3398 case STD_T_ULL:
3399 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3400 break;
3401 case STD_T_FRQP:
3402 chunk_appendf(msg, "%d",
3403 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003404 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003405 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003406 case STD_T_DICT: {
3407 struct dict_entry *de;
3408 de = stktable_data_cast(ptr, std_t_dict);
3409 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3410 break;
3411 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003412 }
3413 }
3414 chunk_appendf(msg, "\n");
3415
Willy Tarreau06d80a92017-10-19 14:32:15 +02003416 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003417 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003418 return 0;
3419 }
3420
3421 return 1;
3422}
3423
3424
3425/* Processes a single table entry matching a specific key passed in argument.
3426 * returns 0 if wants to be called again, 1 if has ended processing.
3427 */
3428static int table_process_entry_per_key(struct appctx *appctx, char **args)
3429{
3430 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003431 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003432 struct stksess *ts;
3433 uint32_t uint32_key;
3434 unsigned char ip6_key[sizeof(struct in6_addr)];
3435 long long value;
3436 int data_type;
3437 int cur_arg;
3438 void *ptr;
3439 struct freq_ctr_period *frqp;
3440
Willy Tarreau9d008692019-08-09 11:21:01 +02003441 if (!*args[4])
3442 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003443
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003444 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003445 case SMP_T_IPV4:
3446 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003447 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003448 break;
3449 case SMP_T_IPV6:
3450 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003451 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003452 break;
3453 case SMP_T_SINT:
3454 {
3455 char *endptr;
3456 unsigned long val;
3457 errno = 0;
3458 val = strtoul(args[4], &endptr, 10);
3459 if ((errno == ERANGE && val == ULONG_MAX) ||
3460 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003461 val > 0xffffffff)
3462 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003463 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003464 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003465 break;
3466 }
3467 break;
3468 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003469 static_table_key.key = args[4];
3470 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003471 break;
3472 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003473 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003474 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003475 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 +01003476 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003477 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 +01003478 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003479 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 +01003480 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003481 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003482 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003483 }
3484
3485 /* check permissions */
3486 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3487 return 1;
3488
Willy Tarreaua24bc782016-12-14 15:50:35 +01003489 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003490 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003491 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003492 if (!ts)
3493 return 1;
3494 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003495 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3496 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003497 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003498 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003499 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003500 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003501 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003502 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003503 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003504 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003505 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003506 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003507 break;
3508
3509 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003510 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003511 if (!ts)
3512 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003513
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003514 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003515 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003516 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003517 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003518 break;
3519
3520 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003521 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003522 if (!ts) {
3523 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003524 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003525 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003526 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003527 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3528 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003529 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003530 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003531 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003532 return 1;
3533 }
3534
3535 data_type = stktable_get_data_type(args[cur_arg] + 5);
3536 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003537 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003538 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003539 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003540 return 1;
3541 }
3542
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003543 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003544 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003545 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003546 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003547 return 1;
3548 }
3549
3550 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003551 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003552 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003553 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003554 return 1;
3555 }
3556
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003557 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003558
3559 switch (stktable_data_types[data_type].std_type) {
3560 case STD_T_SINT:
3561 stktable_data_cast(ptr, std_t_sint) = value;
3562 break;
3563 case STD_T_UINT:
3564 stktable_data_cast(ptr, std_t_uint) = value;
3565 break;
3566 case STD_T_ULL:
3567 stktable_data_cast(ptr, std_t_ull) = value;
3568 break;
3569 case STD_T_FRQP:
3570 /* We set both the current and previous values. That way
3571 * the reported frequency is stable during all the period
3572 * then slowly fades out. This allows external tools to
3573 * push measures without having to update them too often.
3574 */
3575 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003576 /* First bit is reserved for the freq_ctr_period lock
3577 Note: here we're still protected by the stksess lock
3578 so we don't need to update the update the freq_ctr_period
3579 using its internal lock */
3580 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003581 frqp->prev_ctr = 0;
3582 frqp->curr_ctr = value;
3583 break;
3584 }
3585 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003586 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003587 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003588 break;
3589
3590 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003591 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003592 }
3593 return 1;
3594}
3595
3596/* Prepares the appctx fields with the data-based filters from the command line.
3597 * Returns 0 if the dump can proceed, 1 if has ended processing.
3598 */
3599static int table_prepare_data_request(struct appctx *appctx, char **args)
3600{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003601 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003602 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003603
Willy Tarreau9d008692019-08-09 11:21:01 +02003604 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3605 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003606
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003607 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3608 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3609 break;
3610 /* condition on stored data value */
3611 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3612 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003613 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003614
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003615 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003616 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 +01003617
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003618 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003619 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003620 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 +01003621
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003622 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 +01003623 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3624 }
3625
3626 if (*args[3+3*i]) {
3627 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 +01003628 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003629
3630 /* OK we're done, all the fields are set */
3631 return 0;
3632}
3633
3634/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003635static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003636{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003637 int i;
3638
3639 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3640 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003641 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003642 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003643 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003644
3645 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003646 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003647 if (!appctx->ctx.table.target)
3648 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003649 }
3650 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003651 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003652 goto err_args;
3653 return 0;
3654 }
3655
3656 if (strcmp(args[3], "key") == 0)
3657 return table_process_entry_per_key(appctx, args);
3658 else if (strncmp(args[3], "data.", 5) == 0)
3659 return table_prepare_data_request(appctx, args);
3660 else if (*args[3])
3661 goto err_args;
3662
3663 return 0;
3664
3665err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003666 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003667 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003668 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 +01003669 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003670 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 +01003671 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003672 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003673 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003674 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003675 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003676}
3677
3678/* This function is used to deal with table operations (dump or clear depending
3679 * on the action stored in appctx->private). It returns 0 if the output buffer is
3680 * full and it needs to be called again, otherwise non-zero.
3681 */
3682static int cli_io_handler_table(struct appctx *appctx)
3683{
3684 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003685 struct stream *s = si_strm(si);
3686 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003687 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003688 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003689
3690 /*
3691 * We have 3 possible states in appctx->st2 :
3692 * - STAT_ST_INIT : the first call
3693 * - STAT_ST_INFO : the proxy pointer points to the next table to
3694 * dump, the entry pointer is NULL ;
3695 * - STAT_ST_LIST : the proxy pointer points to the current table
3696 * and the entry pointer points to the next entry to be dumped,
3697 * and the refcount on the next entry is held ;
3698 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3699 * data though.
3700 */
3701
3702 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3703 /* in case of abort, remove any refcount we might have set on an entry */
3704 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003705 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003706 }
3707 return 1;
3708 }
3709
3710 chunk_reset(&trash);
3711
3712 while (appctx->st2 != STAT_ST_FIN) {
3713 switch (appctx->st2) {
3714 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003715 appctx->ctx.table.t = appctx->ctx.table.target;
3716 if (!appctx->ctx.table.t)
3717 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003718
3719 appctx->ctx.table.entry = NULL;
3720 appctx->st2 = STAT_ST_INFO;
3721 break;
3722
3723 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003724 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003725 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003726 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003727 appctx->st2 = STAT_ST_END;
3728 break;
3729 }
3730
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003731 if (appctx->ctx.table.t->size) {
3732 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003733 return 0;
3734
3735 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003736 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003737 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003738 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3739 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003740 if (eb) {
3741 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3742 appctx->ctx.table.entry->ref_cnt++;
3743 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003744 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003745 break;
3746 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003747 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003748 }
3749 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003750 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 break;
3752
3753 case STAT_ST_LIST:
3754 skip_entry = 0;
3755
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003756 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003757
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003758 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003759 /* we're filtering on some data contents */
3760 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003761 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003762 signed char op;
3763 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003764
Emeric Brun819fc6f2017-06-13 19:37:32 +02003765
Willy Tarreau2b64a352020-01-22 17:09:47 +01003766 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003767 if (appctx->ctx.table.data_type[i] == -1)
3768 break;
3769 dt = appctx->ctx.table.data_type[i];
3770 ptr = stktable_data_ptr(appctx->ctx.table.t,
3771 appctx->ctx.table.entry,
3772 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003773
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003774 data = 0;
3775 switch (stktable_data_types[dt].std_type) {
3776 case STD_T_SINT:
3777 data = stktable_data_cast(ptr, std_t_sint);
3778 break;
3779 case STD_T_UINT:
3780 data = stktable_data_cast(ptr, std_t_uint);
3781 break;
3782 case STD_T_ULL:
3783 data = stktable_data_cast(ptr, std_t_ull);
3784 break;
3785 case STD_T_FRQP:
3786 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3787 appctx->ctx.table.t->data_arg[dt].u);
3788 break;
3789 }
3790
3791 op = appctx->ctx.table.data_op[i];
3792 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003793
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003794 /* skip the entry if the data does not match the test and the value */
3795 if ((data < value &&
3796 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3797 (data == value &&
3798 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3799 (data > value &&
3800 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3801 skip_entry = 1;
3802 break;
3803 }
3804 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003805 }
3806
3807 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003808 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003809 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003810 return 0;
3811 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003812
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003813 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003814
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003815 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003816 appctx->ctx.table.entry->ref_cnt--;
3817
3818 eb = ebmb_next(&appctx->ctx.table.entry->key);
3819 if (eb) {
3820 struct stksess *old = appctx->ctx.table.entry;
3821 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3822 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003823 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003824 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003825 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003826 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003827 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003828 break;
3829 }
3830
3831
3832 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003833 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003834 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003835 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003836
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003837 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003838
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003839 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003840 appctx->st2 = STAT_ST_INFO;
3841 break;
3842
3843 case STAT_ST_END:
3844 appctx->st2 = STAT_ST_FIN;
3845 break;
3846 }
3847 }
3848 return 1;
3849}
3850
3851static void cli_release_show_table(struct appctx *appctx)
3852{
3853 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003854 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003855 }
3856}
3857
3858/* register cli keywords */
3859static struct cli_kw_list cli_kws = {{ },{
3860 { { "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 },
3861 { { "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 },
3862 { { "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 },
3863 {{},}
3864}};
3865
Willy Tarreau0108d902018-11-25 19:14:37 +01003866INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003867
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003868static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003869 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003870 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003871 { "sc-set-gpt0", parse_set_gpt0, 1 },
3872 { /* END */ }
3873}};
3874
Willy Tarreau0108d902018-11-25 19:14:37 +01003875INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3876
Willy Tarreau620408f2016-10-21 16:37:51 +02003877static struct action_kw_list tcp_sess_kws = { { }, {
3878 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003879 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003880 { "sc-set-gpt0", parse_set_gpt0, 1 },
3881 { /* END */ }
3882}};
3883
Willy Tarreau0108d902018-11-25 19:14:37 +01003884INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3885
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003886static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003887 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003888 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003889 { "sc-set-gpt0", parse_set_gpt0, 1 },
3890 { /* END */ }
3891}};
3892
Willy Tarreau0108d902018-11-25 19:14:37 +01003893INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3894
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003895static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003896 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003897 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003898 { "sc-set-gpt0", parse_set_gpt0, 1 },
3899 { /* END */ }
3900}};
3901
Willy Tarreau0108d902018-11-25 19:14:37 +01003902INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3903
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003904static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003905 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003906 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003907 { "sc-set-gpt0", parse_set_gpt0, 1 },
3908 { /* END */ }
3909}};
3910
Willy Tarreau0108d902018-11-25 19:14:37 +01003911INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3912
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003913static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003914 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003915 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003916 { "sc-set-gpt0", parse_set_gpt0, 1 },
3917 { /* END */ }
3918}};
3919
Willy Tarreau0108d902018-11-25 19:14:37 +01003920INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3921
Willy Tarreau7d562212016-11-25 16:10:05 +01003922///* Note: must not be declared <const> as its list will be overwritten.
3923// * Please take care of keeping this list alphabetically sorted.
3924// */
3925//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3926// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3927// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3928// { /* END */ },
3929//}};
3930/* Note: must not be declared <const> as its list will be overwritten.
3931 * Please take care of keeping this list alphabetically sorted.
3932 */
3933static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3934 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3935 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3936 { "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 +01003937 { "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 +01003938 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3939 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3940 { "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 +01003941 { "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 +01003942 { "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 +01003943 { "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 +01003944 { "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 +01003945 { "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 +01003946 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3947 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3948 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3949 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3950 { "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 +01003951 { "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 +01003952 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3953 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3954 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3955 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3956 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3957 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3958 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3959 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3960 { "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 +01003961 { "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 +01003962 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3963 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3964 { "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 +01003965 { "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 +01003966 { "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 +01003967 { "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 +01003968 { "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 +01003969 { "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 +01003970 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3971 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3972 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3973 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3974 { "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 +01003975 { "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 +01003976 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3977 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3978 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3979 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3980 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3981 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3982 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3984 { "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 +01003985 { "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 +01003986 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3987 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3988 { "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 +01003989 { "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 +01003990 { "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 +01003991 { "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 +01003992 { "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 +01003993 { "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 +01003994 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3995 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3996 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3997 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3998 { "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 +01003999 { "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 +01004000 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4001 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4002 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4003 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4004 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4005 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4007 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4008 { "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 +01004009 { "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 +01004010 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4011 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4012 { "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 +01004013 { "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 +01004014 { "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 +01004015 { "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 +01004016 { "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 +01004017 { "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 +01004018 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4019 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4020 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4021 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4022 { "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 +01004023 { "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 +01004024 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4025 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4026 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4027 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4028 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4029 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4030 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4031 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4032 { "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 +01004033 { "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 +01004034 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4035 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4036 { "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 +01004037 { "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 +01004038 { "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 +01004039 { "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 +01004040 { "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 +01004041 { "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 +01004042 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4043 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4044 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4045 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4046 { "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 +01004047 { "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 +01004048 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4049 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4050 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4051 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4052 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4053 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4054 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4055 { /* END */ },
4056}};
4057
Willy Tarreau0108d902018-11-25 19:14:37 +01004058INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004059
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004060/* Note: must not be declared <const> as its list will be overwritten */
4061static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004062 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4063 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4064 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4065 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4066 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4067 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4068 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4069 { "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 +01004070 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004071 { "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 +01004072 { "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 +02004073 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4074 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4075 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4076 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4077 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4078 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4079 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4080 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4081 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4082 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004083 { /* END */ },
4084}};
4085
Willy Tarreau0108d902018-11-25 19:14:37 +01004086INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);