blob: 72b0f8b6b71479ae9f2bc86acc9af65290ddb8fa [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
17#include <common/config.h>
Frédéric Lécailled456aa42019-03-08 14:47:00 +010018#include <common/cfgparse.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010019#include <common/initcall.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010020#include <common/memory.h>
21#include <common/mini-clist.h>
Willy Tarreau6cde5d82020-02-25 09:41:22 +010022#include <common/net_helper.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010023#include <common/standard.h>
24#include <common/time.h>
25
26#include <ebmbtree.h>
27#include <ebsttree.h>
28
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010029#include <types/cli.h>
Willy Tarreau39713102016-11-25 15:49:32 +010030#include <types/global.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010031#include <types/stats.h>
32
Willy Tarreaud9f316a2014-07-10 14:03:38 +020033#include <proto/arg.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010034#include <proto/cli.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020035#include <proto/http_rules.h>
Andjelko Iharosc3680ec2017-07-20 16:49:14 +020036#include <proto/log.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020037#include <proto/http_ana.h>
Willy Tarreau7d562212016-11-25 16:10:05 +010038#include <proto/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010039#include <proto/proxy.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020040#include <proto/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020041#include <proto/stream.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010042#include <proto/stream_interface.h>
Willy Tarreau68129b92010-06-06 16:06:52 +020043#include <proto/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010044#include <proto/task.h>
Emeric Brun32da3c42010-09-23 18:39:19 +020045#include <proto/peers.h>
Willy Tarreau39713102016-11-25 15:49:32 +010046#include <proto/tcp_rules.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010047
Willy Tarreau12785782012-04-27 21:37:17 +020048/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020049static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020050
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010051struct stktable *stktables_list;
52struct eb_root stktable_by_name = EB_ROOT;
53
Olivier Houchard52dabbc2018-11-14 17:54:36 +010054#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010055
56/* This function inserts stktable <t> into the tree of known stick-table.
57 * The stick-table ID is used as the storing key so it must already have
58 * been initialized.
59 */
60void stktable_store_name(struct stktable *t)
61{
62 t->name.key = t->id;
63 ebis_insert(&stktable_by_name, &t->name);
64}
65
66struct stktable *stktable_find_by_name(const char *name)
67{
68 struct ebpt_node *node;
69 struct stktable *t;
70
71 node = ebis_lookup(&stktable_by_name, name);
72 if (node) {
73 t = container_of(node, struct stktable, name);
74 if (!strcmp(t->id, name))
75 return t;
76 }
77
78 return NULL;
79}
80
Emeric Brun3bd697e2010-01-04 15:23:48 +010081/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020082 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
83 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010084 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020085void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010086{
87 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010088 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010089}
90
91/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020092 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
93 * in table <t>.
94 * This function locks the table
95 */
96void stksess_free(struct stktable *t, struct stksess *ts)
97{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010098 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020099 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100100 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200101}
102
103/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200104 * Kill an stksess (only if its ref_cnt is zero).
105 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200106int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200107{
108 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200109 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200110
111 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200112 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200113 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200114 __stksess_free(t, ts);
115 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200116}
117
118/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200119 * Decrease the refcount if decrefcnt is not 0.
120 * and try to kill the stksess
121 * This function locks the table
122 */
123int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
124{
125 int ret;
126
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100127 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200128 if (decrefcnt)
129 ts->ref_cnt--;
130 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100131 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200132
133 return ret;
134}
135
136/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200137 * Initialize or update the key in the sticky session <ts> present in table <t>
138 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100139 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200140void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100141{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200142 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200143 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100144 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200145 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
146 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147 }
148}
149
150
151/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200152 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
153 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100154 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200155static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100156{
Willy Tarreau393379c2010-06-06 12:11:37 +0200157 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200158 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200159 ts->key.node.leaf_p = NULL;
160 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200161 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200162 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100163 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100164 return ts;
165}
166
167/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200168 * Trash oldest <to_batch> sticky sessions from table <t>
169 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100170 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200171int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100172{
173 struct stksess *ts;
174 struct eb32_node *eb;
175 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200176 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100177
178 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
179
180 while (batched < to_batch) {
181
182 if (unlikely(!eb)) {
183 /* we might have reached the end of the tree, typically because
184 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200185 * half. Let's loop back to the beginning of the tree now if we
186 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100187 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200188 if (looped)
189 break;
190 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100191 eb = eb32_first(&t->exps);
192 if (likely(!eb))
193 break;
194 }
195
196 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200197 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100198 eb = eb32_next(eb);
199
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200200 /* don't delete an entry which is currently referenced */
201 if (ts->ref_cnt)
202 continue;
203
Willy Tarreau86257dc2010-06-06 12:57:10 +0200204 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100205
Willy Tarreau86257dc2010-06-06 12:57:10 +0200206 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100207 if (!tick_isset(ts->expire))
208 continue;
209
Willy Tarreau86257dc2010-06-06 12:57:10 +0200210 ts->exp.key = ts->expire;
211 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100212
Willy Tarreau86257dc2010-06-06 12:57:10 +0200213 if (!eb || eb->key > ts->exp.key)
214 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100215
216 continue;
217 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100218
Willy Tarreauaea940e2010-06-06 11:56:36 +0200219 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200220 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200221 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200222 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100223 batched++;
224 }
225
226 return batched;
227}
228
229/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200230 * Trash oldest <to_batch> sticky sessions from table <t>
231 * Returns number of trashed sticky sessions.
232 * This function locks the table
233 */
234int stktable_trash_oldest(struct stktable *t, int to_batch)
235{
236 int ret;
237
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100238 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200239 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100240 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200241
242 return ret;
243}
244/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200245 * Allocate and initialise a new sticky session.
246 * The new sticky session is returned or NULL in case of lack of memory.
247 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200248 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
249 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100250 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200251struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100252{
253 struct stksess *ts;
254
255 if (unlikely(t->current == t->size)) {
256 if ( t->nopurge )
257 return NULL;
258
Emeric Brun819fc6f2017-06-13 19:37:32 +0200259 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100260 return NULL;
261 }
262
Willy Tarreaubafbe012017-11-24 17:34:44 +0100263 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264 if (ts) {
265 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100266 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200267 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200268 if (key)
269 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100270 }
271
272 return ts;
273}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200274/*
275 * Allocate and initialise a new sticky session.
276 * The new sticky session is returned or NULL in case of lack of memory.
277 * Sticky sessions should only be allocated this way, and must be freed using
278 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
279 * is not NULL, it is assigned to the new session.
280 * This function locks the table
281 */
282struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
283{
284 struct stksess *ts;
285
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100286 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200287 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100288 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200289
290 return ts;
291}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100292
293/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200294 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200295 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100296 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200297struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100298{
299 struct ebmb_node *eb;
300
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200301 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200302 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 +0100303 else
304 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
305
306 if (unlikely(!eb)) {
307 /* no session found */
308 return NULL;
309 }
310
Willy Tarreau86257dc2010-06-06 12:57:10 +0200311 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100312}
313
Emeric Brun819fc6f2017-06-13 19:37:32 +0200314/*
315 * Looks in table <t> for a sticky session matching key <key>.
316 * Returns pointer on requested sticky session or NULL if none was found.
317 * The refcount of the found entry is increased and this function
318 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200319 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200320struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200321{
322 struct stksess *ts;
323
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100324 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200325 ts = __stktable_lookup_key(t, key);
326 if (ts)
327 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100328 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200329
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200330 return ts;
331}
332
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200333/*
334 * Looks in table <t> for a sticky session with same key as <ts>.
335 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100336 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200337struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100338{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100339 struct ebmb_node *eb;
340
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200341 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200342 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100343 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200344 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100345
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200346 if (unlikely(!eb))
347 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100348
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200349 return ebmb_entry(eb, struct stksess, key);
350}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100351
Emeric Brun819fc6f2017-06-13 19:37:32 +0200352/*
353 * Looks in table <t> for a sticky session with same key as <ts>.
354 * Returns pointer on requested sticky session or NULL if none was found.
355 * The refcount of the found entry is increased and this function
356 * is protected using the table lock
357 */
358struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
359{
360 struct stksess *lts;
361
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100362 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200363 lts = __stktable_lookup(t, ts);
364 if (lts)
365 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100366 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200367
368 return lts;
369}
370
Willy Tarreaucb183642010-06-06 17:58:34 +0200371/* Update the expiration timer for <ts> but do not touch its expiration node.
372 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200373 * The node will be also inserted into the update tree if needed, at a position
374 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200375 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200376void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200377{
Emeric Brun85e77c72010-09-23 18:16:52 +0200378 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200379 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200380 if (t->expire) {
381 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
382 task_queue(t->exp_task);
383 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200384
Emeric Brun819fc6f2017-06-13 19:37:32 +0200385 /* If sync is enabled */
386 if (t->sync_task) {
387 if (local) {
388 /* If this entry is not in the tree
389 or not scheduled for at least one peer */
390 if (!ts->upd.node.leaf_p
391 || (int)(t->commitupdate - ts->upd.key) >= 0
392 || (int)(ts->upd.key - t->localupdate) >= 0) {
393 ts->upd.key = ++t->update;
394 t->localupdate = t->update;
395 eb32_delete(&ts->upd);
396 eb = eb32_insert(&t->updates, &ts->upd);
397 if (eb != &ts->upd) {
398 eb32_delete(eb);
399 eb32_insert(&t->updates, &ts->upd);
400 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200401 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200402 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200403 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200404 else {
405 /* If this entry is not in the tree */
406 if (!ts->upd.node.leaf_p) {
407 ts->upd.key= (++t->update)+(2147483648U);
408 eb = eb32_insert(&t->updates, &ts->upd);
409 if (eb != &ts->upd) {
410 eb32_delete(eb);
411 eb32_insert(&t->updates, &ts->upd);
412 }
413 }
414 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200415 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200416}
417
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200418/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200419 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200420 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200421 * The node will be also inserted into the update tree if needed, at a position
422 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200423 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200424void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
425{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100426 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200427 __stktable_touch_with_exp(t, ts, 0, ts->expire);
428 if (decrefcnt)
429 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100430 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200431}
432
433/* Update the expiration timer for <ts> but do not touch its expiration node.
434 * The table's expiration timer is updated using the date of expiration coming from
435 * <t> stick-table configuration.
436 * The node will be also inserted into the update tree if needed, at a position
437 * considering the update was made locally
438 */
439void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200440{
441 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
442
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100443 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200444 __stktable_touch_with_exp(t, ts, 1, expire);
445 if (decrefcnt)
446 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100447 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200448}
Willy Tarreau43e90352018-06-27 06:25:57 +0200449/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
450static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200451{
Willy Tarreau43e90352018-06-27 06:25:57 +0200452 if (!ts)
453 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100454 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200455 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100456 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200457}
458
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200459/* Insert new sticky session <ts> in the table. It is assumed that it does not
460 * yet exist (the caller must check this). The table's timeout is updated if it
461 * is set. <ts> is returned.
462 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200463void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200464{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100465
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200466 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200467 ts->exp.key = ts->expire;
468 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200469 if (t->expire) {
470 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
471 task_queue(t->exp_task);
472 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200473}
474
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200475/* Returns a valid or initialized stksess for the specified stktable_key in the
476 * specified table, or NULL if the key was NULL, or if no entry was found nor
477 * could be created. The entry's expiration is updated.
478 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200479struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200480{
481 struct stksess *ts;
482
483 if (!key)
484 return NULL;
485
Emeric Brun819fc6f2017-06-13 19:37:32 +0200486 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200487 if (ts == NULL) {
488 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200489 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200490 if (!ts)
491 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200492 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200493 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200494 return ts;
495}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200496/* Returns a valid or initialized stksess for the specified stktable_key in the
497 * specified table, or NULL if the key was NULL, or if no entry was found nor
498 * could be created. The entry's expiration is updated.
499 * This function locks the table, and the refcount of the entry is increased.
500 */
501struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
502{
503 struct stksess *ts;
504
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100505 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200506 ts = __stktable_get_entry(table, key);
507 if (ts)
508 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100509 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200510
511 return ts;
512}
513
514/* Lookup for an entry with the same key and store the submitted
515 * stksess if not found.
516 */
517struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
518{
519 struct stksess *ts;
520
521 ts = __stktable_lookup(table, nts);
522 if (ts == NULL) {
523 ts = nts;
524 __stktable_store(table, ts);
525 }
526 return ts;
527}
528
529/* Lookup for an entry with the same key and store the submitted
530 * stksess if not found.
531 * This function locks the table, and the refcount of the entry is increased.
532 */
533struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
534{
535 struct stksess *ts;
536
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100537 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200538 ts = __stktable_set_entry(table, nts);
539 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100540 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200541
Emeric Brun819fc6f2017-06-13 19:37:32 +0200542 return ts;
543}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100544/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200545 * Trash expired sticky sessions from table <t>. The next expiration date is
546 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100547 */
548static int stktable_trash_expired(struct stktable *t)
549{
550 struct stksess *ts;
551 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200552 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100553
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100554 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100555 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
556
557 while (1) {
558 if (unlikely(!eb)) {
559 /* we might have reached the end of the tree, typically because
560 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200561 * half. Let's loop back to the beginning of the tree now if we
562 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100563 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200564 if (looped)
565 break;
566 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567 eb = eb32_first(&t->exps);
568 if (likely(!eb))
569 break;
570 }
571
572 if (likely(tick_is_lt(now_ms, eb->key))) {
573 /* timer not expired yet, revisit it later */
574 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100575 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100576 }
577
578 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200579 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100580 eb = eb32_next(eb);
581
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200582 /* don't delete an entry which is currently referenced */
583 if (ts->ref_cnt)
584 continue;
585
Willy Tarreau86257dc2010-06-06 12:57:10 +0200586 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100587
588 if (!tick_is_expired(ts->expire, now_ms)) {
589 if (!tick_isset(ts->expire))
590 continue;
591
Willy Tarreau86257dc2010-06-06 12:57:10 +0200592 ts->exp.key = ts->expire;
593 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100594
Willy Tarreau86257dc2010-06-06 12:57:10 +0200595 if (!eb || eb->key > ts->exp.key)
596 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100597 continue;
598 }
599
600 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200601 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200602 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200603 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100604 }
605
606 /* We have found no task to expire in any tree */
607 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100608out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100609 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100610 return t->exp_next;
611}
612
613/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200614 * Task processing function to trash expired sticky sessions. A pointer to the
615 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200617static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100618{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200619 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100620
621 task->expire = stktable_trash_expired(t);
622 return task;
623}
624
Willy Tarreauaea940e2010-06-06 11:56:36 +0200625/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100626int stktable_init(struct stktable *t)
627{
628 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200629 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100631 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100632 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100633
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100634 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 +0100635
636 t->exp_next = TICK_ETERNITY;
637 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200638 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200639 if (!t->exp_task)
640 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100641 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100642 t->exp_task->context = (void *)t;
643 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200644 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200645 peers_register_table(t->peers.p, t);
646 }
647
Emeric Brun3bd697e2010-01-04 15:23:48 +0100648 return t->pool != NULL;
649 }
650 return 1;
651}
652
653/*
654 * Configuration keywords of known table types
655 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200656struct stktable_type stktable_types[SMP_TYPES] = {
657 [SMP_T_SINT] = { "integer", 0, 4 },
658 [SMP_T_IPV4] = { "ip", 0, 4 },
659 [SMP_T_IPV6] = { "ipv6", 0, 16 },
660 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
661 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
662};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100663
664/*
665 * Parse table type configuration.
666 * Returns 0 on successful parsing, else 1.
667 * <myidx> is set at next configuration <args> index.
668 */
669int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
670{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200671 for (*type = 0; *type < SMP_TYPES; (*type)++) {
672 if (!stktable_types[*type].kw)
673 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100674 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
675 continue;
676
677 *key_size = stktable_types[*type].default_size;
678 (*myidx)++;
679
Willy Tarreauaea940e2010-06-06 11:56:36 +0200680 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100681 if (strcmp("len", args[*myidx]) == 0) {
682 (*myidx)++;
683 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200684 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100685 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200686 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200687 /* null terminated string needs +1 for '\0'. */
688 (*key_size)++;
689 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100690 (*myidx)++;
691 }
692 }
693 return 0;
694 }
695 return 1;
696}
697
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100698/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100699 * Parse a line with <linenum> as number in <file> configuration file to configure
700 * the stick-table with <t> as address and <id> as ID.
701 * <peers> provides the "peers" section pointer only if this function is called
702 * from a "peers" section.
703 * <nid> is the stick-table name which is sent over the network. It must be equal
704 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
705 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500706 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100707 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
708 */
709int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100710 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100711{
712 int err_code = 0;
713 int idx = 1;
714 unsigned int val;
715
716 if (!id || !*id) {
717 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
718 err_code |= ERR_ALERT | ERR_ABORT;
719 goto out;
720 }
721
722 /* Store the "peers" section if this function is called from a "peers" section. */
723 if (peers) {
724 t->peers.p = peers;
725 idx++;
726 }
727
728 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100729 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100730 t->type = (unsigned int)-1;
731 t->conf.file = file;
732 t->conf.line = linenum;
733
734 while (*args[idx]) {
735 const char *err;
736
737 if (strcmp(args[idx], "size") == 0) {
738 idx++;
739 if (!*(args[idx])) {
740 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
741 file, linenum, args[0], args[idx-1]);
742 err_code |= ERR_ALERT | ERR_FATAL;
743 goto out;
744 }
745 if ((err = parse_size_err(args[idx], &t->size))) {
746 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
747 file, linenum, args[0], *err, args[idx-1]);
748 err_code |= ERR_ALERT | ERR_FATAL;
749 goto out;
750 }
751 idx++;
752 }
753 /* This argument does not exit in "peers" section. */
754 else if (!peers && strcmp(args[idx], "peers") == 0) {
755 idx++;
756 if (!*(args[idx])) {
757 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
758 file, linenum, args[0], args[idx-1]);
759 err_code |= ERR_ALERT | ERR_FATAL;
760 goto out;
761 }
762 t->peers.name = strdup(args[idx++]);
763 }
764 else if (strcmp(args[idx], "expire") == 0) {
765 idx++;
766 if (!*(args[idx])) {
767 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
768 file, linenum, args[0], args[idx-1]);
769 err_code |= ERR_ALERT | ERR_FATAL;
770 goto out;
771 }
772 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200773 if (err == PARSE_TIME_OVER) {
774 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
775 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100776 err_code |= ERR_ALERT | ERR_FATAL;
777 goto out;
778 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200779 else if (err == PARSE_TIME_UNDER) {
780 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
781 file, linenum, args[0], args[idx], args[idx-1]);
782 err_code |= ERR_ALERT | ERR_FATAL;
783 goto out;
784 }
785 else if (err) {
786 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
787 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100788 err_code |= ERR_ALERT | ERR_FATAL;
789 goto out;
790 }
791 t->expire = val;
792 idx++;
793 }
794 else if (strcmp(args[idx], "nopurge") == 0) {
795 t->nopurge = 1;
796 idx++;
797 }
798 else if (strcmp(args[idx], "type") == 0) {
799 idx++;
800 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
801 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
802 file, linenum, args[0], args[idx]);
803 err_code |= ERR_ALERT | ERR_FATAL;
804 goto out;
805 }
806 /* idx already points to next arg */
807 }
808 else if (strcmp(args[idx], "store") == 0) {
809 int type, err;
810 char *cw, *nw, *sa;
811
812 idx++;
813 nw = args[idx];
814 while (*nw) {
815 /* the "store" keyword supports a comma-separated list */
816 cw = nw;
817 sa = NULL; /* store arg */
818 while (*nw && *nw != ',') {
819 if (*nw == '(') {
820 *nw = 0;
821 sa = ++nw;
822 while (*nw != ')') {
823 if (!*nw) {
824 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
825 file, linenum, args[0], cw);
826 err_code |= ERR_ALERT | ERR_FATAL;
827 goto out;
828 }
829 nw++;
830 }
831 *nw = '\0';
832 }
833 nw++;
834 }
835 if (*nw)
836 *nw++ = '\0';
837 type = stktable_get_data_type(cw);
838 if (type < 0) {
839 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
840 file, linenum, args[0], cw);
841 err_code |= ERR_ALERT | ERR_FATAL;
842 goto out;
843 }
844
845 err = stktable_alloc_data_type(t, type, sa);
846 switch (err) {
847 case PE_NONE: break;
848 case PE_EXIST:
849 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
850 file, linenum, args[0], cw);
851 err_code |= ERR_WARN;
852 break;
853
854 case PE_ARG_MISSING:
855 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
856 file, linenum, args[0], cw);
857 err_code |= ERR_ALERT | ERR_FATAL;
858 goto out;
859
860 case PE_ARG_NOT_USED:
861 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
862 file, linenum, args[0], cw);
863 err_code |= ERR_ALERT | ERR_FATAL;
864 goto out;
865
866 default:
867 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
868 file, linenum, args[0], cw);
869 err_code |= ERR_ALERT | ERR_FATAL;
870 goto out;
871 }
872 }
873 idx++;
874 }
875 else {
876 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
877 file, linenum, args[0], args[idx]);
878 err_code |= ERR_ALERT | ERR_FATAL;
879 goto out;
880 }
881 }
882
883 if (!t->size) {
884 ha_alert("parsing [%s:%d] : %s: missing size.\n",
885 file, linenum, args[0]);
886 err_code |= ERR_ALERT | ERR_FATAL;
887 goto out;
888 }
889
890 if (t->type == (unsigned int)-1) {
891 ha_alert("parsing [%s:%d] : %s: missing type.\n",
892 file, linenum, args[0]);
893 err_code |= ERR_ALERT | ERR_FATAL;
894 goto out;
895 }
896
897 out:
898 return err_code;
899}
900
Willy Tarreau8fed9032014-07-03 17:02:46 +0200901/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200902 * Note that the sample *is* modified and that the returned key may point
903 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200904 * Returns NULL if the sample could not be converted (eg: no matching type),
905 * otherwise a pointer to the static stktable_key filled with what is needed
906 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200907 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200908struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200909{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200910 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200911 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200912 return NULL;
913
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200914 /* Fill static_table_key. */
915 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200916
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200917 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200918 static_table_key.key = &smp->data.u.ipv4;
919 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200920 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200921
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200922 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200923 static_table_key.key = &smp->data.u.ipv6;
924 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200925 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200926
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200927 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200928 /* The stick table require a 32bit unsigned int, "sint" is a
929 * signed 64 it, so we can convert it inplace.
930 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200931 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200932 static_table_key.key = &smp->data.u.sint;
933 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200934 break;
935
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200936 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200937 if (!smp_make_safe(smp))
938 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200939 static_table_key.key = smp->data.u.str.area;
940 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200941 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200942
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200943 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200944 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200945 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200946 if (!smp_make_rw(smp))
947 return NULL;
948
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200949 if (smp->data.u.str.size < t->key_size)
950 if (!smp_dup(smp))
951 return NULL;
952 if (smp->data.u.str.size < t->key_size)
953 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200954 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
955 t->key_size - smp->data.u.str.data);
956 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200957 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200958 static_table_key.key = smp->data.u.str.area;
959 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200960 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200961
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200962 default: /* impossible case. */
963 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200964 }
965
Christopher Fauletca20d022017-08-29 15:30:31 +0200966 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200967}
968
969/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200970 * Process a fetch + format conversion as defined by the sample expression <expr>
971 * on request or response considering the <opt> parameter. Returns either NULL if
972 * no key could be extracted, or a pointer to the converted result stored in
973 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
974 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200975 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
976 * without SMP_OPT_FINAL). The output will be usable like this :
977 *
978 * return MAY_CHANGE FINAL Meaning for the sample
979 * NULL 0 * Not present and will never be (eg: header)
980 * NULL 1 0 Not present or unstable, could change (eg: req_len)
981 * NULL 1 1 Not present, will not change anymore
982 * smp 0 * Present and will not change (eg: header)
983 * smp 1 0 not possible
984 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200985 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200986struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200987 unsigned int opt, struct sample_expr *expr, struct sample *smp)
988{
989 if (smp)
990 memset(smp, 0, sizeof(*smp));
991
Willy Tarreau192252e2015-04-04 01:47:55 +0200992 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200993 if (!smp)
994 return NULL;
995
996 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
997 return NULL; /* we can only use stable samples */
998
999 return smp_to_stkey(smp, t);
1000}
1001
1002/*
Willy Tarreau12785782012-04-27 21:37:17 +02001003 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001004 * type <table_type>, otherwise zero. Used in configuration check.
1005 */
Willy Tarreau12785782012-04-27 21:37:17 +02001006int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001007{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001008 int out_type;
1009
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001010 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001011 return 0;
1012
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001013 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001014
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001015 /* Convert sample. */
1016 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001017 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001018
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001019 return 1;
1020}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001021
Willy Tarreauedee1d62014-07-15 16:44:27 +02001022/* Extra data types processing : after the last one, some room may remain
1023 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1024 * at run time.
1025 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001026struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001027 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001028 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001029 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001030 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001031 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1032 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1033 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1034 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1035 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1036 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1037 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1038 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1039 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1040 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1041 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1042 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1043 [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 +01001044 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1045 [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 +02001046 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001047};
1048
Willy Tarreauedee1d62014-07-15 16:44:27 +02001049/* Registers stick-table extra data type with index <idx>, name <name>, type
1050 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1051 * index is automatically allocated. The allocated index is returned, or -1 if
1052 * no free index was found or <name> was already registered. The <name> is used
1053 * directly as a pointer, so if it's not stable, the caller must allocate it.
1054 */
1055int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1056{
1057 if (idx < 0) {
1058 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1059 if (!stktable_data_types[idx].name)
1060 break;
1061
1062 if (strcmp(stktable_data_types[idx].name, name) == 0)
1063 return -1;
1064 }
1065 }
1066
1067 if (idx >= STKTABLE_DATA_TYPES)
1068 return -1;
1069
1070 if (stktable_data_types[idx].name != NULL)
1071 return -1;
1072
1073 stktable_data_types[idx].name = name;
1074 stktable_data_types[idx].std_type = std_type;
1075 stktable_data_types[idx].arg_type = arg_type;
1076 return idx;
1077}
1078
Willy Tarreau08d5f982010-06-06 13:34:54 +02001079/*
1080 * Returns the data type number for the stktable_data_type whose name is <name>,
1081 * or <0 if not found.
1082 */
1083int stktable_get_data_type(char *name)
1084{
1085 int type;
1086
1087 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001088 if (!stktable_data_types[type].name)
1089 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001090 if (strcmp(name, stktable_data_types[type].name) == 0)
1091 return type;
1092 }
1093 return -1;
1094}
1095
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001096/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1097 * it up into this table. Returns true if found, false otherwise. The input
1098 * type is STR so that input samples are converted to string (since all types
1099 * can be converted to strings), then the function casts the string again into
1100 * the table's type. This is a double conversion, but in the future we might
1101 * support automatic input types to perform the cast on the fly.
1102 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001103static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001104{
1105 struct stktable *t;
1106 struct stktable_key *key;
1107 struct stksess *ts;
1108
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001109 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001110
1111 key = smp_to_stkey(smp, t);
1112 if (!key)
1113 return 0;
1114
1115 ts = stktable_lookup_key(t, key);
1116
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001117 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001118 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001119 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001120 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001121 return 1;
1122}
1123
1124/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1125 * it up into this table. Returns the data rate received from clients in bytes/s
1126 * if the key is present in the table, otherwise zero, so that comparisons can
1127 * be easily performed. If the inspected parameter is not stored in the table,
1128 * <not found> is returned.
1129 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001130static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001131{
1132 struct stktable *t;
1133 struct stktable_key *key;
1134 struct stksess *ts;
1135 void *ptr;
1136
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001137 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001138
1139 key = smp_to_stkey(smp, t);
1140 if (!key)
1141 return 0;
1142
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001143 ts = stktable_lookup_key(t, key);
1144
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001145 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001146 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001147 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001148
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001149 if (!ts) /* key not present */
1150 return 1;
1151
1152 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001153 if (ptr)
1154 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1155 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001156
Daniel Corbett3e60b112018-05-27 09:47:12 -04001157 stktable_release(t, ts);
1158 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001159}
1160
1161/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1162 * it up into this table. Returns the cumulated number of connections for the key
1163 * if the key is present in the table, otherwise zero, so that comparisons can
1164 * be easily performed. If the inspected parameter is not stored in the table,
1165 * <not found> is returned.
1166 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001167static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001168{
1169 struct stktable *t;
1170 struct stktable_key *key;
1171 struct stksess *ts;
1172 void *ptr;
1173
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001174 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001175
1176 key = smp_to_stkey(smp, t);
1177 if (!key)
1178 return 0;
1179
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001180 ts = stktable_lookup_key(t, key);
1181
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001182 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001183 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001184 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001185
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001186 if (!ts) /* key not present */
1187 return 1;
1188
1189 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001190 if (ptr)
1191 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001192
Daniel Corbett3e60b112018-05-27 09:47:12 -04001193 stktable_release(t, ts);
1194 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001195}
1196
1197/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1198 * it up into this table. Returns the number of concurrent connections for the
1199 * key if the key is present in the table, otherwise zero, so that comparisons
1200 * can be easily performed. If the inspected parameter is not stored in the
1201 * table, <not found> is returned.
1202 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001203static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001204{
1205 struct stktable *t;
1206 struct stktable_key *key;
1207 struct stksess *ts;
1208 void *ptr;
1209
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001210 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001211
1212 key = smp_to_stkey(smp, t);
1213 if (!key)
1214 return 0;
1215
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001216 ts = stktable_lookup_key(t, key);
1217
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001218 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001219 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001220 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001221
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001222 if (!ts) /* key not present */
1223 return 1;
1224
1225 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001226 if (ptr)
1227 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001228
Daniel Corbett3e60b112018-05-27 09:47:12 -04001229 stktable_release(t, ts);
1230 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001231}
1232
1233/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1234 * it up into this table. Returns the rate of incoming connections from the key
1235 * if the key is present in the table, otherwise zero, so that comparisons can
1236 * be easily performed. If the inspected parameter is not stored in the table,
1237 * <not found> is returned.
1238 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001239static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001240{
1241 struct stktable *t;
1242 struct stktable_key *key;
1243 struct stksess *ts;
1244 void *ptr;
1245
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001246 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001247
1248 key = smp_to_stkey(smp, t);
1249 if (!key)
1250 return 0;
1251
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001252 ts = stktable_lookup_key(t, key);
1253
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001255 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001256 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001257
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001258 if (!ts) /* key not present */
1259 return 1;
1260
1261 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001262 if (ptr)
1263 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1264 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001265
Daniel Corbett3e60b112018-05-27 09:47:12 -04001266 stktable_release(t, ts);
1267 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001268}
1269
1270/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1271 * it up into this table. Returns the data rate sent to clients in bytes/s
1272 * if the key is present in the table, otherwise zero, so that comparisons can
1273 * be easily performed. If the inspected parameter is not stored in the table,
1274 * <not found> is returned.
1275 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001276static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001277{
1278 struct stktable *t;
1279 struct stktable_key *key;
1280 struct stksess *ts;
1281 void *ptr;
1282
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001283 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001284
1285 key = smp_to_stkey(smp, t);
1286 if (!key)
1287 return 0;
1288
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001289 ts = stktable_lookup_key(t, key);
1290
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001291 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001292 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001293 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001294
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001295 if (!ts) /* key not present */
1296 return 1;
1297
1298 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001299 if (ptr)
1300 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1301 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001302
Daniel Corbett3e60b112018-05-27 09:47:12 -04001303 stktable_release(t, ts);
1304 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001305}
1306
1307/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001308 * it up into this table. Returns the value of the GPT0 tag for the key
1309 * if the key is present in the table, otherwise false, so that comparisons can
1310 * be easily performed. If the inspected parameter is not stored in the table,
1311 * <not found> is returned.
1312 */
1313static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1314{
1315 struct stktable *t;
1316 struct stktable_key *key;
1317 struct stksess *ts;
1318 void *ptr;
1319
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001320 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001321
1322 key = smp_to_stkey(smp, t);
1323 if (!key)
1324 return 0;
1325
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001326 ts = stktable_lookup_key(t, key);
1327
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001328 smp->flags = SMP_F_VOL_TEST;
1329 smp->data.type = SMP_T_SINT;
1330 smp->data.u.sint = 0;
1331
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001332 if (!ts) /* key not present */
1333 return 1;
1334
1335 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001336 if (ptr)
1337 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001338
Daniel Corbett3e60b112018-05-27 09:47:12 -04001339 stktable_release(t, ts);
1340 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001341}
1342
1343/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344 * it up into this table. Returns the value of the GPC0 counter for the key
1345 * if the key is present in the table, otherwise zero, so that comparisons can
1346 * be easily performed. If the inspected parameter is not stored in the table,
1347 * <not found> is returned.
1348 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001349static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350{
1351 struct stktable *t;
1352 struct stktable_key *key;
1353 struct stksess *ts;
1354 void *ptr;
1355
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001356 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357
1358 key = smp_to_stkey(smp, t);
1359 if (!key)
1360 return 0;
1361
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001362 ts = stktable_lookup_key(t, key);
1363
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001364 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001365 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001366 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001367
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001368 if (!ts) /* key not present */
1369 return 1;
1370
1371 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001372 if (ptr)
1373 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001374
Daniel Corbett3e60b112018-05-27 09:47:12 -04001375 stktable_release(t, ts);
1376 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377}
1378
1379/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1380 * it up into this table. Returns the event rate of the GPC0 counter for the key
1381 * if the key is present in the table, otherwise zero, so that comparisons can
1382 * be easily performed. If the inspected parameter is not stored in the table,
1383 * <not found> is returned.
1384 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001385static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386{
1387 struct stktable *t;
1388 struct stktable_key *key;
1389 struct stksess *ts;
1390 void *ptr;
1391
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001392 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393
1394 key = smp_to_stkey(smp, t);
1395 if (!key)
1396 return 0;
1397
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001398 ts = stktable_lookup_key(t, key);
1399
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001401 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001402 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001404 if (!ts) /* key not present */
1405 return 1;
1406
1407 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001408 if (ptr)
1409 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1410 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001411
Daniel Corbett3e60b112018-05-27 09:47:12 -04001412 stktable_release(t, ts);
1413 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001414}
1415
1416/* 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 +01001417 * it up into this table. Returns the value of the GPC1 counter for the key
1418 * if the key is present in the table, otherwise zero, so that comparisons can
1419 * be easily performed. If the inspected parameter is not stored in the table,
1420 * <not found> is returned.
1421 */
1422static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1423{
1424 struct stktable *t;
1425 struct stktable_key *key;
1426 struct stksess *ts;
1427 void *ptr;
1428
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001429 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001430
1431 key = smp_to_stkey(smp, t);
1432 if (!key)
1433 return 0;
1434
1435 ts = stktable_lookup_key(t, key);
1436
1437 smp->flags = SMP_F_VOL_TEST;
1438 smp->data.type = SMP_T_SINT;
1439 smp->data.u.sint = 0;
1440
1441 if (!ts) /* key not present */
1442 return 1;
1443
1444 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001445 if (ptr)
1446 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001447
Daniel Corbett3e60b112018-05-27 09:47:12 -04001448 stktable_release(t, ts);
1449 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001450}
1451
1452/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1453 * it up into this table. Returns the event rate of the GPC1 counter for the key
1454 * if the key is present in the table, otherwise zero, so that comparisons can
1455 * be easily performed. If the inspected parameter is not stored in the table,
1456 * <not found> is returned.
1457 */
1458static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1459{
1460 struct stktable *t;
1461 struct stktable_key *key;
1462 struct stksess *ts;
1463 void *ptr;
1464
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001465 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001466
1467 key = smp_to_stkey(smp, t);
1468 if (!key)
1469 return 0;
1470
1471 ts = stktable_lookup_key(t, key);
1472
1473 smp->flags = SMP_F_VOL_TEST;
1474 smp->data.type = SMP_T_SINT;
1475 smp->data.u.sint = 0;
1476
1477 if (!ts) /* key not present */
1478 return 1;
1479
1480 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001481 if (ptr)
1482 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1483 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001484
Daniel Corbett3e60b112018-05-27 09:47:12 -04001485 stktable_release(t, ts);
1486 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001487}
1488
1489/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001490 * it up into this table. Returns the cumulated number of HTTP request errors
1491 * for the key if the key is present in the table, otherwise zero, so that
1492 * comparisons can be easily performed. If the inspected parameter is not stored
1493 * in the table, <not found> is returned.
1494 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001495static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496{
1497 struct stktable *t;
1498 struct stktable_key *key;
1499 struct stksess *ts;
1500 void *ptr;
1501
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001502 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001503
1504 key = smp_to_stkey(smp, t);
1505 if (!key)
1506 return 0;
1507
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001508 ts = stktable_lookup_key(t, key);
1509
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001510 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001511 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001512 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001513
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001514 if (!ts) /* key not present */
1515 return 1;
1516
1517 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001518 if (ptr)
1519 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001520
Daniel Corbett3e60b112018-05-27 09:47:12 -04001521 stktable_release(t, ts);
1522 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001523}
1524
1525/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1526 * it up into this table. Returns the HTTP request error rate the key
1527 * if the key is present in the table, otherwise zero, so that comparisons can
1528 * be easily performed. If the inspected parameter is not stored in the table,
1529 * <not found> is returned.
1530 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001531static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532{
1533 struct stktable *t;
1534 struct stktable_key *key;
1535 struct stksess *ts;
1536 void *ptr;
1537
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001538 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001539
1540 key = smp_to_stkey(smp, t);
1541 if (!key)
1542 return 0;
1543
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001544 ts = stktable_lookup_key(t, key);
1545
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001546 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001547 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001548 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001549
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001550 if (!ts) /* key not present */
1551 return 1;
1552
1553 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001554 if (ptr)
1555 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1556 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001557
Daniel Corbett3e60b112018-05-27 09:47:12 -04001558 stktable_release(t, ts);
1559 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001560}
1561
1562/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1563 * it up into this table. Returns the cumulated number of HTTP request for the
1564 * key if the key is present in the table, otherwise zero, so that comparisons
1565 * can be easily performed. If the inspected parameter is not stored in the
1566 * table, <not found> is returned.
1567 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001568static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001569{
1570 struct stktable *t;
1571 struct stktable_key *key;
1572 struct stksess *ts;
1573 void *ptr;
1574
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001575 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001576
1577 key = smp_to_stkey(smp, t);
1578 if (!key)
1579 return 0;
1580
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001581 ts = stktable_lookup_key(t, key);
1582
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001583 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001584 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001585 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001586
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001587 if (!ts) /* key not present */
1588 return 1;
1589
1590 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001591 if (ptr)
1592 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593
Daniel Corbett3e60b112018-05-27 09:47:12 -04001594 stktable_release(t, ts);
1595 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596}
1597
1598/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1599 * it up into this table. Returns the HTTP request rate the key if the key is
1600 * present in the table, otherwise zero, so that comparisons can be easily
1601 * performed. If the inspected parameter is not stored in the table, <not found>
1602 * is returned.
1603 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001604static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001605{
1606 struct stktable *t;
1607 struct stktable_key *key;
1608 struct stksess *ts;
1609 void *ptr;
1610
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001611 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001612
1613 key = smp_to_stkey(smp, t);
1614 if (!key)
1615 return 0;
1616
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001617 ts = stktable_lookup_key(t, key);
1618
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001619 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001620 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001621 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001622
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001623 if (!ts) /* key not present */
1624 return 1;
1625
1626 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001627 if (ptr)
1628 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1629 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001630
Daniel Corbett3e60b112018-05-27 09:47:12 -04001631 stktable_release(t, ts);
1632 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001633}
1634
1635/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1636 * it up into this table. Returns the volume of datareceived from clients in kbytes
1637 * if the key is present in the table, otherwise zero, so that comparisons can
1638 * be easily performed. If the inspected parameter is not stored in the table,
1639 * <not found> is returned.
1640 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001641static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001642{
1643 struct stktable *t;
1644 struct stktable_key *key;
1645 struct stksess *ts;
1646 void *ptr;
1647
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001648 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001649
1650 key = smp_to_stkey(smp, t);
1651 if (!key)
1652 return 0;
1653
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001654 ts = stktable_lookup_key(t, key);
1655
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001656 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001657 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001658 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001659
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001660 if (!ts) /* key not present */
1661 return 1;
1662
1663 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001664 if (ptr)
1665 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001666
Daniel Corbett3e60b112018-05-27 09:47:12 -04001667 stktable_release(t, ts);
1668 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001669}
1670
1671/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1672 * it up into this table. Returns the volume of data sent to clients in kbytes
1673 * if the key is present in the table, otherwise zero, so that comparisons can
1674 * be easily performed. If the inspected parameter is not stored in the table,
1675 * <not found> is returned.
1676 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001677static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001678{
1679 struct stktable *t;
1680 struct stktable_key *key;
1681 struct stksess *ts;
1682 void *ptr;
1683
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001684 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001685
1686 key = smp_to_stkey(smp, t);
1687 if (!key)
1688 return 0;
1689
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001690 ts = stktable_lookup_key(t, key);
1691
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001692 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001693 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001694 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001695
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001696 if (!ts) /* key not present */
1697 return 1;
1698
1699 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001700 if (ptr)
1701 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001702
Daniel Corbett3e60b112018-05-27 09:47:12 -04001703 stktable_release(t, ts);
1704 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001705}
1706
1707/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1708 * it up into this table. Returns the server ID associated with the key if the
1709 * key is present in the table, otherwise zero, so that comparisons can be
1710 * easily performed. If the inspected parameter is not stored in the table,
1711 * <not found> is returned.
1712 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001713static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001714{
1715 struct stktable *t;
1716 struct stktable_key *key;
1717 struct stksess *ts;
1718 void *ptr;
1719
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001720 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001721
1722 key = smp_to_stkey(smp, t);
1723 if (!key)
1724 return 0;
1725
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001726 ts = stktable_lookup_key(t, key);
1727
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001728 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001729 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001730 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001731
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001732 if (!ts) /* key not present */
1733 return 1;
1734
1735 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001736 if (ptr)
1737 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001738
Daniel Corbett3e60b112018-05-27 09:47:12 -04001739 stktable_release(t, ts);
1740 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001741}
1742
1743/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1744 * it up into this table. Returns the cumulated number of sessions for the
1745 * key if the key is present in the table, otherwise zero, so that comparisons
1746 * can be easily performed. If the inspected parameter is not stored in the
1747 * table, <not found> is returned.
1748 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001749static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001750{
1751 struct stktable *t;
1752 struct stktable_key *key;
1753 struct stksess *ts;
1754 void *ptr;
1755
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001756 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001757
1758 key = smp_to_stkey(smp, t);
1759 if (!key)
1760 return 0;
1761
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001762 ts = stktable_lookup_key(t, key);
1763
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001764 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001765 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001766 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001767
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001768 if (!ts) /* key not present */
1769 return 1;
1770
1771 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001772 if (ptr)
1773 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001774
Daniel Corbett3e60b112018-05-27 09:47:12 -04001775 stktable_release(t, ts);
1776 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001777}
1778
1779/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1780 * it up into this table. Returns the session rate the key if the key is
1781 * present in the table, otherwise zero, so that comparisons can be easily
1782 * performed. If the inspected parameter is not stored in the table, <not found>
1783 * is returned.
1784 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001785static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001786{
1787 struct stktable *t;
1788 struct stktable_key *key;
1789 struct stksess *ts;
1790 void *ptr;
1791
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001792 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001793
1794 key = smp_to_stkey(smp, t);
1795 if (!key)
1796 return 0;
1797
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001798 ts = stktable_lookup_key(t, key);
1799
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001801 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001802 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001803
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001804 if (!ts) /* key not present */
1805 return 1;
1806
1807 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001808 if (ptr)
1809 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1810 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001811
Daniel Corbett3e60b112018-05-27 09:47:12 -04001812 stktable_release(t, ts);
1813 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001814}
1815
1816/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1817 * it up into this table. Returns the amount of concurrent connections tracking
1818 * the same key if the key is present in the table, otherwise zero, so that
1819 * comparisons can be easily performed. If the inspected parameter is not
1820 * stored in the table, <not found> is returned.
1821 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001822static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001823{
1824 struct stktable *t;
1825 struct stktable_key *key;
1826 struct stksess *ts;
1827
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001828 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001829
1830 key = smp_to_stkey(smp, t);
1831 if (!key)
1832 return 0;
1833
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001834 ts = stktable_lookup_key(t, key);
1835
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001836 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001837 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001838 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001839
Tim Duesterhus65189c12018-06-26 15:57:29 +02001840 if (!ts)
1841 return 1;
1842
1843 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001844
Daniel Corbett3e60b112018-05-27 09:47:12 -04001845 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001846 return 1;
1847}
1848
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001849/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001850static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001851 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001852{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001853 struct stksess *ts;
1854 struct stkctr *stkctr;
1855
1856 /* Extract the stksess, return OK if no stksess available. */
1857 if (s)
1858 stkctr = &s->stkctr[rule->arg.gpc.sc];
1859 else
1860 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001861
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001862 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001863 if (ts) {
1864 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001865
Willy Tarreau79c1e912016-01-25 14:54:45 +01001866 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1867 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001868 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1869 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001870 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001871
1872 if (ptr1)
1873 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001874 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001875
Emeric Brun819fc6f2017-06-13 19:37:32 +02001876 if (ptr2)
1877 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001878
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001879 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001880
1881 /* If data was modified, we need to touch to re-schedule sync */
1882 stktable_touch_local(stkctr->table, ts, 0);
1883 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001884 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001885 return ACT_RET_CONT;
1886}
1887
1888/* This function is a common parser for using variables. It understands
1889 * the formats:
1890 *
1891 * sc-inc-gpc0(<stick-table ID>)
1892 *
1893 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1894 * it returns 1 and the variable <expr> is filled with the pointer to the
1895 * expression to execute.
1896 */
1897static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1898 struct act_rule *rule, char **err)
1899{
1900 const char *cmd_name = args[*arg-1];
1901 char *error;
1902
1903 cmd_name += strlen("sc-inc-gpc0");
1904 if (*cmd_name == '\0') {
1905 /* default stick table id. */
1906 rule->arg.gpc.sc = 0;
1907 } else {
1908 /* parse the stick table id. */
1909 if (*cmd_name != '(') {
1910 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1911 return ACT_RET_PRS_ERR;
1912 }
1913 cmd_name++; /* jump the '(' */
1914 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1915 if (*error != ')') {
1916 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1917 return ACT_RET_PRS_ERR;
1918 }
1919
Christopher Faulet28436e22019-12-18 10:25:46 +01001920 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001921 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001922 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001923 return ACT_RET_PRS_ERR;
1924 }
1925 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001926 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001927 rule->action_ptr = action_inc_gpc0;
1928 return ACT_RET_PRS_OK;
1929}
1930
1931/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001932static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1933 struct session *sess, struct stream *s, int flags)
1934{
1935 struct stksess *ts;
1936 struct stkctr *stkctr;
1937
1938 /* Extract the stksess, return OK if no stksess available. */
1939 if (s)
1940 stkctr = &s->stkctr[rule->arg.gpc.sc];
1941 else
1942 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1943
1944 ts = stkctr_entry(stkctr);
1945 if (ts) {
1946 void *ptr1, *ptr2;
1947
1948 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1949 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1950 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1951 if (ptr1 || ptr2) {
1952 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1953
1954 if (ptr1)
1955 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1956 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1957
1958 if (ptr2)
1959 stktable_data_cast(ptr2, gpc1)++;
1960
1961 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1962
1963 /* If data was modified, we need to touch to re-schedule sync */
1964 stktable_touch_local(stkctr->table, ts, 0);
1965 }
1966 }
1967 return ACT_RET_CONT;
1968}
1969
1970/* This function is a common parser for using variables. It understands
1971 * the formats:
1972 *
1973 * sc-inc-gpc1(<stick-table ID>)
1974 *
1975 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1976 * it returns 1 and the variable <expr> is filled with the pointer to the
1977 * expression to execute.
1978 */
1979static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1980 struct act_rule *rule, char **err)
1981{
1982 const char *cmd_name = args[*arg-1];
1983 char *error;
1984
1985 cmd_name += strlen("sc-inc-gpc1");
1986 if (*cmd_name == '\0') {
1987 /* default stick table id. */
1988 rule->arg.gpc.sc = 0;
1989 } else {
1990 /* parse the stick table id. */
1991 if (*cmd_name != '(') {
1992 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1993 return ACT_RET_PRS_ERR;
1994 }
1995 cmd_name++; /* jump the '(' */
1996 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1997 if (*error != ')') {
1998 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1999 return ACT_RET_PRS_ERR;
2000 }
2001
Christopher Faulet28436e22019-12-18 10:25:46 +01002002 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002003 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002004 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002005 return ACT_RET_PRS_ERR;
2006 }
2007 }
2008 rule->action = ACT_CUSTOM;
2009 rule->action_ptr = action_inc_gpc1;
2010 return ACT_RET_PRS_OK;
2011}
2012
2013/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002014static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002015 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002016{
2017 void *ptr;
2018 struct stksess *ts;
2019 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002020 unsigned int value = 0;
2021 struct sample *smp;
2022 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002023
2024 /* Extract the stksess, return OK if no stksess available. */
2025 if (s)
2026 stkctr = &s->stkctr[rule->arg.gpt.sc];
2027 else
2028 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002029
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002030 ts = stkctr_entry(stkctr);
2031 if (!ts)
2032 return ACT_RET_CONT;
2033
2034 /* Store the sample in the required sc, and ignore errors. */
2035 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002036 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002037 if (!rule->arg.gpt.expr)
2038 value = (unsigned int)(rule->arg.gpt.value);
2039 else {
2040 switch (rule->from) {
2041 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2042 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2043 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2044 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2045 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2046 default:
2047 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2048 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2049 ha_alert("stick table: internal error while executing setting gpt0.\n");
2050 return ACT_RET_CONT;
2051 }
2052
2053 /* Fetch and cast the expression. */
2054 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2055 if (!smp) {
2056 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2057 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2058 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2059 return ACT_RET_CONT;
2060 }
2061 value = (unsigned int)(smp->data.u.sint);
2062 }
2063
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002064 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002065
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002066 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002067
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002068 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002069
2070 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002071 }
2072
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002073 return ACT_RET_CONT;
2074}
2075
2076/* This function is a common parser for using variables. It understands
2077 * the format:
2078 *
2079 * set-gpt0(<stick-table ID>) <expression>
2080 *
2081 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2082 * it returns 1 and the variable <expr> is filled with the pointer to the
2083 * expression to execute.
2084 */
2085static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2086 struct act_rule *rule, char **err)
2087
2088
2089{
2090 const char *cmd_name = args[*arg-1];
2091 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002092 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002093
2094 cmd_name += strlen("sc-set-gpt0");
2095 if (*cmd_name == '\0') {
2096 /* default stick table id. */
2097 rule->arg.gpt.sc = 0;
2098 } else {
2099 /* parse the stick table id. */
2100 if (*cmd_name != '(') {
2101 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2102 return ACT_RET_PRS_ERR;
2103 }
2104 cmd_name++; /* jump the '(' */
2105 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2106 if (*error != ')') {
2107 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2108 return ACT_RET_PRS_ERR;
2109 }
2110
Christopher Faulet28436e22019-12-18 10:25:46 +01002111 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002112 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002113 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002114 return ACT_RET_PRS_ERR;
2115 }
2116 }
2117
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002118 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002119 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2120 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002121 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002122 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002123 if (!rule->arg.gpt.expr)
2124 return ACT_RET_PRS_ERR;
2125
2126 switch (rule->from) {
2127 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2128 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2129 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2130 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2131 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2132 default:
2133 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2134 return ACT_RET_PRS_ERR;
2135 }
2136 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2137 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2138 sample_src_names(rule->arg.gpt.expr->fetch->use));
2139 free(rule->arg.gpt.expr);
2140 return ACT_RET_PRS_ERR;
2141 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002142 }
2143 (*arg)++;
2144
Thierry FOURNIER42148732015-09-02 17:17:33 +02002145 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002146 rule->action_ptr = action_set_gpt0;
2147
2148 return ACT_RET_PRS_OK;
2149}
2150
Willy Tarreau7d562212016-11-25 16:10:05 +01002151/* set temp integer to the number of used entries in the table pointed to by expr.
2152 * Accepts exactly 1 argument of type table.
2153 */
2154static int
2155smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2156{
2157 smp->flags = SMP_F_VOL_TEST;
2158 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002159 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002160 return 1;
2161}
2162
2163/* set temp integer to the number of free entries in the table pointed to by expr.
2164 * Accepts exactly 1 argument of type table.
2165 */
2166static int
2167smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2168{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002169 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002170
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002171 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002172 smp->flags = SMP_F_VOL_TEST;
2173 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002174 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002175 return 1;
2176}
2177
2178/* Returns a pointer to a stkctr depending on the fetch keyword name.
2179 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2180 * sc[0-9]_* will return a pointer to the respective field in the
2181 * stream <l4>. sc_* requires an UINT argument specifying the stick
2182 * counter number. src_* will fill a locally allocated structure with
2183 * the table and entry corresponding to what is specified with src_*.
2184 * NULL may be returned if the designated stkctr is not tracked. For
2185 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2186 * passed. When present, the currently tracked key is then looked up
2187 * in the specified table instead of the current table. The purpose is
2188 * to be able to convery multiple values per key (eg: have gpc0 from
2189 * multiple tables). <strm> is allowed to be NULL, in which case only
2190 * the session will be consulted.
2191 */
2192struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002193smp_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 +01002194{
Willy Tarreau7d562212016-11-25 16:10:05 +01002195 struct stkctr *stkptr;
2196 struct stksess *stksess;
2197 unsigned int num = kw[2] - '0';
2198 int arg = 0;
2199
2200 if (num == '_' - '0') {
2201 /* sc_* variant, args[0] = ctr# (mandatory) */
2202 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002203 }
2204 else if (num > 9) { /* src_* variant, args[0] = table */
2205 struct stktable_key *key;
2206 struct connection *conn = objt_conn(sess->origin);
2207 struct sample smp;
2208
2209 if (!conn)
2210 return NULL;
2211
Joseph Herlant5662fa42018-11-15 13:43:28 -08002212 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002213 smp.px = NULL;
2214 smp.sess = sess;
2215 smp.strm = strm;
2216 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2217 return NULL;
2218
2219 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002220 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002221 if (!key)
2222 return NULL;
2223
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002224 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002225 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2226 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002227 }
2228
2229 /* Here, <num> contains the counter number from 0 to 9 for
2230 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2231 * args[arg] is the first optional argument. We first lookup the
2232 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002233 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002234 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002235 if (num >= MAX_SESS_STKCTR)
2236 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002237
2238 if (strm)
2239 stkptr = &strm->stkctr[num];
2240 if (!strm || !stkctr_entry(stkptr)) {
2241 stkptr = &sess->stkctr[num];
2242 if (!stkctr_entry(stkptr))
2243 return NULL;
2244 }
2245
2246 stksess = stkctr_entry(stkptr);
2247 if (!stksess)
2248 return NULL;
2249
2250 if (unlikely(args[arg].type == ARGT_TAB)) {
2251 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002252 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002253 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2254 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002255 }
2256 return stkptr;
2257}
2258
2259/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2260 * the entry if it doesn't exist yet. This is needed for a few fetch
2261 * functions which need to create an entry, such as src_inc_gpc* and
2262 * src_clr_gpc*.
2263 */
2264struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002265smp_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 +01002266{
Willy Tarreau7d562212016-11-25 16:10:05 +01002267 struct stktable_key *key;
2268 struct connection *conn = objt_conn(sess->origin);
2269 struct sample smp;
2270
2271 if (strncmp(kw, "src_", 4) != 0)
2272 return NULL;
2273
2274 if (!conn)
2275 return NULL;
2276
Joseph Herlant5662fa42018-11-15 13:43:28 -08002277 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002278 smp.px = NULL;
2279 smp.sess = sess;
2280 smp.strm = strm;
2281 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2282 return NULL;
2283
2284 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002285 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002286 if (!key)
2287 return NULL;
2288
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002289 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002290 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2291 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002292}
2293
2294/* set return a boolean indicating if the requested stream counter is
2295 * currently being tracked or not.
2296 * Supports being called as "sc[0-9]_tracked" only.
2297 */
2298static int
2299smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2300{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002301 struct stkctr tmpstkctr;
2302 struct stkctr *stkctr;
2303
Willy Tarreau7d562212016-11-25 16:10:05 +01002304 smp->flags = SMP_F_VOL_TEST;
2305 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002306 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2307 smp->data.u.sint = !!stkctr;
2308
2309 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002310 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002311 stktable_release(stkctr->table, stkctr_entry(stkctr));
2312
Willy Tarreau7d562212016-11-25 16:10:05 +01002313 return 1;
2314}
2315
2316/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2317 * frontend counters or from the src.
2318 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2319 * zero is returned if the key is new.
2320 */
2321static int
2322smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2323{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002324 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002325 struct stkctr *stkctr;
2326
Emeric Brun819fc6f2017-06-13 19:37:32 +02002327 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002328 if (!stkctr)
2329 return 0;
2330
2331 smp->flags = SMP_F_VOL_TEST;
2332 smp->data.type = SMP_T_SINT;
2333 smp->data.u.sint = 0;
2334
Emeric Brun819fc6f2017-06-13 19:37:32 +02002335 if (stkctr_entry(stkctr)) {
2336 void *ptr;
2337
2338 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2339 if (!ptr) {
2340 if (stkctr == &tmpstkctr)
2341 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002342 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002343 }
2344
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002345 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002346
Willy Tarreau7d562212016-11-25 16:10:05 +01002347 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002348
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002349 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002350
2351 if (stkctr == &tmpstkctr)
2352 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002353 }
2354 return 1;
2355}
2356
2357/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2358 * frontend counters or from the src.
2359 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2360 * zero is returned if the key is new.
2361 */
2362static int
2363smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2364{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002365 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002366 struct stkctr *stkctr;
2367
Emeric Brun819fc6f2017-06-13 19:37:32 +02002368 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002369 if (!stkctr)
2370 return 0;
2371
2372 smp->flags = SMP_F_VOL_TEST;
2373 smp->data.type = SMP_T_SINT;
2374 smp->data.u.sint = 0;
2375
2376 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002377 void *ptr;
2378
2379 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2380 if (!ptr) {
2381 if (stkctr == &tmpstkctr)
2382 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002383 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002384 }
2385
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002386 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002387
Willy Tarreau7d562212016-11-25 16:10:05 +01002388 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002389
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002390 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002391
2392 if (stkctr == &tmpstkctr)
2393 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002394 }
2395 return 1;
2396}
2397
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002398/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2399 * frontend counters or from the src.
2400 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2401 * zero is returned if the key is new.
2402 */
2403static int
2404smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2405{
2406 struct stkctr tmpstkctr;
2407 struct stkctr *stkctr;
2408
2409 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2410 if (!stkctr)
2411 return 0;
2412
2413 smp->flags = SMP_F_VOL_TEST;
2414 smp->data.type = SMP_T_SINT;
2415 smp->data.u.sint = 0;
2416
2417 if (stkctr_entry(stkctr) != NULL) {
2418 void *ptr;
2419
2420 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2421 if (!ptr) {
2422 if (stkctr == &tmpstkctr)
2423 stktable_release(stkctr->table, stkctr_entry(stkctr));
2424 return 0; /* parameter not stored */
2425 }
2426
2427 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2428
2429 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2430
2431 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2432
2433 if (stkctr == &tmpstkctr)
2434 stktable_release(stkctr->table, stkctr_entry(stkctr));
2435 }
2436 return 1;
2437}
2438
Willy Tarreau7d562212016-11-25 16:10:05 +01002439/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2440 * tracked frontend counters or from the src.
2441 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2442 * Value zero is returned if the key is new.
2443 */
2444static int
2445smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2446{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002447 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002448 struct stkctr *stkctr;
2449
Emeric Brun819fc6f2017-06-13 19:37:32 +02002450 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002451 if (!stkctr)
2452 return 0;
2453
2454 smp->flags = SMP_F_VOL_TEST;
2455 smp->data.type = SMP_T_SINT;
2456 smp->data.u.sint = 0;
2457 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002458 void *ptr;
2459
2460 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2461 if (!ptr) {
2462 if (stkctr == &tmpstkctr)
2463 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002464 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002465 }
2466
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002467 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002468
Willy Tarreau7d562212016-11-25 16:10:05 +01002469 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2470 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002471
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002472 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002473
2474 if (stkctr == &tmpstkctr)
2475 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002476 }
2477 return 1;
2478}
2479
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002480/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2481 * tracked frontend counters or from the src.
2482 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2483 * Value zero is returned if the key is new.
2484 */
2485static int
2486smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2487{
2488 struct stkctr tmpstkctr;
2489 struct stkctr *stkctr;
2490
2491 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2492 if (!stkctr)
2493 return 0;
2494
2495 smp->flags = SMP_F_VOL_TEST;
2496 smp->data.type = SMP_T_SINT;
2497 smp->data.u.sint = 0;
2498 if (stkctr_entry(stkctr) != NULL) {
2499 void *ptr;
2500
2501 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2502 if (!ptr) {
2503 if (stkctr == &tmpstkctr)
2504 stktable_release(stkctr->table, stkctr_entry(stkctr));
2505 return 0; /* parameter not stored */
2506 }
2507
2508 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2509
2510 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2511 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2512
2513 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2514
2515 if (stkctr == &tmpstkctr)
2516 stktable_release(stkctr->table, stkctr_entry(stkctr));
2517 }
2518 return 1;
2519}
2520
Willy Tarreau7d562212016-11-25 16:10:05 +01002521/* Increment the General Purpose Counter 0 value from the stream's tracked
2522 * frontend counters and return it into temp integer.
2523 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2524 */
2525static int
2526smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2527{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002528 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002529 struct stkctr *stkctr;
2530
Emeric Brun819fc6f2017-06-13 19:37:32 +02002531 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002532 if (!stkctr)
2533 return 0;
2534
2535 smp->flags = SMP_F_VOL_TEST;
2536 smp->data.type = SMP_T_SINT;
2537 smp->data.u.sint = 0;
2538
Emeric Brun819fc6f2017-06-13 19:37:32 +02002539 if (!stkctr_entry(stkctr))
2540 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002541
2542 if (stkctr && stkctr_entry(stkctr)) {
2543 void *ptr1,*ptr2;
2544
Emeric Brun819fc6f2017-06-13 19:37:32 +02002545
Willy Tarreau7d562212016-11-25 16:10:05 +01002546 /* First, update gpc0_rate if it's tracked. Second, update its
2547 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2548 */
2549 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002550 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002551 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002552 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002553
Emeric Brun819fc6f2017-06-13 19:37:32 +02002554 if (ptr1) {
2555 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2556 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2557 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2558 }
2559
2560 if (ptr2)
2561 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2562
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002563 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002564
2565 /* If data was modified, we need to touch to re-schedule sync */
2566 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2567 }
2568 else if (stkctr == &tmpstkctr)
2569 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002570 }
2571 return 1;
2572}
2573
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002574/* Increment the General Purpose Counter 1 value from the stream's tracked
2575 * frontend counters and return it into temp integer.
2576 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2577 */
2578static int
2579smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2580{
2581 struct stkctr tmpstkctr;
2582 struct stkctr *stkctr;
2583
2584 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2585 if (!stkctr)
2586 return 0;
2587
2588 smp->flags = SMP_F_VOL_TEST;
2589 smp->data.type = SMP_T_SINT;
2590 smp->data.u.sint = 0;
2591
2592 if (!stkctr_entry(stkctr))
2593 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2594
2595 if (stkctr && stkctr_entry(stkctr)) {
2596 void *ptr1,*ptr2;
2597
2598
2599 /* First, update gpc1_rate if it's tracked. Second, update its
2600 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2601 */
2602 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2603 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2604 if (ptr1 || ptr2) {
2605 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2606
2607 if (ptr1) {
2608 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2609 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2610 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2611 }
2612
2613 if (ptr2)
2614 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2615
2616 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2617
2618 /* If data was modified, we need to touch to re-schedule sync */
2619 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2620 }
2621 else if (stkctr == &tmpstkctr)
2622 stktable_release(stkctr->table, stkctr_entry(stkctr));
2623 }
2624 return 1;
2625}
2626
Willy Tarreau7d562212016-11-25 16:10:05 +01002627/* Clear the General Purpose Counter 0 value from the stream's tracked
2628 * frontend counters and return its previous value into temp integer.
2629 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2630 */
2631static int
2632smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2633{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002634 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002635 struct stkctr *stkctr;
2636
Emeric Brun819fc6f2017-06-13 19:37:32 +02002637 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002638 if (!stkctr)
2639 return 0;
2640
2641 smp->flags = SMP_F_VOL_TEST;
2642 smp->data.type = SMP_T_SINT;
2643 smp->data.u.sint = 0;
2644
Emeric Brun819fc6f2017-06-13 19:37:32 +02002645 if (!stkctr_entry(stkctr))
2646 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002647
Emeric Brun819fc6f2017-06-13 19:37:32 +02002648 if (stkctr && stkctr_entry(stkctr)) {
2649 void *ptr;
2650
2651 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2652 if (!ptr) {
2653 if (stkctr == &tmpstkctr)
2654 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002655 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002656 }
2657
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002658 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002659
Willy Tarreau7d562212016-11-25 16:10:05 +01002660 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2661 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002663 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002664
Willy Tarreau7d562212016-11-25 16:10:05 +01002665 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002666 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002667 }
2668 return 1;
2669}
2670
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002671/* Clear the General Purpose Counter 1 value from the stream's tracked
2672 * frontend counters and return its previous value into temp integer.
2673 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2674 */
2675static int
2676smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2677{
2678 struct stkctr tmpstkctr;
2679 struct stkctr *stkctr;
2680
2681 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2682 if (!stkctr)
2683 return 0;
2684
2685 smp->flags = SMP_F_VOL_TEST;
2686 smp->data.type = SMP_T_SINT;
2687 smp->data.u.sint = 0;
2688
2689 if (!stkctr_entry(stkctr))
2690 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2691
2692 if (stkctr && stkctr_entry(stkctr)) {
2693 void *ptr;
2694
2695 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2696 if (!ptr) {
2697 if (stkctr == &tmpstkctr)
2698 stktable_release(stkctr->table, stkctr_entry(stkctr));
2699 return 0; /* parameter not stored */
2700 }
2701
2702 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2703
2704 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2705 stktable_data_cast(ptr, gpc1) = 0;
2706
2707 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2708
2709 /* If data was modified, we need to touch to re-schedule sync */
2710 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2711 }
2712 return 1;
2713}
2714
Willy Tarreau7d562212016-11-25 16:10:05 +01002715/* set <smp> to the cumulated number of connections from the stream's tracked
2716 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2717 * "src_conn_cnt" only.
2718 */
2719static int
2720smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2721{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002722 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002723 struct stkctr *stkctr;
2724
Emeric Brun819fc6f2017-06-13 19:37:32 +02002725 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002726 if (!stkctr)
2727 return 0;
2728
2729 smp->flags = SMP_F_VOL_TEST;
2730 smp->data.type = SMP_T_SINT;
2731 smp->data.u.sint = 0;
2732 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002733 void *ptr;
2734
2735 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2736 if (!ptr) {
2737 if (stkctr == &tmpstkctr)
2738 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002739 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002740 }
2741
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002742 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002743
Willy Tarreau7d562212016-11-25 16:10:05 +01002744 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002745
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002746 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002747
2748 if (stkctr == &tmpstkctr)
2749 stktable_release(stkctr->table, stkctr_entry(stkctr));
2750
2751
Willy Tarreau7d562212016-11-25 16:10:05 +01002752 }
2753 return 1;
2754}
2755
2756/* set <smp> to the connection rate from the stream's tracked frontend
2757 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2758 * only.
2759 */
2760static int
2761smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2762{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002763 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002764 struct stkctr *stkctr;
2765
Emeric Brun819fc6f2017-06-13 19:37:32 +02002766 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002767 if (!stkctr)
2768 return 0;
2769
2770 smp->flags = SMP_F_VOL_TEST;
2771 smp->data.type = SMP_T_SINT;
2772 smp->data.u.sint = 0;
2773 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002774 void *ptr;
2775
2776 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2777 if (!ptr) {
2778 if (stkctr == &tmpstkctr)
2779 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002780 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002781 }
2782
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002783 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002784
Willy Tarreau7d562212016-11-25 16:10:05 +01002785 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2786 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002787
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002788 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002789
2790 if (stkctr == &tmpstkctr)
2791 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002792 }
2793 return 1;
2794}
2795
2796/* set temp integer to the number of connections from the stream's source address
2797 * in the table pointed to by expr, after updating it.
2798 * Accepts exactly 1 argument of type table.
2799 */
2800static int
2801smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2802{
2803 struct connection *conn = objt_conn(smp->sess->origin);
2804 struct stksess *ts;
2805 struct stktable_key *key;
2806 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002807 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002808
2809 if (!conn)
2810 return 0;
2811
Joseph Herlant5662fa42018-11-15 13:43:28 -08002812 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002813 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2814 return 0;
2815
2816 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002817 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002818 if (!key)
2819 return 0;
2820
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002821 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002822
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002823 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002824 /* entry does not exist and could not be created */
2825 return 0;
2826
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002827 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002828 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002829 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002830 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002831
2832 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002834 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835
Willy Tarreau7d562212016-11-25 16:10:05 +01002836 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002837
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002838 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002839
Willy Tarreau7d562212016-11-25 16:10:05 +01002840 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002841
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002842 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002843
2844 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002845 return 1;
2846}
2847
2848/* set <smp> to the number of concurrent connections from the stream's tracked
2849 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2850 * "src_conn_cur" only.
2851 */
2852static int
2853smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2854{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002855 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 struct stkctr *stkctr;
2857
Emeric Brun819fc6f2017-06-13 19:37:32 +02002858 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002859 if (!stkctr)
2860 return 0;
2861
2862 smp->flags = SMP_F_VOL_TEST;
2863 smp->data.type = SMP_T_SINT;
2864 smp->data.u.sint = 0;
2865 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002866 void *ptr;
2867
2868 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2869 if (!ptr) {
2870 if (stkctr == &tmpstkctr)
2871 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002872 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002873 }
2874
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002875 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002876
Willy Tarreau7d562212016-11-25 16:10:05 +01002877 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002878
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002879 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002880
2881 if (stkctr == &tmpstkctr)
2882 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002883 }
2884 return 1;
2885}
2886
2887/* set <smp> to the cumulated number of streams from the stream's tracked
2888 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2889 * "src_sess_cnt" only.
2890 */
2891static int
2892smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2893{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002894 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 struct stkctr *stkctr;
2896
Emeric Brun819fc6f2017-06-13 19:37:32 +02002897 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002898 if (!stkctr)
2899 return 0;
2900
2901 smp->flags = SMP_F_VOL_TEST;
2902 smp->data.type = SMP_T_SINT;
2903 smp->data.u.sint = 0;
2904 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002905 void *ptr;
2906
2907 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2908 if (!ptr) {
2909 if (stkctr == &tmpstkctr)
2910 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002912 }
2913
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002914 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002915
Willy Tarreau7d562212016-11-25 16:10:05 +01002916 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002917
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002918 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002919
2920 if (stkctr == &tmpstkctr)
2921 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002922 }
2923 return 1;
2924}
2925
2926/* set <smp> to the stream rate from the stream's tracked frontend counters.
2927 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2928 */
2929static int
2930smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2931{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002932 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 struct stkctr *stkctr;
2934
Emeric Brun819fc6f2017-06-13 19:37:32 +02002935 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002936 if (!stkctr)
2937 return 0;
2938
2939 smp->flags = SMP_F_VOL_TEST;
2940 smp->data.type = SMP_T_SINT;
2941 smp->data.u.sint = 0;
2942 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002943 void *ptr;
2944
2945 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2946 if (!ptr) {
2947 if (stkctr == &tmpstkctr)
2948 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002949 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002950 }
2951
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002952 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002953
Willy Tarreau7d562212016-11-25 16:10:05 +01002954 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2955 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002957 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002958
2959 if (stkctr == &tmpstkctr)
2960 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002961 }
2962 return 1;
2963}
2964
2965/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2966 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2967 * "src_http_req_cnt" only.
2968 */
2969static int
2970smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2971{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002972 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002973 struct stkctr *stkctr;
2974
Emeric Brun819fc6f2017-06-13 19:37:32 +02002975 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002976 if (!stkctr)
2977 return 0;
2978
2979 smp->flags = SMP_F_VOL_TEST;
2980 smp->data.type = SMP_T_SINT;
2981 smp->data.u.sint = 0;
2982 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002983 void *ptr;
2984
2985 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2986 if (!ptr) {
2987 if (stkctr == &tmpstkctr)
2988 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002989 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002990 }
2991
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002992 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002993
Willy Tarreau7d562212016-11-25 16:10:05 +01002994 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002996 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002997
2998 if (stkctr == &tmpstkctr)
2999 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003000 }
3001 return 1;
3002}
3003
3004/* set <smp> to the HTTP request rate from the stream's tracked frontend
3005 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3006 * "src_http_req_rate" only.
3007 */
3008static int
3009smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3010{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003011 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003012 struct stkctr *stkctr;
3013
Emeric Brun819fc6f2017-06-13 19:37:32 +02003014 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003015 if (!stkctr)
3016 return 0;
3017
3018 smp->flags = SMP_F_VOL_TEST;
3019 smp->data.type = SMP_T_SINT;
3020 smp->data.u.sint = 0;
3021 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003022 void *ptr;
3023
3024 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3025 if (!ptr) {
3026 if (stkctr == &tmpstkctr)
3027 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003028 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003029 }
3030
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003031 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003032
Willy Tarreau7d562212016-11-25 16:10:05 +01003033 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3034 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003035
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003036 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003037
3038 if (stkctr == &tmpstkctr)
3039 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003040 }
3041 return 1;
3042}
3043
3044/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3045 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3046 * "src_http_err_cnt" only.
3047 */
3048static int
3049smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3050{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003051 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003052 struct stkctr *stkctr;
3053
Emeric Brun819fc6f2017-06-13 19:37:32 +02003054 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003055 if (!stkctr)
3056 return 0;
3057
3058 smp->flags = SMP_F_VOL_TEST;
3059 smp->data.type = SMP_T_SINT;
3060 smp->data.u.sint = 0;
3061 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003062 void *ptr;
3063
3064 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3065 if (!ptr) {
3066 if (stkctr == &tmpstkctr)
3067 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003068 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003069 }
3070
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003071 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003072
Willy Tarreau7d562212016-11-25 16:10:05 +01003073 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003074
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003075 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003076
3077 if (stkctr == &tmpstkctr)
3078 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003079 }
3080 return 1;
3081}
3082
3083/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3084 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3085 * "src_http_err_rate" only.
3086 */
3087static int
3088smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3089{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003090 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003091 struct stkctr *stkctr;
3092
Emeric Brun819fc6f2017-06-13 19:37:32 +02003093 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003094 if (!stkctr)
3095 return 0;
3096
3097 smp->flags = SMP_F_VOL_TEST;
3098 smp->data.type = SMP_T_SINT;
3099 smp->data.u.sint = 0;
3100 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003101 void *ptr;
3102
3103 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3104 if (!ptr) {
3105 if (stkctr == &tmpstkctr)
3106 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003107 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003108 }
3109
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003110 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003111
Willy Tarreau7d562212016-11-25 16:10:05 +01003112 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3113 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003115 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003116
3117 if (stkctr == &tmpstkctr)
3118 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003119 }
3120 return 1;
3121}
3122
3123/* set <smp> to the number of kbytes received from clients, as found in the
3124 * stream's tracked frontend counters. Supports being called as
3125 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3126 */
3127static int
3128smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3129{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003130 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003131 struct stkctr *stkctr;
3132
Emeric Brun819fc6f2017-06-13 19:37:32 +02003133 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003134 if (!stkctr)
3135 return 0;
3136
3137 smp->flags = SMP_F_VOL_TEST;
3138 smp->data.type = SMP_T_SINT;
3139 smp->data.u.sint = 0;
3140 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003141 void *ptr;
3142
3143 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3144 if (!ptr) {
3145 if (stkctr == &tmpstkctr)
3146 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003147 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003148 }
3149
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003150 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003151
Willy Tarreau7d562212016-11-25 16:10:05 +01003152 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003153
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003154 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003155
3156 if (stkctr == &tmpstkctr)
3157 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003158 }
3159 return 1;
3160}
3161
3162/* set <smp> to the data rate received from clients in bytes/s, as found
3163 * in the stream's tracked frontend counters. Supports being called as
3164 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3165 */
3166static int
3167smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3168{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003169 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003170 struct stkctr *stkctr;
3171
Emeric Brun819fc6f2017-06-13 19:37:32 +02003172 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003173 if (!stkctr)
3174 return 0;
3175
3176 smp->flags = SMP_F_VOL_TEST;
3177 smp->data.type = SMP_T_SINT;
3178 smp->data.u.sint = 0;
3179 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003180 void *ptr;
3181
3182 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3183 if (!ptr) {
3184 if (stkctr == &tmpstkctr)
3185 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003186 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003187 }
3188
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003189 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003190
Willy Tarreau7d562212016-11-25 16:10:05 +01003191 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3192 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003193
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003194 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003195
3196 if (stkctr == &tmpstkctr)
3197 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003198 }
3199 return 1;
3200}
3201
3202/* set <smp> to the number of kbytes sent to clients, as found in the
3203 * stream's tracked frontend counters. Supports being called as
3204 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3205 */
3206static int
3207smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3208{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003209 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003210 struct stkctr *stkctr;
3211
Emeric Brun819fc6f2017-06-13 19:37:32 +02003212 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003213 if (!stkctr)
3214 return 0;
3215
3216 smp->flags = SMP_F_VOL_TEST;
3217 smp->data.type = SMP_T_SINT;
3218 smp->data.u.sint = 0;
3219 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003220 void *ptr;
3221
3222 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3223 if (!ptr) {
3224 if (stkctr == &tmpstkctr)
3225 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003226 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227 }
3228
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003229 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230
Willy Tarreau7d562212016-11-25 16:10:05 +01003231 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003232
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003233 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003234
3235 if (stkctr == &tmpstkctr)
3236 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003237 }
3238 return 1;
3239}
3240
3241/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3242 * stream's tracked frontend counters. Supports being called as
3243 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3244 */
3245static int
3246smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3247{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003248 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003249 struct stkctr *stkctr;
3250
Emeric Brun819fc6f2017-06-13 19:37:32 +02003251 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003252 if (!stkctr)
3253 return 0;
3254
3255 smp->flags = SMP_F_VOL_TEST;
3256 smp->data.type = SMP_T_SINT;
3257 smp->data.u.sint = 0;
3258 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003259 void *ptr;
3260
3261 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3262 if (!ptr) {
3263 if (stkctr == &tmpstkctr)
3264 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003265 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003266 }
3267
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003268 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003269
Willy Tarreau7d562212016-11-25 16:10:05 +01003270 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3271 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003272
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003273 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003274
3275 if (stkctr == &tmpstkctr)
3276 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003277 }
3278 return 1;
3279}
3280
3281/* set <smp> to the number of active trackers on the SC entry in the stream's
3282 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3283 */
3284static int
3285smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3286{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003287 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003288 struct stkctr *stkctr;
3289
Emeric Brun819fc6f2017-06-13 19:37:32 +02003290 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003291 if (!stkctr)
3292 return 0;
3293
3294 smp->flags = SMP_F_VOL_TEST;
3295 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003296 if (stkctr == &tmpstkctr) {
3297 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3298 stktable_release(stkctr->table, stkctr_entry(stkctr));
3299 }
3300 else {
3301 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3302 }
3303
Willy Tarreau7d562212016-11-25 16:10:05 +01003304 return 1;
3305}
3306
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003307
3308/* The functions below are used to manipulate table contents from the CLI.
3309 * There are 3 main actions, "clear", "set" and "show". The code is shared
3310 * between all actions, and the action is encoded in the void *private in
3311 * the appctx as well as in the keyword registration, among one of the
3312 * following values.
3313 */
3314
3315enum {
3316 STK_CLI_ACT_CLR,
3317 STK_CLI_ACT_SET,
3318 STK_CLI_ACT_SHOW,
3319};
3320
3321/* Dump the status of a table to a stream interface's
3322 * read buffer. It returns 0 if the output buffer is full
3323 * and needs to be called again, otherwise non-zero.
3324 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003325static int table_dump_head_to_buffer(struct buffer *msg,
3326 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003327 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003328{
3329 struct stream *s = si_strm(si);
3330
3331 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003332 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003333
3334 /* any other information should be dumped here */
3335
William Lallemand07a62f72017-05-24 00:57:40 +02003336 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003337 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3338
Willy Tarreau06d80a92017-10-19 14:32:15 +02003339 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003340 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003341 return 0;
3342 }
3343
3344 return 1;
3345}
3346
3347/* Dump a table entry to a stream interface's
3348 * read buffer. It returns 0 if the output buffer is full
3349 * and needs to be called again, otherwise non-zero.
3350 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003351static int table_dump_entry_to_buffer(struct buffer *msg,
3352 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003353 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003354{
3355 int dt;
3356
3357 chunk_appendf(msg, "%p:", entry);
3358
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003359 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003360 char addr[INET_ADDRSTRLEN];
3361 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3362 chunk_appendf(msg, " key=%s", addr);
3363 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003364 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003365 char addr[INET6_ADDRSTRLEN];
3366 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3367 chunk_appendf(msg, " key=%s", addr);
3368 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003369 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003370 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003371 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003372 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003373 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003374 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003375 }
3376 else {
3377 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003378 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003379 }
3380
3381 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3382
3383 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3384 void *ptr;
3385
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003386 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003387 continue;
3388 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003389 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003390 else
3391 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3392
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003393 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003394 switch (stktable_data_types[dt].std_type) {
3395 case STD_T_SINT:
3396 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3397 break;
3398 case STD_T_UINT:
3399 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3400 break;
3401 case STD_T_ULL:
3402 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3403 break;
3404 case STD_T_FRQP:
3405 chunk_appendf(msg, "%d",
3406 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003407 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003408 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003409 case STD_T_DICT: {
3410 struct dict_entry *de;
3411 de = stktable_data_cast(ptr, std_t_dict);
3412 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3413 break;
3414 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003415 }
3416 }
3417 chunk_appendf(msg, "\n");
3418
Willy Tarreau06d80a92017-10-19 14:32:15 +02003419 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003420 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003421 return 0;
3422 }
3423
3424 return 1;
3425}
3426
3427
3428/* Processes a single table entry matching a specific key passed in argument.
3429 * returns 0 if wants to be called again, 1 if has ended processing.
3430 */
3431static int table_process_entry_per_key(struct appctx *appctx, char **args)
3432{
3433 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003434 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003435 struct stksess *ts;
3436 uint32_t uint32_key;
3437 unsigned char ip6_key[sizeof(struct in6_addr)];
3438 long long value;
3439 int data_type;
3440 int cur_arg;
3441 void *ptr;
3442 struct freq_ctr_period *frqp;
3443
Willy Tarreau9d008692019-08-09 11:21:01 +02003444 if (!*args[4])
3445 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003446
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003447 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003448 case SMP_T_IPV4:
3449 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003450 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003451 break;
3452 case SMP_T_IPV6:
3453 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003454 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003455 break;
3456 case SMP_T_SINT:
3457 {
3458 char *endptr;
3459 unsigned long val;
3460 errno = 0;
3461 val = strtoul(args[4], &endptr, 10);
3462 if ((errno == ERANGE && val == ULONG_MAX) ||
3463 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003464 val > 0xffffffff)
3465 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003466 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003467 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003468 break;
3469 }
3470 break;
3471 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003472 static_table_key.key = args[4];
3473 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003474 break;
3475 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003476 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003477 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003478 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 +01003479 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003480 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 +01003481 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003482 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 +01003483 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003484 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003485 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003486 }
3487
3488 /* check permissions */
3489 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3490 return 1;
3491
Willy Tarreaua24bc782016-12-14 15:50:35 +01003492 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003493 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003494 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003495 if (!ts)
3496 return 1;
3497 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003498 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3499 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003500 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003501 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003502 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003503 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003504 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003505 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003506 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003507 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003508 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003509 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003510 break;
3511
3512 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003513 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003514 if (!ts)
3515 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003516
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003517 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003518 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003519 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003520 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003521 break;
3522
3523 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003524 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003525 if (!ts) {
3526 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003527 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003528 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003529 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003530 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3531 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003532 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003533 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003534 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003535 return 1;
3536 }
3537
3538 data_type = stktable_get_data_type(args[cur_arg] + 5);
3539 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003540 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003541 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003542 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003543 return 1;
3544 }
3545
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003546 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003547 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003548 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003549 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003550 return 1;
3551 }
3552
3553 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003554 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003555 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003556 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003557 return 1;
3558 }
3559
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003560 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003561
3562 switch (stktable_data_types[data_type].std_type) {
3563 case STD_T_SINT:
3564 stktable_data_cast(ptr, std_t_sint) = value;
3565 break;
3566 case STD_T_UINT:
3567 stktable_data_cast(ptr, std_t_uint) = value;
3568 break;
3569 case STD_T_ULL:
3570 stktable_data_cast(ptr, std_t_ull) = value;
3571 break;
3572 case STD_T_FRQP:
3573 /* We set both the current and previous values. That way
3574 * the reported frequency is stable during all the period
3575 * then slowly fades out. This allows external tools to
3576 * push measures without having to update them too often.
3577 */
3578 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003579 /* First bit is reserved for the freq_ctr_period lock
3580 Note: here we're still protected by the stksess lock
3581 so we don't need to update the update the freq_ctr_period
3582 using its internal lock */
3583 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003584 frqp->prev_ctr = 0;
3585 frqp->curr_ctr = value;
3586 break;
3587 }
3588 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003589 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003590 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003591 break;
3592
3593 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003594 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003595 }
3596 return 1;
3597}
3598
3599/* Prepares the appctx fields with the data-based filters from the command line.
3600 * Returns 0 if the dump can proceed, 1 if has ended processing.
3601 */
3602static int table_prepare_data_request(struct appctx *appctx, char **args)
3603{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003604 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003605 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003606
Willy Tarreau9d008692019-08-09 11:21:01 +02003607 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3608 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003609
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003610 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3611 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3612 break;
3613 /* condition on stored data value */
3614 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3615 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003616 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003617
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003618 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003619 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 +01003620
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003621 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003622 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003623 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 +01003624
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003625 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 +01003626 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3627 }
3628
3629 if (*args[3+3*i]) {
3630 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 +01003631 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003632
3633 /* OK we're done, all the fields are set */
3634 return 0;
3635}
3636
3637/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003638static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003639{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003640 int i;
3641
3642 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3643 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003644 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003645 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003646 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003647
3648 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003649 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003650 if (!appctx->ctx.table.target)
3651 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003652 }
3653 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003654 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003655 goto err_args;
3656 return 0;
3657 }
3658
3659 if (strcmp(args[3], "key") == 0)
3660 return table_process_entry_per_key(appctx, args);
3661 else if (strncmp(args[3], "data.", 5) == 0)
3662 return table_prepare_data_request(appctx, args);
3663 else if (*args[3])
3664 goto err_args;
3665
3666 return 0;
3667
3668err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003669 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003670 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003671 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 +01003672 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003673 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 +01003674 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003675 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003676 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003677 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003678 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003679}
3680
3681/* This function is used to deal with table operations (dump or clear depending
3682 * on the action stored in appctx->private). It returns 0 if the output buffer is
3683 * full and it needs to be called again, otherwise non-zero.
3684 */
3685static int cli_io_handler_table(struct appctx *appctx)
3686{
3687 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003688 struct stream *s = si_strm(si);
3689 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003690 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003691 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003692
3693 /*
3694 * We have 3 possible states in appctx->st2 :
3695 * - STAT_ST_INIT : the first call
3696 * - STAT_ST_INFO : the proxy pointer points to the next table to
3697 * dump, the entry pointer is NULL ;
3698 * - STAT_ST_LIST : the proxy pointer points to the current table
3699 * and the entry pointer points to the next entry to be dumped,
3700 * and the refcount on the next entry is held ;
3701 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3702 * data though.
3703 */
3704
3705 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3706 /* in case of abort, remove any refcount we might have set on an entry */
3707 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003708 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003709 }
3710 return 1;
3711 }
3712
3713 chunk_reset(&trash);
3714
3715 while (appctx->st2 != STAT_ST_FIN) {
3716 switch (appctx->st2) {
3717 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003718 appctx->ctx.table.t = appctx->ctx.table.target;
3719 if (!appctx->ctx.table.t)
3720 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003721
3722 appctx->ctx.table.entry = NULL;
3723 appctx->st2 = STAT_ST_INFO;
3724 break;
3725
3726 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003727 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003728 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003729 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003730 appctx->st2 = STAT_ST_END;
3731 break;
3732 }
3733
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003734 if (appctx->ctx.table.t->size) {
3735 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003736 return 0;
3737
3738 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003739 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003740 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003741 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3742 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003743 if (eb) {
3744 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3745 appctx->ctx.table.entry->ref_cnt++;
3746 appctx->st2 = STAT_ST_LIST;
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 break;
3749 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003750 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 }
3752 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003753 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003754 break;
3755
3756 case STAT_ST_LIST:
3757 skip_entry = 0;
3758
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003759 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003760
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003761 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003762 /* we're filtering on some data contents */
3763 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003764 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003765 signed char op;
3766 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003767
Emeric Brun819fc6f2017-06-13 19:37:32 +02003768
Willy Tarreau2b64a352020-01-22 17:09:47 +01003769 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003770 if (appctx->ctx.table.data_type[i] == -1)
3771 break;
3772 dt = appctx->ctx.table.data_type[i];
3773 ptr = stktable_data_ptr(appctx->ctx.table.t,
3774 appctx->ctx.table.entry,
3775 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003776
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003777 data = 0;
3778 switch (stktable_data_types[dt].std_type) {
3779 case STD_T_SINT:
3780 data = stktable_data_cast(ptr, std_t_sint);
3781 break;
3782 case STD_T_UINT:
3783 data = stktable_data_cast(ptr, std_t_uint);
3784 break;
3785 case STD_T_ULL:
3786 data = stktable_data_cast(ptr, std_t_ull);
3787 break;
3788 case STD_T_FRQP:
3789 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3790 appctx->ctx.table.t->data_arg[dt].u);
3791 break;
3792 }
3793
3794 op = appctx->ctx.table.data_op[i];
3795 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003796
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003797 /* skip the entry if the data does not match the test and the value */
3798 if ((data < value &&
3799 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3800 (data == value &&
3801 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3802 (data > value &&
3803 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3804 skip_entry = 1;
3805 break;
3806 }
3807 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003808 }
3809
3810 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003811 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003812 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003813 return 0;
3814 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003815
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003816 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003817
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003818 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003819 appctx->ctx.table.entry->ref_cnt--;
3820
3821 eb = ebmb_next(&appctx->ctx.table.entry->key);
3822 if (eb) {
3823 struct stksess *old = appctx->ctx.table.entry;
3824 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3825 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003826 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003827 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003828 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003829 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003830 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003831 break;
3832 }
3833
3834
3835 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003836 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003837 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003838 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003839
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003840 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003841
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003842 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003843 appctx->st2 = STAT_ST_INFO;
3844 break;
3845
3846 case STAT_ST_END:
3847 appctx->st2 = STAT_ST_FIN;
3848 break;
3849 }
3850 }
3851 return 1;
3852}
3853
3854static void cli_release_show_table(struct appctx *appctx)
3855{
3856 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003857 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003858 }
3859}
3860
3861/* register cli keywords */
3862static struct cli_kw_list cli_kws = {{ },{
3863 { { "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 },
3864 { { "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 },
3865 { { "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 },
3866 {{},}
3867}};
3868
Willy Tarreau0108d902018-11-25 19:14:37 +01003869INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003870
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003871static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003872 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003873 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003874 { "sc-set-gpt0", parse_set_gpt0, 1 },
3875 { /* END */ }
3876}};
3877
Willy Tarreau0108d902018-11-25 19:14:37 +01003878INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3879
Willy Tarreau620408f2016-10-21 16:37:51 +02003880static struct action_kw_list tcp_sess_kws = { { }, {
3881 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003882 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003883 { "sc-set-gpt0", parse_set_gpt0, 1 },
3884 { /* END */ }
3885}};
3886
Willy Tarreau0108d902018-11-25 19:14:37 +01003887INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3888
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003889static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003890 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003891 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003892 { "sc-set-gpt0", parse_set_gpt0, 1 },
3893 { /* END */ }
3894}};
3895
Willy Tarreau0108d902018-11-25 19:14:37 +01003896INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3897
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003898static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003899 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003900 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003901 { "sc-set-gpt0", parse_set_gpt0, 1 },
3902 { /* END */ }
3903}};
3904
Willy Tarreau0108d902018-11-25 19:14:37 +01003905INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3906
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003907static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003908 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003909 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003910 { "sc-set-gpt0", parse_set_gpt0, 1 },
3911 { /* END */ }
3912}};
3913
Willy Tarreau0108d902018-11-25 19:14:37 +01003914INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3915
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003916static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003917 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003918 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003919 { "sc-set-gpt0", parse_set_gpt0, 1 },
3920 { /* END */ }
3921}};
3922
Willy Tarreau0108d902018-11-25 19:14:37 +01003923INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3924
Willy Tarreau7d562212016-11-25 16:10:05 +01003925///* Note: must not be declared <const> as its list will be overwritten.
3926// * Please take care of keeping this list alphabetically sorted.
3927// */
3928//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3929// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3930// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3931// { /* END */ },
3932//}};
3933/* Note: must not be declared <const> as its list will be overwritten.
3934 * Please take care of keeping this list alphabetically sorted.
3935 */
3936static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3937 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3938 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3939 { "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 +01003940 { "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 +01003941 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3942 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3943 { "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 +01003944 { "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 +01003945 { "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 +01003946 { "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 +01003947 { "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 +01003948 { "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 +01003949 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3950 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3951 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3952 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3953 { "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 +01003954 { "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 +01003955 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3956 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3957 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3958 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3959 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3960 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3961 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3962 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3963 { "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 +01003964 { "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 +01003965 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3966 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3967 { "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 +01003968 { "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 +01003969 { "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 +01003970 { "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 +01003971 { "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 +01003972 { "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 +01003973 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3974 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3975 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3976 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3977 { "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 +01003978 { "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 +01003979 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3980 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3981 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3982 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3984 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3985 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3986 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3987 { "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 +01003988 { "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 +01003989 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3990 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3991 { "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 +01003992 { "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 +01003993 { "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 +01003994 { "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 +01003995 { "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 +01003996 { "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 +01003997 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3998 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3999 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4000 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4001 { "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 +01004002 { "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 +01004003 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4004 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4005 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4007 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4008 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4009 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4010 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4011 { "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 +01004012 { "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 +01004013 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4014 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4015 { "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 +01004016 { "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 +01004017 { "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 +01004018 { "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 +01004019 { "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 +01004020 { "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 +01004021 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4022 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4023 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4024 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4025 { "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 +01004026 { "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 +01004027 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4028 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4029 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4030 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4031 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4032 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4033 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4034 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4035 { "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 +01004036 { "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 +01004037 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4038 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4039 { "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 +01004040 { "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 +01004041 { "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 +01004042 { "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 +01004043 { "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 +01004044 { "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 +01004045 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4046 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4047 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4048 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4049 { "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 +01004050 { "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 +01004051 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4052 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4053 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4054 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4055 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4056 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4057 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4058 { /* END */ },
4059}};
4060
Willy Tarreau0108d902018-11-25 19:14:37 +01004061INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004062
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004063/* Note: must not be declared <const> as its list will be overwritten */
4064static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004065 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4066 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4067 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4068 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4069 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4070 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4071 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4072 { "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 +01004073 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004074 { "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 +01004075 { "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 +02004076 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4077 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4078 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4079 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4080 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4081 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4082 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4083 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4084 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4085 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004086 { /* END */ },
4087}};
4088
Willy Tarreau0108d902018-11-25 19:14:37 +01004089INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);