blob: 121ad07c2260c55d52e538f2a95e905871739c67 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020023#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020024#include <haproxy/cli.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020025#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020026#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020027#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020028#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020029#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020030#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020031#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020032#include <haproxy/pool.h>
33#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020034#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020035#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020036#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020038#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020039#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020040#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020041#include <haproxy/tcp_rules.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020042#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020043#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010044
Emeric Brun3bd697e2010-01-04 15:23:48 +010045
Willy Tarreau12785782012-04-27 21:37:17 +020046/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020047static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020048
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010049struct stktable *stktables_list;
50struct eb_root stktable_by_name = EB_ROOT;
51
Olivier Houchard52dabbc2018-11-14 17:54:36 +010052#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010053
54/* This function inserts stktable <t> into the tree of known stick-table.
55 * The stick-table ID is used as the storing key so it must already have
56 * been initialized.
57 */
58void stktable_store_name(struct stktable *t)
59{
60 t->name.key = t->id;
61 ebis_insert(&stktable_by_name, &t->name);
62}
63
64struct stktable *stktable_find_by_name(const char *name)
65{
66 struct ebpt_node *node;
67 struct stktable *t;
68
69 node = ebis_lookup(&stktable_by_name, name);
70 if (node) {
71 t = container_of(node, struct stktable, name);
72 if (!strcmp(t->id, name))
73 return t;
74 }
75
76 return NULL;
77}
78
Emeric Brun3bd697e2010-01-04 15:23:48 +010079/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020080 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
81 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010082 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020083void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010084{
85 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010086 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010087}
88
89/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020090 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
91 * in table <t>.
92 * This function locks the table
93 */
94void stksess_free(struct stktable *t, struct stksess *ts)
95{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010096 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020097 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010098 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020099}
100
101/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200102 * Kill an stksess (only if its ref_cnt is zero).
103 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200104int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200105{
106 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200107 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200108
109 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200110 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200111 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200112 __stksess_free(t, ts);
113 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200114}
115
116/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200117 * Decrease the refcount if decrefcnt is not 0.
118 * and try to kill the stksess
119 * This function locks the table
120 */
121int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
122{
123 int ret;
124
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100125 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200126 if (decrefcnt)
127 ts->ref_cnt--;
128 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100129 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200130
131 return ret;
132}
133
134/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200135 * Initialize or update the key in the sticky session <ts> present in table <t>
136 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100137 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200138void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100139{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200140 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200141 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100142 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200143 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
144 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100145 }
146}
147
148
149/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200150 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
151 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100152 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200153static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100154{
Willy Tarreau393379c2010-06-06 12:11:37 +0200155 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200156 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200157 ts->key.node.leaf_p = NULL;
158 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200159 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200160 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100161 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100162 return ts;
163}
164
165/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200166 * Trash oldest <to_batch> sticky sessions from table <t>
167 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100168 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200169int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100170{
171 struct stksess *ts;
172 struct eb32_node *eb;
173 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200174 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100175
176 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
177
178 while (batched < to_batch) {
179
180 if (unlikely(!eb)) {
181 /* we might have reached the end of the tree, typically because
182 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200183 * half. Let's loop back to the beginning of the tree now if we
184 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100185 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200186 if (looped)
187 break;
188 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100189 eb = eb32_first(&t->exps);
190 if (likely(!eb))
191 break;
192 }
193
194 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200195 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100196 eb = eb32_next(eb);
197
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200198 /* don't delete an entry which is currently referenced */
199 if (ts->ref_cnt)
200 continue;
201
Willy Tarreau86257dc2010-06-06 12:57:10 +0200202 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100203
Willy Tarreau86257dc2010-06-06 12:57:10 +0200204 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100205 if (!tick_isset(ts->expire))
206 continue;
207
Willy Tarreau86257dc2010-06-06 12:57:10 +0200208 ts->exp.key = ts->expire;
209 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210
Willy Tarreau86257dc2010-06-06 12:57:10 +0200211 if (!eb || eb->key > ts->exp.key)
212 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100213
214 continue;
215 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100216
Willy Tarreauaea940e2010-06-06 11:56:36 +0200217 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200219 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200220 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100221 batched++;
222 }
223
224 return batched;
225}
226
227/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200228 * Trash oldest <to_batch> sticky sessions from table <t>
229 * Returns number of trashed sticky sessions.
230 * This function locks the table
231 */
232int stktable_trash_oldest(struct stktable *t, int to_batch)
233{
234 int ret;
235
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100236 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200237 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100238 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200239
240 return ret;
241}
242/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200243 * Allocate and initialise a new sticky session.
244 * The new sticky session is returned or NULL in case of lack of memory.
245 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200246 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
247 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100248 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200249struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100250{
251 struct stksess *ts;
252
253 if (unlikely(t->current == t->size)) {
254 if ( t->nopurge )
255 return NULL;
256
Emeric Brun819fc6f2017-06-13 19:37:32 +0200257 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100258 return NULL;
259 }
260
Willy Tarreaubafbe012017-11-24 17:34:44 +0100261 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262 if (ts) {
263 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100264 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200265 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200266 if (key)
267 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100268 }
269
270 return ts;
271}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200272/*
273 * Allocate and initialise a new sticky session.
274 * The new sticky session is returned or NULL in case of lack of memory.
275 * Sticky sessions should only be allocated this way, and must be freed using
276 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
277 * is not NULL, it is assigned to the new session.
278 * This function locks the table
279 */
280struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
281{
282 struct stksess *ts;
283
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100284 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200285 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100286 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200287
288 return ts;
289}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100290
291/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200292 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200293 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100294 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200295struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100296{
297 struct ebmb_node *eb;
298
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200299 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200300 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 +0100301 else
302 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
303
304 if (unlikely(!eb)) {
305 /* no session found */
306 return NULL;
307 }
308
Willy Tarreau86257dc2010-06-06 12:57:10 +0200309 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310}
311
Emeric Brun819fc6f2017-06-13 19:37:32 +0200312/*
313 * Looks in table <t> for a sticky session matching key <key>.
314 * Returns pointer on requested sticky session or NULL if none was found.
315 * The refcount of the found entry is increased and this function
316 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200317 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200318struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200319{
320 struct stksess *ts;
321
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100322 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200323 ts = __stktable_lookup_key(t, key);
324 if (ts)
325 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100326 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200327
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200328 return ts;
329}
330
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200331/*
332 * Looks in table <t> for a sticky session with same key as <ts>.
333 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100334 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200335struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100336{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100337 struct ebmb_node *eb;
338
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200339 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200340 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100341 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200342 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100343
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200344 if (unlikely(!eb))
345 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100346
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200347 return ebmb_entry(eb, struct stksess, key);
348}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100349
Emeric Brun819fc6f2017-06-13 19:37:32 +0200350/*
351 * Looks in table <t> for a sticky session with same key as <ts>.
352 * Returns pointer on requested sticky session or NULL if none was found.
353 * The refcount of the found entry is increased and this function
354 * is protected using the table lock
355 */
356struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
357{
358 struct stksess *lts;
359
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100360 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200361 lts = __stktable_lookup(t, ts);
362 if (lts)
363 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100364 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200365
366 return lts;
367}
368
Willy Tarreaucb183642010-06-06 17:58:34 +0200369/* Update the expiration timer for <ts> but do not touch its expiration node.
370 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200371 * The node will be also inserted into the update tree if needed, at a position
372 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200373 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200374void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200375{
Emeric Brun85e77c72010-09-23 18:16:52 +0200376 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200377 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200378 if (t->expire) {
379 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
380 task_queue(t->exp_task);
381 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200382
Emeric Brun819fc6f2017-06-13 19:37:32 +0200383 /* If sync is enabled */
384 if (t->sync_task) {
385 if (local) {
386 /* If this entry is not in the tree
387 or not scheduled for at least one peer */
388 if (!ts->upd.node.leaf_p
389 || (int)(t->commitupdate - ts->upd.key) >= 0
390 || (int)(ts->upd.key - t->localupdate) >= 0) {
391 ts->upd.key = ++t->update;
392 t->localupdate = t->update;
393 eb32_delete(&ts->upd);
394 eb = eb32_insert(&t->updates, &ts->upd);
395 if (eb != &ts->upd) {
396 eb32_delete(eb);
397 eb32_insert(&t->updates, &ts->upd);
398 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200399 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200400 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200401 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200402 else {
403 /* If this entry is not in the tree */
404 if (!ts->upd.node.leaf_p) {
405 ts->upd.key= (++t->update)+(2147483648U);
406 eb = eb32_insert(&t->updates, &ts->upd);
407 if (eb != &ts->upd) {
408 eb32_delete(eb);
409 eb32_insert(&t->updates, &ts->upd);
410 }
411 }
412 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200413 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200414}
415
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200416/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200418 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200419 * The node will be also inserted into the update tree if needed, at a position
420 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200421 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200422void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
423{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100424 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200425 __stktable_touch_with_exp(t, ts, 0, ts->expire);
426 if (decrefcnt)
427 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100428 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200429}
430
431/* Update the expiration timer for <ts> but do not touch its expiration node.
432 * The table's expiration timer is updated using the date of expiration coming from
433 * <t> stick-table configuration.
434 * The node will be also inserted into the update tree if needed, at a position
435 * considering the update was made locally
436 */
437void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200438{
439 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
440
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100441 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200442 __stktable_touch_with_exp(t, ts, 1, expire);
443 if (decrefcnt)
444 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100445 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200446}
Willy Tarreau43e90352018-06-27 06:25:57 +0200447/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
448static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200449{
Willy Tarreau43e90352018-06-27 06:25:57 +0200450 if (!ts)
451 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100452 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100454 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200455}
456
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200457/* Insert new sticky session <ts> in the table. It is assumed that it does not
458 * yet exist (the caller must check this). The table's timeout is updated if it
459 * is set. <ts> is returned.
460 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200461void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200462{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100463
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200464 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200465 ts->exp.key = ts->expire;
466 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200467 if (t->expire) {
468 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
469 task_queue(t->exp_task);
470 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200471}
472
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200473/* Returns a valid or initialized stksess for the specified stktable_key in the
474 * specified table, or NULL if the key was NULL, or if no entry was found nor
475 * could be created. The entry's expiration is updated.
476 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200477struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200478{
479 struct stksess *ts;
480
481 if (!key)
482 return NULL;
483
Emeric Brun819fc6f2017-06-13 19:37:32 +0200484 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200485 if (ts == NULL) {
486 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200487 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200488 if (!ts)
489 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200490 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200491 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200492 return ts;
493}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200494/* Returns a valid or initialized stksess for the specified stktable_key in the
495 * specified table, or NULL if the key was NULL, or if no entry was found nor
496 * could be created. The entry's expiration is updated.
497 * This function locks the table, and the refcount of the entry is increased.
498 */
499struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
500{
501 struct stksess *ts;
502
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100503 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200504 ts = __stktable_get_entry(table, key);
505 if (ts)
506 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100507 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508
509 return ts;
510}
511
512/* Lookup for an entry with the same key and store the submitted
513 * stksess if not found.
514 */
515struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
516{
517 struct stksess *ts;
518
519 ts = __stktable_lookup(table, nts);
520 if (ts == NULL) {
521 ts = nts;
522 __stktable_store(table, ts);
523 }
524 return ts;
525}
526
527/* Lookup for an entry with the same key and store the submitted
528 * stksess if not found.
529 * This function locks the table, and the refcount of the entry is increased.
530 */
531struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
532{
533 struct stksess *ts;
534
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100535 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200536 ts = __stktable_set_entry(table, nts);
537 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100538 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200539
Emeric Brun819fc6f2017-06-13 19:37:32 +0200540 return ts;
541}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100542/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200543 * Trash expired sticky sessions from table <t>. The next expiration date is
544 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100545 */
546static int stktable_trash_expired(struct stktable *t)
547{
548 struct stksess *ts;
549 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200550 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100551
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100552 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100553 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
554
555 while (1) {
556 if (unlikely(!eb)) {
557 /* we might have reached the end of the tree, typically because
558 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200559 * half. Let's loop back to the beginning of the tree now if we
560 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100561 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200562 if (looped)
563 break;
564 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100565 eb = eb32_first(&t->exps);
566 if (likely(!eb))
567 break;
568 }
569
570 if (likely(tick_is_lt(now_ms, eb->key))) {
571 /* timer not expired yet, revisit it later */
572 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100573 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100574 }
575
576 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200577 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100578 eb = eb32_next(eb);
579
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200580 /* don't delete an entry which is currently referenced */
581 if (ts->ref_cnt)
582 continue;
583
Willy Tarreau86257dc2010-06-06 12:57:10 +0200584 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100585
586 if (!tick_is_expired(ts->expire, now_ms)) {
587 if (!tick_isset(ts->expire))
588 continue;
589
Willy Tarreau86257dc2010-06-06 12:57:10 +0200590 ts->exp.key = ts->expire;
591 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592
Willy Tarreau86257dc2010-06-06 12:57:10 +0200593 if (!eb || eb->key > ts->exp.key)
594 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100595 continue;
596 }
597
598 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200599 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200600 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200601 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100602 }
603
604 /* We have found no task to expire in any tree */
605 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100606out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100607 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100608 return t->exp_next;
609}
610
611/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200612 * Task processing function to trash expired sticky sessions. A pointer to the
613 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100614 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200615static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200617 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100618
619 task->expire = stktable_trash_expired(t);
620 return task;
621}
622
Willy Tarreauaea940e2010-06-06 11:56:36 +0200623/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100624int stktable_init(struct stktable *t)
625{
626 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200627 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100628 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100629 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100630 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100631
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100632 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 +0100633
634 t->exp_next = TICK_ETERNITY;
635 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200636 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200637 if (!t->exp_task)
638 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100640 t->exp_task->context = (void *)t;
641 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200642 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200643 peers_register_table(t->peers.p, t);
644 }
645
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646 return t->pool != NULL;
647 }
648 return 1;
649}
650
651/*
652 * Configuration keywords of known table types
653 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200654struct stktable_type stktable_types[SMP_TYPES] = {
655 [SMP_T_SINT] = { "integer", 0, 4 },
656 [SMP_T_IPV4] = { "ip", 0, 4 },
657 [SMP_T_IPV6] = { "ipv6", 0, 16 },
658 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
659 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
660};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100661
662/*
663 * Parse table type configuration.
664 * Returns 0 on successful parsing, else 1.
665 * <myidx> is set at next configuration <args> index.
666 */
667int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
668{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200669 for (*type = 0; *type < SMP_TYPES; (*type)++) {
670 if (!stktable_types[*type].kw)
671 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100672 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
673 continue;
674
675 *key_size = stktable_types[*type].default_size;
676 (*myidx)++;
677
Willy Tarreauaea940e2010-06-06 11:56:36 +0200678 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100679 if (strcmp("len", args[*myidx]) == 0) {
680 (*myidx)++;
681 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200682 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100683 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200684 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200685 /* null terminated string needs +1 for '\0'. */
686 (*key_size)++;
687 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100688 (*myidx)++;
689 }
690 }
691 return 0;
692 }
693 return 1;
694}
695
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100696/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100697 * Parse a line with <linenum> as number in <file> configuration file to configure
698 * the stick-table with <t> as address and <id> as ID.
699 * <peers> provides the "peers" section pointer only if this function is called
700 * from a "peers" section.
701 * <nid> is the stick-table name which is sent over the network. It must be equal
702 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
703 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500704 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100705 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
706 */
707int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100708 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100709{
710 int err_code = 0;
711 int idx = 1;
712 unsigned int val;
713
714 if (!id || !*id) {
715 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
716 err_code |= ERR_ALERT | ERR_ABORT;
717 goto out;
718 }
719
720 /* Store the "peers" section if this function is called from a "peers" section. */
721 if (peers) {
722 t->peers.p = peers;
723 idx++;
724 }
725
726 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100727 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100728 t->type = (unsigned int)-1;
729 t->conf.file = file;
730 t->conf.line = linenum;
731
732 while (*args[idx]) {
733 const char *err;
734
735 if (strcmp(args[idx], "size") == 0) {
736 idx++;
737 if (!*(args[idx])) {
738 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
739 file, linenum, args[0], args[idx-1]);
740 err_code |= ERR_ALERT | ERR_FATAL;
741 goto out;
742 }
743 if ((err = parse_size_err(args[idx], &t->size))) {
744 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
745 file, linenum, args[0], *err, args[idx-1]);
746 err_code |= ERR_ALERT | ERR_FATAL;
747 goto out;
748 }
749 idx++;
750 }
751 /* This argument does not exit in "peers" section. */
752 else if (!peers && strcmp(args[idx], "peers") == 0) {
753 idx++;
754 if (!*(args[idx])) {
755 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
756 file, linenum, args[0], args[idx-1]);
757 err_code |= ERR_ALERT | ERR_FATAL;
758 goto out;
759 }
760 t->peers.name = strdup(args[idx++]);
761 }
762 else if (strcmp(args[idx], "expire") == 0) {
763 idx++;
764 if (!*(args[idx])) {
765 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
766 file, linenum, args[0], args[idx-1]);
767 err_code |= ERR_ALERT | ERR_FATAL;
768 goto out;
769 }
770 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200771 if (err == PARSE_TIME_OVER) {
772 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
773 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100774 err_code |= ERR_ALERT | ERR_FATAL;
775 goto out;
776 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200777 else if (err == PARSE_TIME_UNDER) {
778 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
779 file, linenum, args[0], args[idx], args[idx-1]);
780 err_code |= ERR_ALERT | ERR_FATAL;
781 goto out;
782 }
783 else if (err) {
784 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
785 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100786 err_code |= ERR_ALERT | ERR_FATAL;
787 goto out;
788 }
789 t->expire = val;
790 idx++;
791 }
792 else if (strcmp(args[idx], "nopurge") == 0) {
793 t->nopurge = 1;
794 idx++;
795 }
796 else if (strcmp(args[idx], "type") == 0) {
797 idx++;
798 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
799 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
800 file, linenum, args[0], args[idx]);
801 err_code |= ERR_ALERT | ERR_FATAL;
802 goto out;
803 }
804 /* idx already points to next arg */
805 }
806 else if (strcmp(args[idx], "store") == 0) {
807 int type, err;
808 char *cw, *nw, *sa;
809
810 idx++;
811 nw = args[idx];
812 while (*nw) {
813 /* the "store" keyword supports a comma-separated list */
814 cw = nw;
815 sa = NULL; /* store arg */
816 while (*nw && *nw != ',') {
817 if (*nw == '(') {
818 *nw = 0;
819 sa = ++nw;
820 while (*nw != ')') {
821 if (!*nw) {
822 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
823 file, linenum, args[0], cw);
824 err_code |= ERR_ALERT | ERR_FATAL;
825 goto out;
826 }
827 nw++;
828 }
829 *nw = '\0';
830 }
831 nw++;
832 }
833 if (*nw)
834 *nw++ = '\0';
835 type = stktable_get_data_type(cw);
836 if (type < 0) {
837 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
838 file, linenum, args[0], cw);
839 err_code |= ERR_ALERT | ERR_FATAL;
840 goto out;
841 }
842
843 err = stktable_alloc_data_type(t, type, sa);
844 switch (err) {
845 case PE_NONE: break;
846 case PE_EXIST:
847 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
848 file, linenum, args[0], cw);
849 err_code |= ERR_WARN;
850 break;
851
852 case PE_ARG_MISSING:
853 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
854 file, linenum, args[0], cw);
855 err_code |= ERR_ALERT | ERR_FATAL;
856 goto out;
857
858 case PE_ARG_NOT_USED:
859 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
860 file, linenum, args[0], cw);
861 err_code |= ERR_ALERT | ERR_FATAL;
862 goto out;
863
864 default:
865 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
866 file, linenum, args[0], cw);
867 err_code |= ERR_ALERT | ERR_FATAL;
868 goto out;
869 }
870 }
871 idx++;
872 }
873 else {
874 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
875 file, linenum, args[0], args[idx]);
876 err_code |= ERR_ALERT | ERR_FATAL;
877 goto out;
878 }
879 }
880
881 if (!t->size) {
882 ha_alert("parsing [%s:%d] : %s: missing size.\n",
883 file, linenum, args[0]);
884 err_code |= ERR_ALERT | ERR_FATAL;
885 goto out;
886 }
887
888 if (t->type == (unsigned int)-1) {
889 ha_alert("parsing [%s:%d] : %s: missing type.\n",
890 file, linenum, args[0]);
891 err_code |= ERR_ALERT | ERR_FATAL;
892 goto out;
893 }
894
895 out:
896 return err_code;
897}
898
Willy Tarreau8fed9032014-07-03 17:02:46 +0200899/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200900 * Note that the sample *is* modified and that the returned key may point
901 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200902 * Returns NULL if the sample could not be converted (eg: no matching type),
903 * otherwise a pointer to the static stktable_key filled with what is needed
904 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200905 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200906struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200907{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200908 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200909 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200910 return NULL;
911
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200912 /* Fill static_table_key. */
913 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200914
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200915 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200916 static_table_key.key = &smp->data.u.ipv4;
917 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200918 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200919
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200920 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200921 static_table_key.key = &smp->data.u.ipv6;
922 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200923 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200924
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200925 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200926 /* The stick table require a 32bit unsigned int, "sint" is a
927 * signed 64 it, so we can convert it inplace.
928 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200929 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200930 static_table_key.key = &smp->data.u.sint;
931 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200932 break;
933
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200934 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200935 if (!smp_make_safe(smp))
936 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200937 static_table_key.key = smp->data.u.str.area;
938 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200939 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200940
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200941 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200942 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200943 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200944 if (!smp_make_rw(smp))
945 return NULL;
946
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200947 if (smp->data.u.str.size < t->key_size)
948 if (!smp_dup(smp))
949 return NULL;
950 if (smp->data.u.str.size < t->key_size)
951 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200952 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
953 t->key_size - smp->data.u.str.data);
954 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200955 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200956 static_table_key.key = smp->data.u.str.area;
957 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200958 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200959
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200960 default: /* impossible case. */
961 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200962 }
963
Christopher Fauletca20d022017-08-29 15:30:31 +0200964 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200965}
966
967/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200968 * Process a fetch + format conversion as defined by the sample expression <expr>
969 * on request or response considering the <opt> parameter. Returns either NULL if
970 * no key could be extracted, or a pointer to the converted result stored in
971 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
972 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200973 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
974 * without SMP_OPT_FINAL). The output will be usable like this :
975 *
976 * return MAY_CHANGE FINAL Meaning for the sample
977 * NULL 0 * Not present and will never be (eg: header)
978 * NULL 1 0 Not present or unstable, could change (eg: req_len)
979 * NULL 1 1 Not present, will not change anymore
980 * smp 0 * Present and will not change (eg: header)
981 * smp 1 0 not possible
982 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200983 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200984struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200985 unsigned int opt, struct sample_expr *expr, struct sample *smp)
986{
987 if (smp)
988 memset(smp, 0, sizeof(*smp));
989
Willy Tarreau192252e2015-04-04 01:47:55 +0200990 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200991 if (!smp)
992 return NULL;
993
994 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
995 return NULL; /* we can only use stable samples */
996
997 return smp_to_stkey(smp, t);
998}
999
1000/*
Willy Tarreau12785782012-04-27 21:37:17 +02001001 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001002 * type <table_type>, otherwise zero. Used in configuration check.
1003 */
Willy Tarreau12785782012-04-27 21:37:17 +02001004int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001005{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001006 int out_type;
1007
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001008 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001009 return 0;
1010
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001011 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001012
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001013 /* Convert sample. */
1014 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001015 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001016
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001017 return 1;
1018}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001019
Willy Tarreauedee1d62014-07-15 16:44:27 +02001020/* Extra data types processing : after the last one, some room may remain
1021 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1022 * at run time.
1023 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001024struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001025 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001026 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001027 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001028 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001029 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1030 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1031 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1032 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1033 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1034 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1035 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1036 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1037 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1038 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1039 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1040 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1041 [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 +01001042 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1043 [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 +02001044 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001045};
1046
Willy Tarreauedee1d62014-07-15 16:44:27 +02001047/* Registers stick-table extra data type with index <idx>, name <name>, type
1048 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1049 * index is automatically allocated. The allocated index is returned, or -1 if
1050 * no free index was found or <name> was already registered. The <name> is used
1051 * directly as a pointer, so if it's not stable, the caller must allocate it.
1052 */
1053int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1054{
1055 if (idx < 0) {
1056 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1057 if (!stktable_data_types[idx].name)
1058 break;
1059
1060 if (strcmp(stktable_data_types[idx].name, name) == 0)
1061 return -1;
1062 }
1063 }
1064
1065 if (idx >= STKTABLE_DATA_TYPES)
1066 return -1;
1067
1068 if (stktable_data_types[idx].name != NULL)
1069 return -1;
1070
1071 stktable_data_types[idx].name = name;
1072 stktable_data_types[idx].std_type = std_type;
1073 stktable_data_types[idx].arg_type = arg_type;
1074 return idx;
1075}
1076
Willy Tarreau08d5f982010-06-06 13:34:54 +02001077/*
1078 * Returns the data type number for the stktable_data_type whose name is <name>,
1079 * or <0 if not found.
1080 */
1081int stktable_get_data_type(char *name)
1082{
1083 int type;
1084
1085 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001086 if (!stktable_data_types[type].name)
1087 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001088 if (strcmp(name, stktable_data_types[type].name) == 0)
1089 return type;
1090 }
1091 return -1;
1092}
1093
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001094/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1095 * it up into this table. Returns true if found, false otherwise. The input
1096 * type is STR so that input samples are converted to string (since all types
1097 * can be converted to strings), then the function casts the string again into
1098 * the table's type. This is a double conversion, but in the future we might
1099 * support automatic input types to perform the cast on the fly.
1100 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001101static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001102{
1103 struct stktable *t;
1104 struct stktable_key *key;
1105 struct stksess *ts;
1106
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001107 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001108
1109 key = smp_to_stkey(smp, t);
1110 if (!key)
1111 return 0;
1112
1113 ts = stktable_lookup_key(t, key);
1114
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001115 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001116 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001117 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001118 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001119 return 1;
1120}
1121
1122/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1123 * it up into this table. Returns the data rate received from clients in bytes/s
1124 * if the key is present in the table, otherwise zero, so that comparisons can
1125 * be easily performed. If the inspected parameter is not stored in the table,
1126 * <not found> is returned.
1127 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001128static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001129{
1130 struct stktable *t;
1131 struct stktable_key *key;
1132 struct stksess *ts;
1133 void *ptr;
1134
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001135 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001136
1137 key = smp_to_stkey(smp, t);
1138 if (!key)
1139 return 0;
1140
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001141 ts = stktable_lookup_key(t, key);
1142
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001143 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001144 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001145 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001146
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001147 if (!ts) /* key not present */
1148 return 1;
1149
1150 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001151 if (ptr)
1152 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1153 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001154
Daniel Corbett3e60b112018-05-27 09:47:12 -04001155 stktable_release(t, ts);
1156 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001157}
1158
1159/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1160 * it up into this table. Returns the cumulated number of connections for the key
1161 * if the key is present in the table, otherwise zero, so that comparisons can
1162 * be easily performed. If the inspected parameter is not stored in the table,
1163 * <not found> is returned.
1164 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001165static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001166{
1167 struct stktable *t;
1168 struct stktable_key *key;
1169 struct stksess *ts;
1170 void *ptr;
1171
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001172 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001173
1174 key = smp_to_stkey(smp, t);
1175 if (!key)
1176 return 0;
1177
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001178 ts = stktable_lookup_key(t, key);
1179
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001180 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001181 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001182 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001183
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001184 if (!ts) /* key not present */
1185 return 1;
1186
1187 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001188 if (ptr)
1189 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001190
Daniel Corbett3e60b112018-05-27 09:47:12 -04001191 stktable_release(t, ts);
1192 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001193}
1194
1195/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1196 * it up into this table. Returns the number of concurrent connections for the
1197 * key if the key is present in the table, otherwise zero, so that comparisons
1198 * can be easily performed. If the inspected parameter is not stored in the
1199 * table, <not found> is returned.
1200 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001201static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001202{
1203 struct stktable *t;
1204 struct stktable_key *key;
1205 struct stksess *ts;
1206 void *ptr;
1207
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001208 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001209
1210 key = smp_to_stkey(smp, t);
1211 if (!key)
1212 return 0;
1213
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001214 ts = stktable_lookup_key(t, key);
1215
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001216 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001217 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001218 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001219
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001220 if (!ts) /* key not present */
1221 return 1;
1222
1223 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001224 if (ptr)
1225 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001226
Daniel Corbett3e60b112018-05-27 09:47:12 -04001227 stktable_release(t, ts);
1228 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001229}
1230
1231/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1232 * it up into this table. Returns the rate of incoming connections from the key
1233 * if the key is present in the table, otherwise zero, so that comparisons can
1234 * be easily performed. If the inspected parameter is not stored in the table,
1235 * <not found> is returned.
1236 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001237static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001238{
1239 struct stktable *t;
1240 struct stktable_key *key;
1241 struct stksess *ts;
1242 void *ptr;
1243
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001244 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001245
1246 key = smp_to_stkey(smp, t);
1247 if (!key)
1248 return 0;
1249
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001250 ts = stktable_lookup_key(t, key);
1251
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001253 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001254 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001255
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001256 if (!ts) /* key not present */
1257 return 1;
1258
1259 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001260 if (ptr)
1261 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1262 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001263
Daniel Corbett3e60b112018-05-27 09:47:12 -04001264 stktable_release(t, ts);
1265 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001266}
1267
1268/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1269 * it up into this table. Returns the data rate sent to clients in bytes/s
1270 * if the key is present in the table, otherwise zero, so that comparisons can
1271 * be easily performed. If the inspected parameter is not stored in the table,
1272 * <not found> is returned.
1273 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001274static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275{
1276 struct stktable *t;
1277 struct stktable_key *key;
1278 struct stksess *ts;
1279 void *ptr;
1280
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001281 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001282
1283 key = smp_to_stkey(smp, t);
1284 if (!key)
1285 return 0;
1286
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001287 ts = stktable_lookup_key(t, key);
1288
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001289 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001290 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001291 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001292
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001293 if (!ts) /* key not present */
1294 return 1;
1295
1296 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001297 if (ptr)
1298 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1299 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001300
Daniel Corbett3e60b112018-05-27 09:47:12 -04001301 stktable_release(t, ts);
1302 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001303}
1304
1305/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001306 * it up into this table. Returns the value of the GPT0 tag for the key
1307 * if the key is present in the table, otherwise false, so that comparisons can
1308 * be easily performed. If the inspected parameter is not stored in the table,
1309 * <not found> is returned.
1310 */
1311static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1312{
1313 struct stktable *t;
1314 struct stktable_key *key;
1315 struct stksess *ts;
1316 void *ptr;
1317
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001318 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001319
1320 key = smp_to_stkey(smp, t);
1321 if (!key)
1322 return 0;
1323
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001324 ts = stktable_lookup_key(t, key);
1325
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001326 smp->flags = SMP_F_VOL_TEST;
1327 smp->data.type = SMP_T_SINT;
1328 smp->data.u.sint = 0;
1329
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001330 if (!ts) /* key not present */
1331 return 1;
1332
1333 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001334 if (ptr)
1335 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001336
Daniel Corbett3e60b112018-05-27 09:47:12 -04001337 stktable_release(t, ts);
1338 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001339}
1340
1341/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001342 * it up into this table. Returns the value of the GPC0 counter for the key
1343 * if the key is present in the table, otherwise zero, so that comparisons can
1344 * be easily performed. If the inspected parameter is not stored in the table,
1345 * <not found> is returned.
1346 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001347static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001348{
1349 struct stktable *t;
1350 struct stktable_key *key;
1351 struct stksess *ts;
1352 void *ptr;
1353
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001354 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001355
1356 key = smp_to_stkey(smp, t);
1357 if (!key)
1358 return 0;
1359
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001360 ts = stktable_lookup_key(t, key);
1361
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001363 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001364 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001365
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366 if (!ts) /* key not present */
1367 return 1;
1368
1369 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001370 if (ptr)
1371 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372
Daniel Corbett3e60b112018-05-27 09:47:12 -04001373 stktable_release(t, ts);
1374 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001375}
1376
1377/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1378 * it up into this table. Returns the event rate of the GPC0 counter for the key
1379 * if the key is present in the table, otherwise zero, so that comparisons can
1380 * be easily performed. If the inspected parameter is not stored in the table,
1381 * <not found> is returned.
1382 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001383static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384{
1385 struct stktable *t;
1386 struct stktable_key *key;
1387 struct stksess *ts;
1388 void *ptr;
1389
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001390 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391
1392 key = smp_to_stkey(smp, t);
1393 if (!key)
1394 return 0;
1395
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001396 ts = stktable_lookup_key(t, key);
1397
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001399 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001400 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001401
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402 if (!ts) /* key not present */
1403 return 1;
1404
1405 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001406 if (ptr)
1407 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1408 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409
Daniel Corbett3e60b112018-05-27 09:47:12 -04001410 stktable_release(t, ts);
1411 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001412}
1413
1414/* 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 +01001415 * it up into this table. Returns the value of the GPC1 counter for the key
1416 * if the key is present in the table, otherwise zero, so that comparisons can
1417 * be easily performed. If the inspected parameter is not stored in the table,
1418 * <not found> is returned.
1419 */
1420static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1421{
1422 struct stktable *t;
1423 struct stktable_key *key;
1424 struct stksess *ts;
1425 void *ptr;
1426
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001427 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001428
1429 key = smp_to_stkey(smp, t);
1430 if (!key)
1431 return 0;
1432
1433 ts = stktable_lookup_key(t, key);
1434
1435 smp->flags = SMP_F_VOL_TEST;
1436 smp->data.type = SMP_T_SINT;
1437 smp->data.u.sint = 0;
1438
1439 if (!ts) /* key not present */
1440 return 1;
1441
1442 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001443 if (ptr)
1444 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001445
Daniel Corbett3e60b112018-05-27 09:47:12 -04001446 stktable_release(t, ts);
1447 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001448}
1449
1450/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1451 * it up into this table. Returns the event rate of the GPC1 counter for the key
1452 * if the key is present in the table, otherwise zero, so that comparisons can
1453 * be easily performed. If the inspected parameter is not stored in the table,
1454 * <not found> is returned.
1455 */
1456static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1457{
1458 struct stktable *t;
1459 struct stktable_key *key;
1460 struct stksess *ts;
1461 void *ptr;
1462
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001463 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001464
1465 key = smp_to_stkey(smp, t);
1466 if (!key)
1467 return 0;
1468
1469 ts = stktable_lookup_key(t, key);
1470
1471 smp->flags = SMP_F_VOL_TEST;
1472 smp->data.type = SMP_T_SINT;
1473 smp->data.u.sint = 0;
1474
1475 if (!ts) /* key not present */
1476 return 1;
1477
1478 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001479 if (ptr)
1480 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1481 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001482
Daniel Corbett3e60b112018-05-27 09:47:12 -04001483 stktable_release(t, ts);
1484 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001485}
1486
1487/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001488 * it up into this table. Returns the cumulated number of HTTP request errors
1489 * for the key if the key is present in the table, otherwise zero, so that
1490 * comparisons can be easily performed. If the inspected parameter is not stored
1491 * in the table, <not found> is returned.
1492 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001493static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001494{
1495 struct stktable *t;
1496 struct stktable_key *key;
1497 struct stksess *ts;
1498 void *ptr;
1499
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001500 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001501
1502 key = smp_to_stkey(smp, t);
1503 if (!key)
1504 return 0;
1505
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001506 ts = stktable_lookup_key(t, key);
1507
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001508 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001509 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001510 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001511
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001512 if (!ts) /* key not present */
1513 return 1;
1514
1515 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001516 if (ptr)
1517 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001518
Daniel Corbett3e60b112018-05-27 09:47:12 -04001519 stktable_release(t, ts);
1520 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001521}
1522
1523/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1524 * it up into this table. Returns the HTTP request error rate the key
1525 * if the key is present in the table, otherwise zero, so that comparisons can
1526 * be easily performed. If the inspected parameter is not stored in the table,
1527 * <not found> is returned.
1528 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001529static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001530{
1531 struct stktable *t;
1532 struct stktable_key *key;
1533 struct stksess *ts;
1534 void *ptr;
1535
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001536 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001537
1538 key = smp_to_stkey(smp, t);
1539 if (!key)
1540 return 0;
1541
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001542 ts = stktable_lookup_key(t, key);
1543
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001544 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001545 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001546 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001547
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001548 if (!ts) /* key not present */
1549 return 1;
1550
1551 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001552 if (ptr)
1553 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1554 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001555
Daniel Corbett3e60b112018-05-27 09:47:12 -04001556 stktable_release(t, ts);
1557 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001558}
1559
1560/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1561 * it up into this table. Returns the cumulated number of HTTP request for the
1562 * key if the key is present in the table, otherwise zero, so that comparisons
1563 * can be easily performed. If the inspected parameter is not stored in the
1564 * table, <not found> is returned.
1565 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001566static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001567{
1568 struct stktable *t;
1569 struct stktable_key *key;
1570 struct stksess *ts;
1571 void *ptr;
1572
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001573 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001574
1575 key = smp_to_stkey(smp, t);
1576 if (!key)
1577 return 0;
1578
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001579 ts = stktable_lookup_key(t, key);
1580
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001581 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001582 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001583 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001584
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001585 if (!ts) /* key not present */
1586 return 1;
1587
1588 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001589 if (ptr)
1590 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001591
Daniel Corbett3e60b112018-05-27 09:47:12 -04001592 stktable_release(t, ts);
1593 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001594}
1595
1596/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1597 * it up into this table. Returns the HTTP request rate the key if the key is
1598 * present in the table, otherwise zero, so that comparisons can be easily
1599 * performed. If the inspected parameter is not stored in the table, <not found>
1600 * is returned.
1601 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001602static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001603{
1604 struct stktable *t;
1605 struct stktable_key *key;
1606 struct stksess *ts;
1607 void *ptr;
1608
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001609 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001610
1611 key = smp_to_stkey(smp, t);
1612 if (!key)
1613 return 0;
1614
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001615 ts = stktable_lookup_key(t, key);
1616
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001617 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001618 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001619 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001620
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001621 if (!ts) /* key not present */
1622 return 1;
1623
1624 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001625 if (ptr)
1626 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1627 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001628
Daniel Corbett3e60b112018-05-27 09:47:12 -04001629 stktable_release(t, ts);
1630 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001631}
1632
1633/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1634 * it up into this table. Returns the volume of datareceived from clients in kbytes
1635 * if the key is present in the table, otherwise zero, so that comparisons can
1636 * be easily performed. If the inspected parameter is not stored in the table,
1637 * <not found> is returned.
1638 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001639static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001640{
1641 struct stktable *t;
1642 struct stktable_key *key;
1643 struct stksess *ts;
1644 void *ptr;
1645
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001646 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001647
1648 key = smp_to_stkey(smp, t);
1649 if (!key)
1650 return 0;
1651
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001652 ts = stktable_lookup_key(t, key);
1653
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001654 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001655 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001656 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001657
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001658 if (!ts) /* key not present */
1659 return 1;
1660
1661 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001662 if (ptr)
1663 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001664
Daniel Corbett3e60b112018-05-27 09:47:12 -04001665 stktable_release(t, ts);
1666 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001667}
1668
1669/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1670 * it up into this table. Returns the volume of data sent to clients in kbytes
1671 * if the key is present in the table, otherwise zero, so that comparisons can
1672 * be easily performed. If the inspected parameter is not stored in the table,
1673 * <not found> is returned.
1674 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001675static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001676{
1677 struct stktable *t;
1678 struct stktable_key *key;
1679 struct stksess *ts;
1680 void *ptr;
1681
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001682 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001683
1684 key = smp_to_stkey(smp, t);
1685 if (!key)
1686 return 0;
1687
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001688 ts = stktable_lookup_key(t, key);
1689
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001690 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001691 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001692 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001693
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001694 if (!ts) /* key not present */
1695 return 1;
1696
1697 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001698 if (ptr)
1699 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001700
Daniel Corbett3e60b112018-05-27 09:47:12 -04001701 stktable_release(t, ts);
1702 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001703}
1704
1705/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1706 * it up into this table. Returns the server ID associated with the key if the
1707 * key is present in the table, otherwise zero, so that comparisons can be
1708 * easily performed. If the inspected parameter is not stored in the table,
1709 * <not found> is returned.
1710 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001711static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001712{
1713 struct stktable *t;
1714 struct stktable_key *key;
1715 struct stksess *ts;
1716 void *ptr;
1717
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001718 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001719
1720 key = smp_to_stkey(smp, t);
1721 if (!key)
1722 return 0;
1723
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001724 ts = stktable_lookup_key(t, key);
1725
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001726 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001727 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001728 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001729
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001730 if (!ts) /* key not present */
1731 return 1;
1732
1733 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001734 if (ptr)
1735 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736
Daniel Corbett3e60b112018-05-27 09:47:12 -04001737 stktable_release(t, ts);
1738 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001739}
1740
1741/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1742 * it up into this table. Returns the cumulated number of sessions for the
1743 * key if the key is present in the table, otherwise zero, so that comparisons
1744 * can be easily performed. If the inspected parameter is not stored in the
1745 * table, <not found> is returned.
1746 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001747static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001748{
1749 struct stktable *t;
1750 struct stktable_key *key;
1751 struct stksess *ts;
1752 void *ptr;
1753
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001754 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001755
1756 key = smp_to_stkey(smp, t);
1757 if (!key)
1758 return 0;
1759
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001760 ts = stktable_lookup_key(t, key);
1761
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001762 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001763 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001764 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001765
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001766 if (!ts) /* key not present */
1767 return 1;
1768
1769 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001770 if (ptr)
1771 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772
Daniel Corbett3e60b112018-05-27 09:47:12 -04001773 stktable_release(t, ts);
1774 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001775}
1776
1777/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1778 * it up into this table. Returns the session rate the key if the key is
1779 * present in the table, otherwise zero, so that comparisons can be easily
1780 * performed. If the inspected parameter is not stored in the table, <not found>
1781 * is returned.
1782 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001783static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001784{
1785 struct stktable *t;
1786 struct stktable_key *key;
1787 struct stksess *ts;
1788 void *ptr;
1789
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001790 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791
1792 key = smp_to_stkey(smp, t);
1793 if (!key)
1794 return 0;
1795
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001796 ts = stktable_lookup_key(t, key);
1797
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001798 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001799 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001800 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802 if (!ts) /* key not present */
1803 return 1;
1804
1805 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001806 if (ptr)
1807 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1808 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809
Daniel Corbett3e60b112018-05-27 09:47:12 -04001810 stktable_release(t, ts);
1811 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001812}
1813
1814/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1815 * it up into this table. Returns the amount of concurrent connections tracking
1816 * the same key if the key is present in the table, otherwise zero, so that
1817 * comparisons can be easily performed. If the inspected parameter is not
1818 * stored in the table, <not found> is returned.
1819 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001820static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001821{
1822 struct stktable *t;
1823 struct stktable_key *key;
1824 struct stksess *ts;
1825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001826 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001827
1828 key = smp_to_stkey(smp, t);
1829 if (!key)
1830 return 0;
1831
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001832 ts = stktable_lookup_key(t, key);
1833
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001834 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001835 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001836 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001837
Tim Duesterhus65189c12018-06-26 15:57:29 +02001838 if (!ts)
1839 return 1;
1840
1841 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001842
Daniel Corbett3e60b112018-05-27 09:47:12 -04001843 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001844 return 1;
1845}
1846
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001847/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001848static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001849 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001850{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001851 struct stksess *ts;
1852 struct stkctr *stkctr;
1853
1854 /* Extract the stksess, return OK if no stksess available. */
1855 if (s)
1856 stkctr = &s->stkctr[rule->arg.gpc.sc];
1857 else
1858 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001859
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001860 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001861 if (ts) {
1862 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001863
Willy Tarreau79c1e912016-01-25 14:54:45 +01001864 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1865 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001866 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1867 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001868 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001869
1870 if (ptr1)
1871 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001872 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001873
Emeric Brun819fc6f2017-06-13 19:37:32 +02001874 if (ptr2)
1875 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001876
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001877 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001878
1879 /* If data was modified, we need to touch to re-schedule sync */
1880 stktable_touch_local(stkctr->table, ts, 0);
1881 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001882 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001883 return ACT_RET_CONT;
1884}
1885
1886/* This function is a common parser for using variables. It understands
1887 * the formats:
1888 *
1889 * sc-inc-gpc0(<stick-table ID>)
1890 *
1891 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1892 * it returns 1 and the variable <expr> is filled with the pointer to the
1893 * expression to execute.
1894 */
1895static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1896 struct act_rule *rule, char **err)
1897{
1898 const char *cmd_name = args[*arg-1];
1899 char *error;
1900
1901 cmd_name += strlen("sc-inc-gpc0");
1902 if (*cmd_name == '\0') {
1903 /* default stick table id. */
1904 rule->arg.gpc.sc = 0;
1905 } else {
1906 /* parse the stick table id. */
1907 if (*cmd_name != '(') {
1908 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1909 return ACT_RET_PRS_ERR;
1910 }
1911 cmd_name++; /* jump the '(' */
1912 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1913 if (*error != ')') {
1914 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1915 return ACT_RET_PRS_ERR;
1916 }
1917
Christopher Faulet28436e22019-12-18 10:25:46 +01001918 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001919 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001920 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001921 return ACT_RET_PRS_ERR;
1922 }
1923 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001924 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001925 rule->action_ptr = action_inc_gpc0;
1926 return ACT_RET_PRS_OK;
1927}
1928
1929/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001930static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1931 struct session *sess, struct stream *s, int flags)
1932{
1933 struct stksess *ts;
1934 struct stkctr *stkctr;
1935
1936 /* Extract the stksess, return OK if no stksess available. */
1937 if (s)
1938 stkctr = &s->stkctr[rule->arg.gpc.sc];
1939 else
1940 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1941
1942 ts = stkctr_entry(stkctr);
1943 if (ts) {
1944 void *ptr1, *ptr2;
1945
1946 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1947 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1948 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1949 if (ptr1 || ptr2) {
1950 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1951
1952 if (ptr1)
1953 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1954 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1955
1956 if (ptr2)
1957 stktable_data_cast(ptr2, gpc1)++;
1958
1959 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1960
1961 /* If data was modified, we need to touch to re-schedule sync */
1962 stktable_touch_local(stkctr->table, ts, 0);
1963 }
1964 }
1965 return ACT_RET_CONT;
1966}
1967
1968/* This function is a common parser for using variables. It understands
1969 * the formats:
1970 *
1971 * sc-inc-gpc1(<stick-table ID>)
1972 *
1973 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1974 * it returns 1 and the variable <expr> is filled with the pointer to the
1975 * expression to execute.
1976 */
1977static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1978 struct act_rule *rule, char **err)
1979{
1980 const char *cmd_name = args[*arg-1];
1981 char *error;
1982
1983 cmd_name += strlen("sc-inc-gpc1");
1984 if (*cmd_name == '\0') {
1985 /* default stick table id. */
1986 rule->arg.gpc.sc = 0;
1987 } else {
1988 /* parse the stick table id. */
1989 if (*cmd_name != '(') {
1990 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1991 return ACT_RET_PRS_ERR;
1992 }
1993 cmd_name++; /* jump the '(' */
1994 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1995 if (*error != ')') {
1996 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1997 return ACT_RET_PRS_ERR;
1998 }
1999
Christopher Faulet28436e22019-12-18 10:25:46 +01002000 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002001 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002002 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002003 return ACT_RET_PRS_ERR;
2004 }
2005 }
2006 rule->action = ACT_CUSTOM;
2007 rule->action_ptr = action_inc_gpc1;
2008 return ACT_RET_PRS_OK;
2009}
2010
2011/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002012static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002013 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002014{
2015 void *ptr;
2016 struct stksess *ts;
2017 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002018 unsigned int value = 0;
2019 struct sample *smp;
2020 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002021
2022 /* Extract the stksess, return OK if no stksess available. */
2023 if (s)
2024 stkctr = &s->stkctr[rule->arg.gpt.sc];
2025 else
2026 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002027
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002028 ts = stkctr_entry(stkctr);
2029 if (!ts)
2030 return ACT_RET_CONT;
2031
2032 /* Store the sample in the required sc, and ignore errors. */
2033 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002034 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002035 if (!rule->arg.gpt.expr)
2036 value = (unsigned int)(rule->arg.gpt.value);
2037 else {
2038 switch (rule->from) {
2039 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2040 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2041 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2042 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2043 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2044 default:
2045 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2046 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2047 ha_alert("stick table: internal error while executing setting gpt0.\n");
2048 return ACT_RET_CONT;
2049 }
2050
2051 /* Fetch and cast the expression. */
2052 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2053 if (!smp) {
2054 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2055 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2056 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2057 return ACT_RET_CONT;
2058 }
2059 value = (unsigned int)(smp->data.u.sint);
2060 }
2061
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002062 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002063
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002064 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002065
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002066 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002067
2068 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002069 }
2070
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002071 return ACT_RET_CONT;
2072}
2073
2074/* This function is a common parser for using variables. It understands
2075 * the format:
2076 *
2077 * set-gpt0(<stick-table ID>) <expression>
2078 *
2079 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2080 * it returns 1 and the variable <expr> is filled with the pointer to the
2081 * expression to execute.
2082 */
2083static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2084 struct act_rule *rule, char **err)
2085
2086
2087{
2088 const char *cmd_name = args[*arg-1];
2089 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002090 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002091
2092 cmd_name += strlen("sc-set-gpt0");
2093 if (*cmd_name == '\0') {
2094 /* default stick table id. */
2095 rule->arg.gpt.sc = 0;
2096 } else {
2097 /* parse the stick table id. */
2098 if (*cmd_name != '(') {
2099 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2100 return ACT_RET_PRS_ERR;
2101 }
2102 cmd_name++; /* jump the '(' */
2103 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2104 if (*error != ')') {
2105 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2106 return ACT_RET_PRS_ERR;
2107 }
2108
Christopher Faulet28436e22019-12-18 10:25:46 +01002109 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002110 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002111 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002112 return ACT_RET_PRS_ERR;
2113 }
2114 }
2115
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002116 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002117 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2118 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002119 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002120 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002121 if (!rule->arg.gpt.expr)
2122 return ACT_RET_PRS_ERR;
2123
2124 switch (rule->from) {
2125 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2126 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2127 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2128 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2129 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2130 default:
2131 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2132 return ACT_RET_PRS_ERR;
2133 }
2134 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2135 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2136 sample_src_names(rule->arg.gpt.expr->fetch->use));
2137 free(rule->arg.gpt.expr);
2138 return ACT_RET_PRS_ERR;
2139 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002140 }
2141 (*arg)++;
2142
Thierry FOURNIER42148732015-09-02 17:17:33 +02002143 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002144 rule->action_ptr = action_set_gpt0;
2145
2146 return ACT_RET_PRS_OK;
2147}
2148
Willy Tarreau7d562212016-11-25 16:10:05 +01002149/* set temp integer to the number of used entries in the table pointed to by expr.
2150 * Accepts exactly 1 argument of type table.
2151 */
2152static int
2153smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2154{
2155 smp->flags = SMP_F_VOL_TEST;
2156 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002157 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002158 return 1;
2159}
2160
2161/* set temp integer to the number of free entries in the table pointed to by expr.
2162 * Accepts exactly 1 argument of type table.
2163 */
2164static int
2165smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2166{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002167 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002168
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002169 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002170 smp->flags = SMP_F_VOL_TEST;
2171 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002172 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002173 return 1;
2174}
2175
2176/* Returns a pointer to a stkctr depending on the fetch keyword name.
2177 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2178 * sc[0-9]_* will return a pointer to the respective field in the
2179 * stream <l4>. sc_* requires an UINT argument specifying the stick
2180 * counter number. src_* will fill a locally allocated structure with
2181 * the table and entry corresponding to what is specified with src_*.
2182 * NULL may be returned if the designated stkctr is not tracked. For
2183 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2184 * passed. When present, the currently tracked key is then looked up
2185 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002186 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002187 * multiple tables). <strm> is allowed to be NULL, in which case only
2188 * the session will be consulted.
2189 */
2190struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002191smp_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 +01002192{
Willy Tarreau7d562212016-11-25 16:10:05 +01002193 struct stkctr *stkptr;
2194 struct stksess *stksess;
2195 unsigned int num = kw[2] - '0';
2196 int arg = 0;
2197
2198 if (num == '_' - '0') {
2199 /* sc_* variant, args[0] = ctr# (mandatory) */
2200 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002201 }
2202 else if (num > 9) { /* src_* variant, args[0] = table */
2203 struct stktable_key *key;
2204 struct connection *conn = objt_conn(sess->origin);
2205 struct sample smp;
2206
2207 if (!conn)
2208 return NULL;
2209
Joseph Herlant5662fa42018-11-15 13:43:28 -08002210 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002211 smp.px = NULL;
2212 smp.sess = sess;
2213 smp.strm = strm;
2214 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2215 return NULL;
2216
2217 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002218 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002219 if (!key)
2220 return NULL;
2221
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002222 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002223 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2224 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002225 }
2226
2227 /* Here, <num> contains the counter number from 0 to 9 for
2228 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2229 * args[arg] is the first optional argument. We first lookup the
2230 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002231 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002232 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002233 if (num >= MAX_SESS_STKCTR)
2234 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002235
2236 if (strm)
2237 stkptr = &strm->stkctr[num];
2238 if (!strm || !stkctr_entry(stkptr)) {
2239 stkptr = &sess->stkctr[num];
2240 if (!stkctr_entry(stkptr))
2241 return NULL;
2242 }
2243
2244 stksess = stkctr_entry(stkptr);
2245 if (!stksess)
2246 return NULL;
2247
2248 if (unlikely(args[arg].type == ARGT_TAB)) {
2249 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002250 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002251 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2252 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002253 }
2254 return stkptr;
2255}
2256
2257/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2258 * the entry if it doesn't exist yet. This is needed for a few fetch
2259 * functions which need to create an entry, such as src_inc_gpc* and
2260 * src_clr_gpc*.
2261 */
2262struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002263smp_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 +01002264{
Willy Tarreau7d562212016-11-25 16:10:05 +01002265 struct stktable_key *key;
2266 struct connection *conn = objt_conn(sess->origin);
2267 struct sample smp;
2268
2269 if (strncmp(kw, "src_", 4) != 0)
2270 return NULL;
2271
2272 if (!conn)
2273 return NULL;
2274
Joseph Herlant5662fa42018-11-15 13:43:28 -08002275 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002276 smp.px = NULL;
2277 smp.sess = sess;
2278 smp.strm = strm;
2279 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2280 return NULL;
2281
2282 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002283 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002284 if (!key)
2285 return NULL;
2286
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002287 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002288 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2289 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002290}
2291
2292/* set return a boolean indicating if the requested stream counter is
2293 * currently being tracked or not.
2294 * Supports being called as "sc[0-9]_tracked" only.
2295 */
2296static int
2297smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2298{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002299 struct stkctr tmpstkctr;
2300 struct stkctr *stkctr;
2301
Willy Tarreau7d562212016-11-25 16:10:05 +01002302 smp->flags = SMP_F_VOL_TEST;
2303 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002304 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2305 smp->data.u.sint = !!stkctr;
2306
2307 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002308 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002309 stktable_release(stkctr->table, stkctr_entry(stkctr));
2310
Willy Tarreau7d562212016-11-25 16:10:05 +01002311 return 1;
2312}
2313
2314/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2315 * frontend counters or from the src.
2316 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2317 * zero is returned if the key is new.
2318 */
2319static int
2320smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2321{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002322 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002323 struct stkctr *stkctr;
2324
Emeric Brun819fc6f2017-06-13 19:37:32 +02002325 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002326 if (!stkctr)
2327 return 0;
2328
2329 smp->flags = SMP_F_VOL_TEST;
2330 smp->data.type = SMP_T_SINT;
2331 smp->data.u.sint = 0;
2332
Emeric Brun819fc6f2017-06-13 19:37:32 +02002333 if (stkctr_entry(stkctr)) {
2334 void *ptr;
2335
2336 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2337 if (!ptr) {
2338 if (stkctr == &tmpstkctr)
2339 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002340 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002341 }
2342
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002343 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002344
Willy Tarreau7d562212016-11-25 16:10:05 +01002345 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002346
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002347 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002348
2349 if (stkctr == &tmpstkctr)
2350 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002351 }
2352 return 1;
2353}
2354
2355/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2356 * frontend counters or from the src.
2357 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2358 * zero is returned if the key is new.
2359 */
2360static int
2361smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2362{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002363 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002364 struct stkctr *stkctr;
2365
Emeric Brun819fc6f2017-06-13 19:37:32 +02002366 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002367 if (!stkctr)
2368 return 0;
2369
2370 smp->flags = SMP_F_VOL_TEST;
2371 smp->data.type = SMP_T_SINT;
2372 smp->data.u.sint = 0;
2373
2374 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002375 void *ptr;
2376
2377 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2378 if (!ptr) {
2379 if (stkctr == &tmpstkctr)
2380 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002381 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002382 }
2383
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002384 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002385
Willy Tarreau7d562212016-11-25 16:10:05 +01002386 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002387
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002388 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002389
2390 if (stkctr == &tmpstkctr)
2391 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002392 }
2393 return 1;
2394}
2395
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002396/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2397 * frontend counters or from the src.
2398 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2399 * zero is returned if the key is new.
2400 */
2401static int
2402smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2403{
2404 struct stkctr tmpstkctr;
2405 struct stkctr *stkctr;
2406
2407 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2408 if (!stkctr)
2409 return 0;
2410
2411 smp->flags = SMP_F_VOL_TEST;
2412 smp->data.type = SMP_T_SINT;
2413 smp->data.u.sint = 0;
2414
2415 if (stkctr_entry(stkctr) != NULL) {
2416 void *ptr;
2417
2418 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2419 if (!ptr) {
2420 if (stkctr == &tmpstkctr)
2421 stktable_release(stkctr->table, stkctr_entry(stkctr));
2422 return 0; /* parameter not stored */
2423 }
2424
2425 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2426
2427 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2428
2429 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2430
2431 if (stkctr == &tmpstkctr)
2432 stktable_release(stkctr->table, stkctr_entry(stkctr));
2433 }
2434 return 1;
2435}
2436
Willy Tarreau7d562212016-11-25 16:10:05 +01002437/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2438 * tracked frontend counters or from the src.
2439 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2440 * Value zero is returned if the key is new.
2441 */
2442static int
2443smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2444{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002445 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002446 struct stkctr *stkctr;
2447
Emeric Brun819fc6f2017-06-13 19:37:32 +02002448 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002449 if (!stkctr)
2450 return 0;
2451
2452 smp->flags = SMP_F_VOL_TEST;
2453 smp->data.type = SMP_T_SINT;
2454 smp->data.u.sint = 0;
2455 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002456 void *ptr;
2457
2458 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2459 if (!ptr) {
2460 if (stkctr == &tmpstkctr)
2461 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002462 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002463 }
2464
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002465 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002466
Willy Tarreau7d562212016-11-25 16:10:05 +01002467 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2468 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002469
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002470 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002471
2472 if (stkctr == &tmpstkctr)
2473 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002474 }
2475 return 1;
2476}
2477
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002478/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2479 * tracked frontend counters or from the src.
2480 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2481 * Value zero is returned if the key is new.
2482 */
2483static int
2484smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2485{
2486 struct stkctr tmpstkctr;
2487 struct stkctr *stkctr;
2488
2489 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2490 if (!stkctr)
2491 return 0;
2492
2493 smp->flags = SMP_F_VOL_TEST;
2494 smp->data.type = SMP_T_SINT;
2495 smp->data.u.sint = 0;
2496 if (stkctr_entry(stkctr) != NULL) {
2497 void *ptr;
2498
2499 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2500 if (!ptr) {
2501 if (stkctr == &tmpstkctr)
2502 stktable_release(stkctr->table, stkctr_entry(stkctr));
2503 return 0; /* parameter not stored */
2504 }
2505
2506 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2507
2508 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2509 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2510
2511 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2512
2513 if (stkctr == &tmpstkctr)
2514 stktable_release(stkctr->table, stkctr_entry(stkctr));
2515 }
2516 return 1;
2517}
2518
Willy Tarreau7d562212016-11-25 16:10:05 +01002519/* Increment the General Purpose Counter 0 value from the stream's tracked
2520 * frontend counters and return it into temp integer.
2521 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2522 */
2523static int
2524smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2525{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002526 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002527 struct stkctr *stkctr;
2528
Emeric Brun819fc6f2017-06-13 19:37:32 +02002529 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002530 if (!stkctr)
2531 return 0;
2532
2533 smp->flags = SMP_F_VOL_TEST;
2534 smp->data.type = SMP_T_SINT;
2535 smp->data.u.sint = 0;
2536
Emeric Brun819fc6f2017-06-13 19:37:32 +02002537 if (!stkctr_entry(stkctr))
2538 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002539
2540 if (stkctr && stkctr_entry(stkctr)) {
2541 void *ptr1,*ptr2;
2542
Emeric Brun819fc6f2017-06-13 19:37:32 +02002543
Willy Tarreau7d562212016-11-25 16:10:05 +01002544 /* First, update gpc0_rate if it's tracked. Second, update its
2545 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2546 */
2547 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002548 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002549 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002550 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002551
Emeric Brun819fc6f2017-06-13 19:37:32 +02002552 if (ptr1) {
2553 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2554 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2555 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2556 }
2557
2558 if (ptr2)
2559 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2560
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002561 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002562
2563 /* If data was modified, we need to touch to re-schedule sync */
2564 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2565 }
2566 else if (stkctr == &tmpstkctr)
2567 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002568 }
2569 return 1;
2570}
2571
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002572/* Increment the General Purpose Counter 1 value from the stream's tracked
2573 * frontend counters and return it into temp integer.
2574 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2575 */
2576static int
2577smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2578{
2579 struct stkctr tmpstkctr;
2580 struct stkctr *stkctr;
2581
2582 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2583 if (!stkctr)
2584 return 0;
2585
2586 smp->flags = SMP_F_VOL_TEST;
2587 smp->data.type = SMP_T_SINT;
2588 smp->data.u.sint = 0;
2589
2590 if (!stkctr_entry(stkctr))
2591 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2592
2593 if (stkctr && stkctr_entry(stkctr)) {
2594 void *ptr1,*ptr2;
2595
2596
2597 /* First, update gpc1_rate if it's tracked. Second, update its
2598 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2599 */
2600 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2601 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2602 if (ptr1 || ptr2) {
2603 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2604
2605 if (ptr1) {
2606 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2607 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2608 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2609 }
2610
2611 if (ptr2)
2612 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2613
2614 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2615
2616 /* If data was modified, we need to touch to re-schedule sync */
2617 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2618 }
2619 else if (stkctr == &tmpstkctr)
2620 stktable_release(stkctr->table, stkctr_entry(stkctr));
2621 }
2622 return 1;
2623}
2624
Willy Tarreau7d562212016-11-25 16:10:05 +01002625/* Clear the General Purpose Counter 0 value from the stream's tracked
2626 * frontend counters and return its previous value into temp integer.
2627 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2628 */
2629static int
2630smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2631{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002632 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002633 struct stkctr *stkctr;
2634
Emeric Brun819fc6f2017-06-13 19:37:32 +02002635 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002636 if (!stkctr)
2637 return 0;
2638
2639 smp->flags = SMP_F_VOL_TEST;
2640 smp->data.type = SMP_T_SINT;
2641 smp->data.u.sint = 0;
2642
Emeric Brun819fc6f2017-06-13 19:37:32 +02002643 if (!stkctr_entry(stkctr))
2644 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002645
Emeric Brun819fc6f2017-06-13 19:37:32 +02002646 if (stkctr && stkctr_entry(stkctr)) {
2647 void *ptr;
2648
2649 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2650 if (!ptr) {
2651 if (stkctr == &tmpstkctr)
2652 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002653 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002654 }
2655
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002656 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002657
Willy Tarreau7d562212016-11-25 16:10:05 +01002658 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2659 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002660
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002661 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662
Willy Tarreau7d562212016-11-25 16:10:05 +01002663 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002664 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002665 }
2666 return 1;
2667}
2668
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002669/* Clear the General Purpose Counter 1 value from the stream's tracked
2670 * frontend counters and return its previous value into temp integer.
2671 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2672 */
2673static int
2674smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2675{
2676 struct stkctr tmpstkctr;
2677 struct stkctr *stkctr;
2678
2679 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2680 if (!stkctr)
2681 return 0;
2682
2683 smp->flags = SMP_F_VOL_TEST;
2684 smp->data.type = SMP_T_SINT;
2685 smp->data.u.sint = 0;
2686
2687 if (!stkctr_entry(stkctr))
2688 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2689
2690 if (stkctr && stkctr_entry(stkctr)) {
2691 void *ptr;
2692
2693 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2694 if (!ptr) {
2695 if (stkctr == &tmpstkctr)
2696 stktable_release(stkctr->table, stkctr_entry(stkctr));
2697 return 0; /* parameter not stored */
2698 }
2699
2700 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2701
2702 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2703 stktable_data_cast(ptr, gpc1) = 0;
2704
2705 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2706
2707 /* If data was modified, we need to touch to re-schedule sync */
2708 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2709 }
2710 return 1;
2711}
2712
Willy Tarreau7d562212016-11-25 16:10:05 +01002713/* set <smp> to the cumulated number of connections from the stream's tracked
2714 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2715 * "src_conn_cnt" only.
2716 */
2717static int
2718smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2719{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002720 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002721 struct stkctr *stkctr;
2722
Emeric Brun819fc6f2017-06-13 19:37:32 +02002723 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002724 if (!stkctr)
2725 return 0;
2726
2727 smp->flags = SMP_F_VOL_TEST;
2728 smp->data.type = SMP_T_SINT;
2729 smp->data.u.sint = 0;
2730 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002731 void *ptr;
2732
2733 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2734 if (!ptr) {
2735 if (stkctr == &tmpstkctr)
2736 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002737 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002738 }
2739
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002740 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002741
Willy Tarreau7d562212016-11-25 16:10:05 +01002742 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002743
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002744 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002745
2746 if (stkctr == &tmpstkctr)
2747 stktable_release(stkctr->table, stkctr_entry(stkctr));
2748
2749
Willy Tarreau7d562212016-11-25 16:10:05 +01002750 }
2751 return 1;
2752}
2753
2754/* set <smp> to the connection rate from the stream's tracked frontend
2755 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2756 * only.
2757 */
2758static int
2759smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2760{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002761 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002762 struct stkctr *stkctr;
2763
Emeric Brun819fc6f2017-06-13 19:37:32 +02002764 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002765 if (!stkctr)
2766 return 0;
2767
2768 smp->flags = SMP_F_VOL_TEST;
2769 smp->data.type = SMP_T_SINT;
2770 smp->data.u.sint = 0;
2771 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002772 void *ptr;
2773
2774 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2775 if (!ptr) {
2776 if (stkctr == &tmpstkctr)
2777 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002778 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002779 }
2780
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002781 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002782
Willy Tarreau7d562212016-11-25 16:10:05 +01002783 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2784 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002785
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002786 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002787
2788 if (stkctr == &tmpstkctr)
2789 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002790 }
2791 return 1;
2792}
2793
2794/* set temp integer to the number of connections from the stream's source address
2795 * in the table pointed to by expr, after updating it.
2796 * Accepts exactly 1 argument of type table.
2797 */
2798static int
2799smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2800{
2801 struct connection *conn = objt_conn(smp->sess->origin);
2802 struct stksess *ts;
2803 struct stktable_key *key;
2804 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002805 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002806
2807 if (!conn)
2808 return 0;
2809
Joseph Herlant5662fa42018-11-15 13:43:28 -08002810 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002811 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2812 return 0;
2813
2814 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002815 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002816 if (!key)
2817 return 0;
2818
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002819 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002820
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002821 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002822 /* entry does not exist and could not be created */
2823 return 0;
2824
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002825 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002826 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002827 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002828 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002829
2830 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002831
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002832 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833
Willy Tarreau7d562212016-11-25 16:10:05 +01002834 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002836 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002837
Willy Tarreau7d562212016-11-25 16:10:05 +01002838 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002839
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002840 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002841
2842 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002843 return 1;
2844}
2845
2846/* set <smp> to the number of concurrent connections from the stream's tracked
2847 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2848 * "src_conn_cur" only.
2849 */
2850static int
2851smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2852{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002853 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002854 struct stkctr *stkctr;
2855
Emeric Brun819fc6f2017-06-13 19:37:32 +02002856 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002857 if (!stkctr)
2858 return 0;
2859
2860 smp->flags = SMP_F_VOL_TEST;
2861 smp->data.type = SMP_T_SINT;
2862 smp->data.u.sint = 0;
2863 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002864 void *ptr;
2865
2866 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2867 if (!ptr) {
2868 if (stkctr == &tmpstkctr)
2869 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002870 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002871 }
2872
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002873 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002874
Willy Tarreau7d562212016-11-25 16:10:05 +01002875 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002876
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002877 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002878
2879 if (stkctr == &tmpstkctr)
2880 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002881 }
2882 return 1;
2883}
2884
2885/* set <smp> to the cumulated number of streams from the stream's tracked
2886 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2887 * "src_sess_cnt" only.
2888 */
2889static int
2890smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2891{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002893 struct stkctr *stkctr;
2894
Emeric Brun819fc6f2017-06-13 19:37:32 +02002895 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002896 if (!stkctr)
2897 return 0;
2898
2899 smp->flags = SMP_F_VOL_TEST;
2900 smp->data.type = SMP_T_SINT;
2901 smp->data.u.sint = 0;
2902 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002903 void *ptr;
2904
2905 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2906 if (!ptr) {
2907 if (stkctr == &tmpstkctr)
2908 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002909 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002910 }
2911
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002912 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002913
Willy Tarreau7d562212016-11-25 16:10:05 +01002914 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002915
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002916 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002917
2918 if (stkctr == &tmpstkctr)
2919 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002920 }
2921 return 1;
2922}
2923
2924/* set <smp> to the stream rate from the stream's tracked frontend counters.
2925 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2926 */
2927static int
2928smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2929{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002930 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002931 struct stkctr *stkctr;
2932
Emeric Brun819fc6f2017-06-13 19:37:32 +02002933 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002934 if (!stkctr)
2935 return 0;
2936
2937 smp->flags = SMP_F_VOL_TEST;
2938 smp->data.type = SMP_T_SINT;
2939 smp->data.u.sint = 0;
2940 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002941 void *ptr;
2942
2943 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2944 if (!ptr) {
2945 if (stkctr == &tmpstkctr)
2946 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002947 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002948 }
2949
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002950 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002951
Willy Tarreau7d562212016-11-25 16:10:05 +01002952 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2953 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002954
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002955 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956
2957 if (stkctr == &tmpstkctr)
2958 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002959 }
2960 return 1;
2961}
2962
2963/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2964 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2965 * "src_http_req_cnt" only.
2966 */
2967static int
2968smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2969{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002970 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002971 struct stkctr *stkctr;
2972
Emeric Brun819fc6f2017-06-13 19:37:32 +02002973 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002974 if (!stkctr)
2975 return 0;
2976
2977 smp->flags = SMP_F_VOL_TEST;
2978 smp->data.type = SMP_T_SINT;
2979 smp->data.u.sint = 0;
2980 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981 void *ptr;
2982
2983 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2984 if (!ptr) {
2985 if (stkctr == &tmpstkctr)
2986 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002987 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002988 }
2989
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002990 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002991
Willy Tarreau7d562212016-11-25 16:10:05 +01002992 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002993
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002994 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995
2996 if (stkctr == &tmpstkctr)
2997 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002998 }
2999 return 1;
3000}
3001
3002/* set <smp> to the HTTP request rate from the stream's tracked frontend
3003 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3004 * "src_http_req_rate" only.
3005 */
3006static int
3007smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3008{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003009 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003010 struct stkctr *stkctr;
3011
Emeric Brun819fc6f2017-06-13 19:37:32 +02003012 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003013 if (!stkctr)
3014 return 0;
3015
3016 smp->flags = SMP_F_VOL_TEST;
3017 smp->data.type = SMP_T_SINT;
3018 smp->data.u.sint = 0;
3019 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003020 void *ptr;
3021
3022 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3023 if (!ptr) {
3024 if (stkctr == &tmpstkctr)
3025 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003026 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003027 }
3028
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003029 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003030
Willy Tarreau7d562212016-11-25 16:10:05 +01003031 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3032 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003033
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003034 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003035
3036 if (stkctr == &tmpstkctr)
3037 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003038 }
3039 return 1;
3040}
3041
3042/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3043 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3044 * "src_http_err_cnt" only.
3045 */
3046static int
3047smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3048{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003049 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003050 struct stkctr *stkctr;
3051
Emeric Brun819fc6f2017-06-13 19:37:32 +02003052 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003053 if (!stkctr)
3054 return 0;
3055
3056 smp->flags = SMP_F_VOL_TEST;
3057 smp->data.type = SMP_T_SINT;
3058 smp->data.u.sint = 0;
3059 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003060 void *ptr;
3061
3062 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3063 if (!ptr) {
3064 if (stkctr == &tmpstkctr)
3065 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003066 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003067 }
3068
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003069 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003070
Willy Tarreau7d562212016-11-25 16:10:05 +01003071 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003072
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003073 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003074
3075 if (stkctr == &tmpstkctr)
3076 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003077 }
3078 return 1;
3079}
3080
3081/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3082 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3083 * "src_http_err_rate" only.
3084 */
3085static int
3086smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3087{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003088 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003089 struct stkctr *stkctr;
3090
Emeric Brun819fc6f2017-06-13 19:37:32 +02003091 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003092 if (!stkctr)
3093 return 0;
3094
3095 smp->flags = SMP_F_VOL_TEST;
3096 smp->data.type = SMP_T_SINT;
3097 smp->data.u.sint = 0;
3098 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003099 void *ptr;
3100
3101 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3102 if (!ptr) {
3103 if (stkctr == &tmpstkctr)
3104 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003105 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003106 }
3107
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003108 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003109
Willy Tarreau7d562212016-11-25 16:10:05 +01003110 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3111 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003112
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003113 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114
3115 if (stkctr == &tmpstkctr)
3116 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003117 }
3118 return 1;
3119}
3120
3121/* set <smp> to the number of kbytes received from clients, as found in the
3122 * stream's tracked frontend counters. Supports being called as
3123 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3124 */
3125static int
3126smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3127{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003128 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003129 struct stkctr *stkctr;
3130
Emeric Brun819fc6f2017-06-13 19:37:32 +02003131 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003132 if (!stkctr)
3133 return 0;
3134
3135 smp->flags = SMP_F_VOL_TEST;
3136 smp->data.type = SMP_T_SINT;
3137 smp->data.u.sint = 0;
3138 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003139 void *ptr;
3140
3141 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3142 if (!ptr) {
3143 if (stkctr == &tmpstkctr)
3144 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003145 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146 }
3147
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003148 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003149
Willy Tarreau7d562212016-11-25 16:10:05 +01003150 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003151
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003152 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003153
3154 if (stkctr == &tmpstkctr)
3155 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003156 }
3157 return 1;
3158}
3159
3160/* set <smp> to the data rate received from clients in bytes/s, as found
3161 * in the stream's tracked frontend counters. Supports being called as
3162 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3163 */
3164static int
3165smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3166{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003167 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003168 struct stkctr *stkctr;
3169
Emeric Brun819fc6f2017-06-13 19:37:32 +02003170 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003171 if (!stkctr)
3172 return 0;
3173
3174 smp->flags = SMP_F_VOL_TEST;
3175 smp->data.type = SMP_T_SINT;
3176 smp->data.u.sint = 0;
3177 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178 void *ptr;
3179
3180 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3181 if (!ptr) {
3182 if (stkctr == &tmpstkctr)
3183 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003184 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003185 }
3186
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003187 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003188
Willy Tarreau7d562212016-11-25 16:10:05 +01003189 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3190 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003191
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003192 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003193
3194 if (stkctr == &tmpstkctr)
3195 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003196 }
3197 return 1;
3198}
3199
3200/* set <smp> to the number of kbytes sent to clients, as found in the
3201 * stream's tracked frontend counters. Supports being called as
3202 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3203 */
3204static int
3205smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3206{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003207 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003208 struct stkctr *stkctr;
3209
Emeric Brun819fc6f2017-06-13 19:37:32 +02003210 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003211 if (!stkctr)
3212 return 0;
3213
3214 smp->flags = SMP_F_VOL_TEST;
3215 smp->data.type = SMP_T_SINT;
3216 smp->data.u.sint = 0;
3217 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003218 void *ptr;
3219
3220 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3221 if (!ptr) {
3222 if (stkctr == &tmpstkctr)
3223 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003224 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225 }
3226
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003227 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228
Willy Tarreau7d562212016-11-25 16:10:05 +01003229 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003231 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003232
3233 if (stkctr == &tmpstkctr)
3234 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003235 }
3236 return 1;
3237}
3238
3239/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3240 * stream's tracked frontend counters. Supports being called as
3241 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3242 */
3243static int
3244smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3245{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003246 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003247 struct stkctr *stkctr;
3248
Emeric Brun819fc6f2017-06-13 19:37:32 +02003249 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003250 if (!stkctr)
3251 return 0;
3252
3253 smp->flags = SMP_F_VOL_TEST;
3254 smp->data.type = SMP_T_SINT;
3255 smp->data.u.sint = 0;
3256 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003257 void *ptr;
3258
3259 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3260 if (!ptr) {
3261 if (stkctr == &tmpstkctr)
3262 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003263 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003264 }
3265
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003266 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003267
Willy Tarreau7d562212016-11-25 16:10:05 +01003268 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3269 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003270
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003271 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003272
3273 if (stkctr == &tmpstkctr)
3274 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003275 }
3276 return 1;
3277}
3278
3279/* set <smp> to the number of active trackers on the SC entry in the stream's
3280 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3281 */
3282static int
3283smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3284{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003285 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003286 struct stkctr *stkctr;
3287
Emeric Brun819fc6f2017-06-13 19:37:32 +02003288 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003289 if (!stkctr)
3290 return 0;
3291
3292 smp->flags = SMP_F_VOL_TEST;
3293 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003294 if (stkctr == &tmpstkctr) {
3295 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3296 stktable_release(stkctr->table, stkctr_entry(stkctr));
3297 }
3298 else {
3299 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3300 }
3301
Willy Tarreau7d562212016-11-25 16:10:05 +01003302 return 1;
3303}
3304
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003305
3306/* The functions below are used to manipulate table contents from the CLI.
3307 * There are 3 main actions, "clear", "set" and "show". The code is shared
3308 * between all actions, and the action is encoded in the void *private in
3309 * the appctx as well as in the keyword registration, among one of the
3310 * following values.
3311 */
3312
3313enum {
3314 STK_CLI_ACT_CLR,
3315 STK_CLI_ACT_SET,
3316 STK_CLI_ACT_SHOW,
3317};
3318
3319/* Dump the status of a table to a stream interface's
3320 * read buffer. It returns 0 if the output buffer is full
3321 * and needs to be called again, otherwise non-zero.
3322 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003323static int table_dump_head_to_buffer(struct buffer *msg,
3324 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003325 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003326{
3327 struct stream *s = si_strm(si);
3328
3329 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003330 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003331
3332 /* any other information should be dumped here */
3333
William Lallemand07a62f72017-05-24 00:57:40 +02003334 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003335 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3336
Willy Tarreau06d80a92017-10-19 14:32:15 +02003337 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003338 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003339 return 0;
3340 }
3341
3342 return 1;
3343}
3344
3345/* Dump a table entry to a stream interface's
3346 * read buffer. It returns 0 if the output buffer is full
3347 * and needs to be called again, otherwise non-zero.
3348 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003349static int table_dump_entry_to_buffer(struct buffer *msg,
3350 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003351 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003352{
3353 int dt;
3354
3355 chunk_appendf(msg, "%p:", entry);
3356
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003357 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003358 char addr[INET_ADDRSTRLEN];
3359 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3360 chunk_appendf(msg, " key=%s", addr);
3361 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003362 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003363 char addr[INET6_ADDRSTRLEN];
3364 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3365 chunk_appendf(msg, " key=%s", addr);
3366 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003367 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003368 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003369 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003370 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003371 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003372 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003373 }
3374 else {
3375 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003376 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003377 }
3378
3379 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3380
3381 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3382 void *ptr;
3383
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003384 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003385 continue;
3386 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003387 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003388 else
3389 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3390
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003391 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003392 switch (stktable_data_types[dt].std_type) {
3393 case STD_T_SINT:
3394 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3395 break;
3396 case STD_T_UINT:
3397 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3398 break;
3399 case STD_T_ULL:
3400 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3401 break;
3402 case STD_T_FRQP:
3403 chunk_appendf(msg, "%d",
3404 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003405 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003406 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003407 case STD_T_DICT: {
3408 struct dict_entry *de;
3409 de = stktable_data_cast(ptr, std_t_dict);
3410 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3411 break;
3412 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003413 }
3414 }
3415 chunk_appendf(msg, "\n");
3416
Willy Tarreau06d80a92017-10-19 14:32:15 +02003417 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003418 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003419 return 0;
3420 }
3421
3422 return 1;
3423}
3424
3425
3426/* Processes a single table entry matching a specific key passed in argument.
3427 * returns 0 if wants to be called again, 1 if has ended processing.
3428 */
3429static int table_process_entry_per_key(struct appctx *appctx, char **args)
3430{
3431 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003432 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003433 struct stksess *ts;
3434 uint32_t uint32_key;
3435 unsigned char ip6_key[sizeof(struct in6_addr)];
3436 long long value;
3437 int data_type;
3438 int cur_arg;
3439 void *ptr;
3440 struct freq_ctr_period *frqp;
3441
Willy Tarreau9d008692019-08-09 11:21:01 +02003442 if (!*args[4])
3443 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003444
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003445 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003446 case SMP_T_IPV4:
3447 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003448 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003449 break;
3450 case SMP_T_IPV6:
3451 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003452 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003453 break;
3454 case SMP_T_SINT:
3455 {
3456 char *endptr;
3457 unsigned long val;
3458 errno = 0;
3459 val = strtoul(args[4], &endptr, 10);
3460 if ((errno == ERANGE && val == ULONG_MAX) ||
3461 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003462 val > 0xffffffff)
3463 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003464 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003465 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003466 break;
3467 }
3468 break;
3469 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003470 static_table_key.key = args[4];
3471 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003472 break;
3473 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003474 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003475 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003476 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 +01003477 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003478 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 +01003479 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003480 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 +01003481 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003482 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003483 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003484 }
3485
3486 /* check permissions */
3487 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3488 return 1;
3489
Willy Tarreaua24bc782016-12-14 15:50:35 +01003490 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003491 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003492 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003493 if (!ts)
3494 return 1;
3495 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003496 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3497 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003498 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003499 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003500 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003501 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003502 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003503 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003504 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003505 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003506 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003507 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003508 break;
3509
3510 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003511 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003512 if (!ts)
3513 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003514
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003515 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003516 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003517 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003518 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003519 break;
3520
3521 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003522 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003523 if (!ts) {
3524 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003525 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003526 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003527 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003528 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3529 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003530 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003531 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003532 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003533 return 1;
3534 }
3535
3536 data_type = stktable_get_data_type(args[cur_arg] + 5);
3537 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003538 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003539 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003540 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003541 return 1;
3542 }
3543
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003544 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003545 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003546 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003547 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003548 return 1;
3549 }
3550
3551 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003552 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003553 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003554 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003555 return 1;
3556 }
3557
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003558 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003559
3560 switch (stktable_data_types[data_type].std_type) {
3561 case STD_T_SINT:
3562 stktable_data_cast(ptr, std_t_sint) = value;
3563 break;
3564 case STD_T_UINT:
3565 stktable_data_cast(ptr, std_t_uint) = value;
3566 break;
3567 case STD_T_ULL:
3568 stktable_data_cast(ptr, std_t_ull) = value;
3569 break;
3570 case STD_T_FRQP:
3571 /* We set both the current and previous values. That way
3572 * the reported frequency is stable during all the period
3573 * then slowly fades out. This allows external tools to
3574 * push measures without having to update them too often.
3575 */
3576 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003577 /* First bit is reserved for the freq_ctr_period lock
3578 Note: here we're still protected by the stksess lock
3579 so we don't need to update the update the freq_ctr_period
3580 using its internal lock */
3581 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003582 frqp->prev_ctr = 0;
3583 frqp->curr_ctr = value;
3584 break;
3585 }
3586 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003587 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003588 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003589 break;
3590
3591 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003592 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003593 }
3594 return 1;
3595}
3596
3597/* Prepares the appctx fields with the data-based filters from the command line.
3598 * Returns 0 if the dump can proceed, 1 if has ended processing.
3599 */
3600static int table_prepare_data_request(struct appctx *appctx, char **args)
3601{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003602 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003603 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003604
Willy Tarreau9d008692019-08-09 11:21:01 +02003605 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3606 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003607
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003608 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3609 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3610 break;
3611 /* condition on stored data value */
3612 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3613 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003614 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003615
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003616 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003617 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 +01003618
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003619 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003620 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003621 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 +01003622
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003623 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 +01003624 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3625 }
3626
3627 if (*args[3+3*i]) {
3628 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 +01003629 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003630
3631 /* OK we're done, all the fields are set */
3632 return 0;
3633}
3634
3635/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003636static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003637{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003638 int i;
3639
3640 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3641 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003642 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003644 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003645
3646 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003647 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003648 if (!appctx->ctx.table.target)
3649 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003650 }
3651 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003652 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003653 goto err_args;
3654 return 0;
3655 }
3656
3657 if (strcmp(args[3], "key") == 0)
3658 return table_process_entry_per_key(appctx, args);
3659 else if (strncmp(args[3], "data.", 5) == 0)
3660 return table_prepare_data_request(appctx, args);
3661 else if (*args[3])
3662 goto err_args;
3663
3664 return 0;
3665
3666err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003667 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003668 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003669 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 +01003670 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003671 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 +01003672 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003673 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003674 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003675 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003676 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003677}
3678
3679/* This function is used to deal with table operations (dump or clear depending
3680 * on the action stored in appctx->private). It returns 0 if the output buffer is
3681 * full and it needs to be called again, otherwise non-zero.
3682 */
3683static int cli_io_handler_table(struct appctx *appctx)
3684{
3685 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003686 struct stream *s = si_strm(si);
3687 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003688 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003689 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003690
3691 /*
3692 * We have 3 possible states in appctx->st2 :
3693 * - STAT_ST_INIT : the first call
3694 * - STAT_ST_INFO : the proxy pointer points to the next table to
3695 * dump, the entry pointer is NULL ;
3696 * - STAT_ST_LIST : the proxy pointer points to the current table
3697 * and the entry pointer points to the next entry to be dumped,
3698 * and the refcount on the next entry is held ;
3699 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3700 * data though.
3701 */
3702
3703 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3704 /* in case of abort, remove any refcount we might have set on an entry */
3705 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003706 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003707 }
3708 return 1;
3709 }
3710
3711 chunk_reset(&trash);
3712
3713 while (appctx->st2 != STAT_ST_FIN) {
3714 switch (appctx->st2) {
3715 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003716 appctx->ctx.table.t = appctx->ctx.table.target;
3717 if (!appctx->ctx.table.t)
3718 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003719
3720 appctx->ctx.table.entry = NULL;
3721 appctx->st2 = STAT_ST_INFO;
3722 break;
3723
3724 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003725 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003726 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003727 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003728 appctx->st2 = STAT_ST_END;
3729 break;
3730 }
3731
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003732 if (appctx->ctx.table.t->size) {
3733 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003734 return 0;
3735
3736 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003737 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003738 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003739 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3740 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003741 if (eb) {
3742 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3743 appctx->ctx.table.entry->ref_cnt++;
3744 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003745 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003746 break;
3747 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003748 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003749 }
3750 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003751 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003752 break;
3753
3754 case STAT_ST_LIST:
3755 skip_entry = 0;
3756
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003757 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003758
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003759 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003760 /* we're filtering on some data contents */
3761 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003762 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003763 signed char op;
3764 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003765
Emeric Brun819fc6f2017-06-13 19:37:32 +02003766
Willy Tarreau2b64a352020-01-22 17:09:47 +01003767 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003768 if (appctx->ctx.table.data_type[i] == -1)
3769 break;
3770 dt = appctx->ctx.table.data_type[i];
3771 ptr = stktable_data_ptr(appctx->ctx.table.t,
3772 appctx->ctx.table.entry,
3773 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003774
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003775 data = 0;
3776 switch (stktable_data_types[dt].std_type) {
3777 case STD_T_SINT:
3778 data = stktable_data_cast(ptr, std_t_sint);
3779 break;
3780 case STD_T_UINT:
3781 data = stktable_data_cast(ptr, std_t_uint);
3782 break;
3783 case STD_T_ULL:
3784 data = stktable_data_cast(ptr, std_t_ull);
3785 break;
3786 case STD_T_FRQP:
3787 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3788 appctx->ctx.table.t->data_arg[dt].u);
3789 break;
3790 }
3791
3792 op = appctx->ctx.table.data_op[i];
3793 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003794
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003795 /* skip the entry if the data does not match the test and the value */
3796 if ((data < value &&
3797 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3798 (data == value &&
3799 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3800 (data > value &&
3801 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3802 skip_entry = 1;
3803 break;
3804 }
3805 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003806 }
3807
3808 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003809 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003810 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003811 return 0;
3812 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003813
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003814 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003815
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003816 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003817 appctx->ctx.table.entry->ref_cnt--;
3818
3819 eb = ebmb_next(&appctx->ctx.table.entry->key);
3820 if (eb) {
3821 struct stksess *old = appctx->ctx.table.entry;
3822 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3823 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003824 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003825 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003826 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003827 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003828 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003829 break;
3830 }
3831
3832
3833 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003834 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003835 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003836 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003837
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003838 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003839
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003840 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003841 appctx->st2 = STAT_ST_INFO;
3842 break;
3843
3844 case STAT_ST_END:
3845 appctx->st2 = STAT_ST_FIN;
3846 break;
3847 }
3848 }
3849 return 1;
3850}
3851
3852static void cli_release_show_table(struct appctx *appctx)
3853{
3854 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003855 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003856 }
3857}
3858
3859/* register cli keywords */
3860static struct cli_kw_list cli_kws = {{ },{
3861 { { "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 },
3862 { { "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 },
3863 { { "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 },
3864 {{},}
3865}};
3866
Willy Tarreau0108d902018-11-25 19:14:37 +01003867INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003868
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003869static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003870 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003871 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003872 { "sc-set-gpt0", parse_set_gpt0, 1 },
3873 { /* END */ }
3874}};
3875
Willy Tarreau0108d902018-11-25 19:14:37 +01003876INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3877
Willy Tarreau620408f2016-10-21 16:37:51 +02003878static struct action_kw_list tcp_sess_kws = { { }, {
3879 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003880 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003881 { "sc-set-gpt0", parse_set_gpt0, 1 },
3882 { /* END */ }
3883}};
3884
Willy Tarreau0108d902018-11-25 19:14:37 +01003885INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3886
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003887static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003888 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003889 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003890 { "sc-set-gpt0", parse_set_gpt0, 1 },
3891 { /* END */ }
3892}};
3893
Willy Tarreau0108d902018-11-25 19:14:37 +01003894INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3895
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003896static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003897 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003898 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003899 { "sc-set-gpt0", parse_set_gpt0, 1 },
3900 { /* END */ }
3901}};
3902
Willy Tarreau0108d902018-11-25 19:14:37 +01003903INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3904
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003905static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003906 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003907 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003908 { "sc-set-gpt0", parse_set_gpt0, 1 },
3909 { /* END */ }
3910}};
3911
Willy Tarreau0108d902018-11-25 19:14:37 +01003912INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3913
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003914static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003915 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003916 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003917 { "sc-set-gpt0", parse_set_gpt0, 1 },
3918 { /* END */ }
3919}};
3920
Willy Tarreau0108d902018-11-25 19:14:37 +01003921INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3922
Willy Tarreau7d562212016-11-25 16:10:05 +01003923///* Note: must not be declared <const> as its list will be overwritten.
3924// * Please take care of keeping this list alphabetically sorted.
3925// */
3926//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3927// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3928// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3929// { /* END */ },
3930//}};
3931/* Note: must not be declared <const> as its list will be overwritten.
3932 * Please take care of keeping this list alphabetically sorted.
3933 */
3934static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3935 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3936 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3937 { "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 +01003938 { "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 +01003939 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3940 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3941 { "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 +01003942 { "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 +01003943 { "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 +01003944 { "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 +01003945 { "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 +01003946 { "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 +01003947 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3948 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3949 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3950 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3951 { "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 +01003952 { "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 +01003953 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3954 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3955 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3956 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3957 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3958 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3959 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3960 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3961 { "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 +01003962 { "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 +01003963 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3964 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3965 { "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 +01003966 { "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 +01003967 { "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 +01003968 { "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 +01003969 { "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 +01003970 { "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 +01003971 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3972 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3973 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3974 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3975 { "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 +01003976 { "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 +01003977 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3978 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3979 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3980 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3981 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3982 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3984 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3985 { "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 +01003986 { "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 +01003987 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3988 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3989 { "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 +01003990 { "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 +01003991 { "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 +01003992 { "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 +01003993 { "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 +01003994 { "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 +01003995 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3996 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3997 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3998 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3999 { "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 +01004000 { "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 +01004001 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4002 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4003 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4004 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4005 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4006 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4007 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4008 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4009 { "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 +01004010 { "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 +01004011 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4012 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4013 { "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 +01004014 { "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 +01004015 { "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 +01004016 { "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 +01004017 { "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 +01004018 { "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 +01004019 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4020 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4021 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4022 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4023 { "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 +01004024 { "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 +01004025 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4026 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4027 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4028 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4029 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4030 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4031 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4032 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4033 { "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 +01004034 { "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 +01004035 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4036 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4037 { "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 +01004038 { "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 +01004039 { "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 +01004040 { "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 +01004041 { "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 +01004042 { "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 +01004043 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4044 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4045 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4046 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4047 { "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 +01004048 { "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 +01004049 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4050 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4051 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4052 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4053 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4054 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4055 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4056 { /* END */ },
4057}};
4058
Willy Tarreau0108d902018-11-25 19:14:37 +01004059INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004060
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004061/* Note: must not be declared <const> as its list will be overwritten */
4062static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004063 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4064 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4065 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4066 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4067 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4068 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4069 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4070 { "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 +01004071 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004072 { "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 +01004073 { "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 +02004074 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4075 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4076 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4077 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4078 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4079 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4080 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4081 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4082 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4083 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004084 { /* END */ },
4085}};
4086
Willy Tarreau0108d902018-11-25 19:14:37 +01004087INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);