blob: fdf1b585ad04794e0e5159fdd636cd958e56671c [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020017#include <haproxy/api.h>
Frédéric Lécailled456aa42019-03-08 14:47:00 +010018#include <common/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020019#include <haproxy/cli.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020020#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020021#include <haproxy/http_rules.h>
Willy Tarreaud0ef4392020-06-02 09:38:52 +020022#include <haproxy/pool.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020023#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020024#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020025#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020026#include <haproxy/peers.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020027#include <haproxy/stats-t.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020028#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020029#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020030#include <haproxy/tcp_rules.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020031#include <haproxy/tools.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020032#include <haproxy/time.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010033
Willy Tarreau8d2b7772020-05-27 10:58:19 +020034#include <import/ebmbtree.h>
35#include <import/ebsttree.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010036
Willy Tarreauaa74c4e2020-06-04 10:19:23 +020037#include <haproxy/arg.h>
Willy Tarreaufc774542020-06-04 17:31:04 +020038#include <haproxy/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010039#include <proto/proxy.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020040#include <haproxy/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020041#include <proto/stream.h>
Willy Tarreau872f2ea2020-06-04 18:46:44 +020042#include <haproxy/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010043
Willy Tarreau12785782012-04-27 21:37:17 +020044/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020045static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020046
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010047struct stktable *stktables_list;
48struct eb_root stktable_by_name = EB_ROOT;
49
Olivier Houchard52dabbc2018-11-14 17:54:36 +010050#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010051
52/* This function inserts stktable <t> into the tree of known stick-table.
53 * The stick-table ID is used as the storing key so it must already have
54 * been initialized.
55 */
56void stktable_store_name(struct stktable *t)
57{
58 t->name.key = t->id;
59 ebis_insert(&stktable_by_name, &t->name);
60}
61
62struct stktable *stktable_find_by_name(const char *name)
63{
64 struct ebpt_node *node;
65 struct stktable *t;
66
67 node = ebis_lookup(&stktable_by_name, name);
68 if (node) {
69 t = container_of(node, struct stktable, name);
70 if (!strcmp(t->id, name))
71 return t;
72 }
73
74 return NULL;
75}
76
Emeric Brun3bd697e2010-01-04 15:23:48 +010077/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020078 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
79 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010080 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020081void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010082{
83 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010084 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010085}
86
87/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020088 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
89 * in table <t>.
90 * This function locks the table
91 */
92void stksess_free(struct stktable *t, struct stksess *ts)
93{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010094 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020095 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010096 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020097}
98
99/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200100 * Kill an stksess (only if its ref_cnt is zero).
101 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200102int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200103{
104 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200105 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200106
107 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200108 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200109 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200110 __stksess_free(t, ts);
111 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200112}
113
114/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200115 * Decrease the refcount if decrefcnt is not 0.
116 * and try to kill the stksess
117 * This function locks the table
118 */
119int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
120{
121 int ret;
122
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100123 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200124 if (decrefcnt)
125 ts->ref_cnt--;
126 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100127 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200128
129 return ret;
130}
131
132/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200133 * Initialize or update the key in the sticky session <ts> present in table <t>
134 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100135 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200136void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100137{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200138 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200139 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100140 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200141 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
142 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100143 }
144}
145
146
147/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200148 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
149 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100150 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200151static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100152{
Willy Tarreau393379c2010-06-06 12:11:37 +0200153 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200154 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200155 ts->key.node.leaf_p = NULL;
156 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200157 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200158 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100159 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100160 return ts;
161}
162
163/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200164 * Trash oldest <to_batch> sticky sessions from table <t>
165 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100166 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200167int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100168{
169 struct stksess *ts;
170 struct eb32_node *eb;
171 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200172 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100173
174 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
175
176 while (batched < to_batch) {
177
178 if (unlikely(!eb)) {
179 /* we might have reached the end of the tree, typically because
180 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200181 * half. Let's loop back to the beginning of the tree now if we
182 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100183 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200184 if (looped)
185 break;
186 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100187 eb = eb32_first(&t->exps);
188 if (likely(!eb))
189 break;
190 }
191
192 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200193 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100194 eb = eb32_next(eb);
195
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200196 /* don't delete an entry which is currently referenced */
197 if (ts->ref_cnt)
198 continue;
199
Willy Tarreau86257dc2010-06-06 12:57:10 +0200200 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100201
Willy Tarreau86257dc2010-06-06 12:57:10 +0200202 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100203 if (!tick_isset(ts->expire))
204 continue;
205
Willy Tarreau86257dc2010-06-06 12:57:10 +0200206 ts->exp.key = ts->expire;
207 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100208
Willy Tarreau86257dc2010-06-06 12:57:10 +0200209 if (!eb || eb->key > ts->exp.key)
210 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100211
212 continue;
213 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100214
Willy Tarreauaea940e2010-06-06 11:56:36 +0200215 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200216 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200217 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200218 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219 batched++;
220 }
221
222 return batched;
223}
224
225/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200226 * Trash oldest <to_batch> sticky sessions from table <t>
227 * Returns number of trashed sticky sessions.
228 * This function locks the table
229 */
230int stktable_trash_oldest(struct stktable *t, int to_batch)
231{
232 int ret;
233
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100234 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200235 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100236 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200237
238 return ret;
239}
240/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200241 * Allocate and initialise a new sticky session.
242 * The new sticky session is returned or NULL in case of lack of memory.
243 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200244 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
245 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100246 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200247struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100248{
249 struct stksess *ts;
250
251 if (unlikely(t->current == t->size)) {
252 if ( t->nopurge )
253 return NULL;
254
Emeric Brun819fc6f2017-06-13 19:37:32 +0200255 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100256 return NULL;
257 }
258
Willy Tarreaubafbe012017-11-24 17:34:44 +0100259 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100260 if (ts) {
261 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100262 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200263 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200264 if (key)
265 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100266 }
267
268 return ts;
269}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200270/*
271 * Allocate and initialise a new sticky session.
272 * The new sticky session is returned or NULL in case of lack of memory.
273 * Sticky sessions should only be allocated this way, and must be freed using
274 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
275 * is not NULL, it is assigned to the new session.
276 * This function locks the table
277 */
278struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
279{
280 struct stksess *ts;
281
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100282 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200283 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100284 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200285
286 return ts;
287}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100288
289/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200290 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200291 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100292 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200293struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100294{
295 struct ebmb_node *eb;
296
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200297 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200298 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 +0100299 else
300 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
301
302 if (unlikely(!eb)) {
303 /* no session found */
304 return NULL;
305 }
306
Willy Tarreau86257dc2010-06-06 12:57:10 +0200307 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308}
309
Emeric Brun819fc6f2017-06-13 19:37:32 +0200310/*
311 * Looks in table <t> for a sticky session matching key <key>.
312 * Returns pointer on requested sticky session or NULL if none was found.
313 * The refcount of the found entry is increased and this function
314 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200315 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200316struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200317{
318 struct stksess *ts;
319
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100320 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200321 ts = __stktable_lookup_key(t, key);
322 if (ts)
323 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100324 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200325
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200326 return ts;
327}
328
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200329/*
330 * Looks in table <t> for a sticky session with same key as <ts>.
331 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100332 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200333struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100334{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335 struct ebmb_node *eb;
336
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200337 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200338 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100339 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200340 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100341
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200342 if (unlikely(!eb))
343 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345 return ebmb_entry(eb, struct stksess, key);
346}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100347
Emeric Brun819fc6f2017-06-13 19:37:32 +0200348/*
349 * Looks in table <t> for a sticky session with same key as <ts>.
350 * Returns pointer on requested sticky session or NULL if none was found.
351 * The refcount of the found entry is increased and this function
352 * is protected using the table lock
353 */
354struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
355{
356 struct stksess *lts;
357
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100358 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200359 lts = __stktable_lookup(t, ts);
360 if (lts)
361 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100362 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200363
364 return lts;
365}
366
Willy Tarreaucb183642010-06-06 17:58:34 +0200367/* Update the expiration timer for <ts> but do not touch its expiration node.
368 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200369 * The node will be also inserted into the update tree if needed, at a position
370 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200371 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200373{
Emeric Brun85e77c72010-09-23 18:16:52 +0200374 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200375 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200376 if (t->expire) {
377 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
378 task_queue(t->exp_task);
379 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200380
Emeric Brun819fc6f2017-06-13 19:37:32 +0200381 /* If sync is enabled */
382 if (t->sync_task) {
383 if (local) {
384 /* If this entry is not in the tree
385 or not scheduled for at least one peer */
386 if (!ts->upd.node.leaf_p
387 || (int)(t->commitupdate - ts->upd.key) >= 0
388 || (int)(ts->upd.key - t->localupdate) >= 0) {
389 ts->upd.key = ++t->update;
390 t->localupdate = t->update;
391 eb32_delete(&ts->upd);
392 eb = eb32_insert(&t->updates, &ts->upd);
393 if (eb != &ts->upd) {
394 eb32_delete(eb);
395 eb32_insert(&t->updates, &ts->upd);
396 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200397 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200398 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200399 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200400 else {
401 /* If this entry is not in the tree */
402 if (!ts->upd.node.leaf_p) {
403 ts->upd.key= (++t->update)+(2147483648U);
404 eb = eb32_insert(&t->updates, &ts->upd);
405 if (eb != &ts->upd) {
406 eb32_delete(eb);
407 eb32_insert(&t->updates, &ts->upd);
408 }
409 }
410 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200411 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200412}
413
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200414/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200415 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200416 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417 * The node will be also inserted into the update tree if needed, at a position
418 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200419 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200420void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
421{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100422 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200423 __stktable_touch_with_exp(t, ts, 0, ts->expire);
424 if (decrefcnt)
425 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100426 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200427}
428
429/* Update the expiration timer for <ts> but do not touch its expiration node.
430 * The table's expiration timer is updated using the date of expiration coming from
431 * <t> stick-table configuration.
432 * The node will be also inserted into the update tree if needed, at a position
433 * considering the update was made locally
434 */
435void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200436{
437 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
438
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100439 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200440 __stktable_touch_with_exp(t, ts, 1, expire);
441 if (decrefcnt)
442 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100443 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200444}
Willy Tarreau43e90352018-06-27 06:25:57 +0200445/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
446static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200447{
Willy Tarreau43e90352018-06-27 06:25:57 +0200448 if (!ts)
449 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100450 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200451 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100452 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200453}
454
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200455/* Insert new sticky session <ts> in the table. It is assumed that it does not
456 * yet exist (the caller must check this). The table's timeout is updated if it
457 * is set. <ts> is returned.
458 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200459void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200460{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100461
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200462 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200463 ts->exp.key = ts->expire;
464 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200465 if (t->expire) {
466 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
467 task_queue(t->exp_task);
468 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200469}
470
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200471/* Returns a valid or initialized stksess for the specified stktable_key in the
472 * specified table, or NULL if the key was NULL, or if no entry was found nor
473 * could be created. The entry's expiration is updated.
474 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200475struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200476{
477 struct stksess *ts;
478
479 if (!key)
480 return NULL;
481
Emeric Brun819fc6f2017-06-13 19:37:32 +0200482 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200483 if (ts == NULL) {
484 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200485 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200486 if (!ts)
487 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200488 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200489 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200490 return ts;
491}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200492/* Returns a valid or initialized stksess for the specified stktable_key in the
493 * specified table, or NULL if the key was NULL, or if no entry was found nor
494 * could be created. The entry's expiration is updated.
495 * This function locks the table, and the refcount of the entry is increased.
496 */
497struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
498{
499 struct stksess *ts;
500
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100501 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200502 ts = __stktable_get_entry(table, key);
503 if (ts)
504 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100505 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200506
507 return ts;
508}
509
510/* Lookup for an entry with the same key and store the submitted
511 * stksess if not found.
512 */
513struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
514{
515 struct stksess *ts;
516
517 ts = __stktable_lookup(table, nts);
518 if (ts == NULL) {
519 ts = nts;
520 __stktable_store(table, ts);
521 }
522 return ts;
523}
524
525/* Lookup for an entry with the same key and store the submitted
526 * stksess if not found.
527 * This function locks the table, and the refcount of the entry is increased.
528 */
529struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
530{
531 struct stksess *ts;
532
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100533 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200534 ts = __stktable_set_entry(table, nts);
535 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100536 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200537
Emeric Brun819fc6f2017-06-13 19:37:32 +0200538 return ts;
539}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100540/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200541 * Trash expired sticky sessions from table <t>. The next expiration date is
542 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100543 */
544static int stktable_trash_expired(struct stktable *t)
545{
546 struct stksess *ts;
547 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200548 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100549
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100550 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100551 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
552
553 while (1) {
554 if (unlikely(!eb)) {
555 /* we might have reached the end of the tree, typically because
556 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200557 * half. Let's loop back to the beginning of the tree now if we
558 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100559 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200560 if (looped)
561 break;
562 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100563 eb = eb32_first(&t->exps);
564 if (likely(!eb))
565 break;
566 }
567
568 if (likely(tick_is_lt(now_ms, eb->key))) {
569 /* timer not expired yet, revisit it later */
570 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100571 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100572 }
573
574 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200575 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100576 eb = eb32_next(eb);
577
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200578 /* don't delete an entry which is currently referenced */
579 if (ts->ref_cnt)
580 continue;
581
Willy Tarreau86257dc2010-06-06 12:57:10 +0200582 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100583
584 if (!tick_is_expired(ts->expire, now_ms)) {
585 if (!tick_isset(ts->expire))
586 continue;
587
Willy Tarreau86257dc2010-06-06 12:57:10 +0200588 ts->exp.key = ts->expire;
589 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100590
Willy Tarreau86257dc2010-06-06 12:57:10 +0200591 if (!eb || eb->key > ts->exp.key)
592 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100593 continue;
594 }
595
596 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200597 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200598 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200599 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600 }
601
602 /* We have found no task to expire in any tree */
603 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100604out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100605 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100606 return t->exp_next;
607}
608
609/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200610 * Task processing function to trash expired sticky sessions. A pointer to the
611 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100612 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200613static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100614{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200615 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616
617 task->expire = stktable_trash_expired(t);
618 return task;
619}
620
Willy Tarreauaea940e2010-06-06 11:56:36 +0200621/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100622int stktable_init(struct stktable *t)
623{
624 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200625 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100626 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100627 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100628 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100629
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100630 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 +0100631
632 t->exp_next = TICK_ETERNITY;
633 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200634 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200635 if (!t->exp_task)
636 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100637 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638 t->exp_task->context = (void *)t;
639 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200640 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200641 peers_register_table(t->peers.p, t);
642 }
643
Emeric Brun3bd697e2010-01-04 15:23:48 +0100644 return t->pool != NULL;
645 }
646 return 1;
647}
648
649/*
650 * Configuration keywords of known table types
651 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200652struct stktable_type stktable_types[SMP_TYPES] = {
653 [SMP_T_SINT] = { "integer", 0, 4 },
654 [SMP_T_IPV4] = { "ip", 0, 4 },
655 [SMP_T_IPV6] = { "ipv6", 0, 16 },
656 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
657 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
658};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100659
660/*
661 * Parse table type configuration.
662 * Returns 0 on successful parsing, else 1.
663 * <myidx> is set at next configuration <args> index.
664 */
665int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
666{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200667 for (*type = 0; *type < SMP_TYPES; (*type)++) {
668 if (!stktable_types[*type].kw)
669 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100670 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
671 continue;
672
673 *key_size = stktable_types[*type].default_size;
674 (*myidx)++;
675
Willy Tarreauaea940e2010-06-06 11:56:36 +0200676 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100677 if (strcmp("len", args[*myidx]) == 0) {
678 (*myidx)++;
679 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200680 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100681 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200682 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200683 /* null terminated string needs +1 for '\0'. */
684 (*key_size)++;
685 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100686 (*myidx)++;
687 }
688 }
689 return 0;
690 }
691 return 1;
692}
693
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100694/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100695 * Parse a line with <linenum> as number in <file> configuration file to configure
696 * the stick-table with <t> as address and <id> as ID.
697 * <peers> provides the "peers" section pointer only if this function is called
698 * from a "peers" section.
699 * <nid> is the stick-table name which is sent over the network. It must be equal
700 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
701 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500702 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100703 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
704 */
705int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100706 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100707{
708 int err_code = 0;
709 int idx = 1;
710 unsigned int val;
711
712 if (!id || !*id) {
713 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
714 err_code |= ERR_ALERT | ERR_ABORT;
715 goto out;
716 }
717
718 /* Store the "peers" section if this function is called from a "peers" section. */
719 if (peers) {
720 t->peers.p = peers;
721 idx++;
722 }
723
724 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100725 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100726 t->type = (unsigned int)-1;
727 t->conf.file = file;
728 t->conf.line = linenum;
729
730 while (*args[idx]) {
731 const char *err;
732
733 if (strcmp(args[idx], "size") == 0) {
734 idx++;
735 if (!*(args[idx])) {
736 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
737 file, linenum, args[0], args[idx-1]);
738 err_code |= ERR_ALERT | ERR_FATAL;
739 goto out;
740 }
741 if ((err = parse_size_err(args[idx], &t->size))) {
742 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
743 file, linenum, args[0], *err, args[idx-1]);
744 err_code |= ERR_ALERT | ERR_FATAL;
745 goto out;
746 }
747 idx++;
748 }
749 /* This argument does not exit in "peers" section. */
750 else if (!peers && strcmp(args[idx], "peers") == 0) {
751 idx++;
752 if (!*(args[idx])) {
753 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
754 file, linenum, args[0], args[idx-1]);
755 err_code |= ERR_ALERT | ERR_FATAL;
756 goto out;
757 }
758 t->peers.name = strdup(args[idx++]);
759 }
760 else if (strcmp(args[idx], "expire") == 0) {
761 idx++;
762 if (!*(args[idx])) {
763 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
764 file, linenum, args[0], args[idx-1]);
765 err_code |= ERR_ALERT | ERR_FATAL;
766 goto out;
767 }
768 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200769 if (err == PARSE_TIME_OVER) {
770 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
771 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100772 err_code |= ERR_ALERT | ERR_FATAL;
773 goto out;
774 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200775 else if (err == PARSE_TIME_UNDER) {
776 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
777 file, linenum, args[0], args[idx], args[idx-1]);
778 err_code |= ERR_ALERT | ERR_FATAL;
779 goto out;
780 }
781 else if (err) {
782 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
783 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100784 err_code |= ERR_ALERT | ERR_FATAL;
785 goto out;
786 }
787 t->expire = val;
788 idx++;
789 }
790 else if (strcmp(args[idx], "nopurge") == 0) {
791 t->nopurge = 1;
792 idx++;
793 }
794 else if (strcmp(args[idx], "type") == 0) {
795 idx++;
796 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
797 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
798 file, linenum, args[0], args[idx]);
799 err_code |= ERR_ALERT | ERR_FATAL;
800 goto out;
801 }
802 /* idx already points to next arg */
803 }
804 else if (strcmp(args[idx], "store") == 0) {
805 int type, err;
806 char *cw, *nw, *sa;
807
808 idx++;
809 nw = args[idx];
810 while (*nw) {
811 /* the "store" keyword supports a comma-separated list */
812 cw = nw;
813 sa = NULL; /* store arg */
814 while (*nw && *nw != ',') {
815 if (*nw == '(') {
816 *nw = 0;
817 sa = ++nw;
818 while (*nw != ')') {
819 if (!*nw) {
820 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
821 file, linenum, args[0], cw);
822 err_code |= ERR_ALERT | ERR_FATAL;
823 goto out;
824 }
825 nw++;
826 }
827 *nw = '\0';
828 }
829 nw++;
830 }
831 if (*nw)
832 *nw++ = '\0';
833 type = stktable_get_data_type(cw);
834 if (type < 0) {
835 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
836 file, linenum, args[0], cw);
837 err_code |= ERR_ALERT | ERR_FATAL;
838 goto out;
839 }
840
841 err = stktable_alloc_data_type(t, type, sa);
842 switch (err) {
843 case PE_NONE: break;
844 case PE_EXIST:
845 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
846 file, linenum, args[0], cw);
847 err_code |= ERR_WARN;
848 break;
849
850 case PE_ARG_MISSING:
851 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
852 file, linenum, args[0], cw);
853 err_code |= ERR_ALERT | ERR_FATAL;
854 goto out;
855
856 case PE_ARG_NOT_USED:
857 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
858 file, linenum, args[0], cw);
859 err_code |= ERR_ALERT | ERR_FATAL;
860 goto out;
861
862 default:
863 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
864 file, linenum, args[0], cw);
865 err_code |= ERR_ALERT | ERR_FATAL;
866 goto out;
867 }
868 }
869 idx++;
870 }
871 else {
872 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
873 file, linenum, args[0], args[idx]);
874 err_code |= ERR_ALERT | ERR_FATAL;
875 goto out;
876 }
877 }
878
879 if (!t->size) {
880 ha_alert("parsing [%s:%d] : %s: missing size.\n",
881 file, linenum, args[0]);
882 err_code |= ERR_ALERT | ERR_FATAL;
883 goto out;
884 }
885
886 if (t->type == (unsigned int)-1) {
887 ha_alert("parsing [%s:%d] : %s: missing type.\n",
888 file, linenum, args[0]);
889 err_code |= ERR_ALERT | ERR_FATAL;
890 goto out;
891 }
892
893 out:
894 return err_code;
895}
896
Willy Tarreau8fed9032014-07-03 17:02:46 +0200897/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200898 * Note that the sample *is* modified and that the returned key may point
899 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200900 * Returns NULL if the sample could not be converted (eg: no matching type),
901 * otherwise a pointer to the static stktable_key filled with what is needed
902 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200903 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200904struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200905{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200906 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200907 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200908 return NULL;
909
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200910 /* Fill static_table_key. */
911 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200912
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200913 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200914 static_table_key.key = &smp->data.u.ipv4;
915 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200916 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200917
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200918 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200919 static_table_key.key = &smp->data.u.ipv6;
920 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200921 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200922
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200923 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200924 /* The stick table require a 32bit unsigned int, "sint" is a
925 * signed 64 it, so we can convert it inplace.
926 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200927 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200928 static_table_key.key = &smp->data.u.sint;
929 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200930 break;
931
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200932 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200933 if (!smp_make_safe(smp))
934 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200935 static_table_key.key = smp->data.u.str.area;
936 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200937 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200938
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200939 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200940 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200941 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200942 if (!smp_make_rw(smp))
943 return NULL;
944
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200945 if (smp->data.u.str.size < t->key_size)
946 if (!smp_dup(smp))
947 return NULL;
948 if (smp->data.u.str.size < t->key_size)
949 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200950 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
951 t->key_size - smp->data.u.str.data);
952 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200953 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200954 static_table_key.key = smp->data.u.str.area;
955 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200956 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200957
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200958 default: /* impossible case. */
959 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200960 }
961
Christopher Fauletca20d022017-08-29 15:30:31 +0200962 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200963}
964
965/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200966 * Process a fetch + format conversion as defined by the sample expression <expr>
967 * on request or response considering the <opt> parameter. Returns either NULL if
968 * no key could be extracted, or a pointer to the converted result stored in
969 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
970 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200971 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
972 * without SMP_OPT_FINAL). The output will be usable like this :
973 *
974 * return MAY_CHANGE FINAL Meaning for the sample
975 * NULL 0 * Not present and will never be (eg: header)
976 * NULL 1 0 Not present or unstable, could change (eg: req_len)
977 * NULL 1 1 Not present, will not change anymore
978 * smp 0 * Present and will not change (eg: header)
979 * smp 1 0 not possible
980 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200981 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200982struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200983 unsigned int opt, struct sample_expr *expr, struct sample *smp)
984{
985 if (smp)
986 memset(smp, 0, sizeof(*smp));
987
Willy Tarreau192252e2015-04-04 01:47:55 +0200988 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200989 if (!smp)
990 return NULL;
991
992 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
993 return NULL; /* we can only use stable samples */
994
995 return smp_to_stkey(smp, t);
996}
997
998/*
Willy Tarreau12785782012-04-27 21:37:17 +0200999 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001000 * type <table_type>, otherwise zero. Used in configuration check.
1001 */
Willy Tarreau12785782012-04-27 21:37:17 +02001002int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001003{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001004 int out_type;
1005
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001006 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001007 return 0;
1008
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001009 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001010
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001011 /* Convert sample. */
1012 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001013 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001014
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001015 return 1;
1016}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001017
Willy Tarreauedee1d62014-07-15 16:44:27 +02001018/* Extra data types processing : after the last one, some room may remain
1019 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1020 * at run time.
1021 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001022struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001023 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001024 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001025 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001026 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001027 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1028 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1029 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1030 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1031 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1032 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1033 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1034 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1035 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1036 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1037 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1038 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1039 [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 +01001040 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1041 [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 +02001042 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001043};
1044
Willy Tarreauedee1d62014-07-15 16:44:27 +02001045/* Registers stick-table extra data type with index <idx>, name <name>, type
1046 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1047 * index is automatically allocated. The allocated index is returned, or -1 if
1048 * no free index was found or <name> was already registered. The <name> is used
1049 * directly as a pointer, so if it's not stable, the caller must allocate it.
1050 */
1051int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1052{
1053 if (idx < 0) {
1054 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1055 if (!stktable_data_types[idx].name)
1056 break;
1057
1058 if (strcmp(stktable_data_types[idx].name, name) == 0)
1059 return -1;
1060 }
1061 }
1062
1063 if (idx >= STKTABLE_DATA_TYPES)
1064 return -1;
1065
1066 if (stktable_data_types[idx].name != NULL)
1067 return -1;
1068
1069 stktable_data_types[idx].name = name;
1070 stktable_data_types[idx].std_type = std_type;
1071 stktable_data_types[idx].arg_type = arg_type;
1072 return idx;
1073}
1074
Willy Tarreau08d5f982010-06-06 13:34:54 +02001075/*
1076 * Returns the data type number for the stktable_data_type whose name is <name>,
1077 * or <0 if not found.
1078 */
1079int stktable_get_data_type(char *name)
1080{
1081 int type;
1082
1083 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001084 if (!stktable_data_types[type].name)
1085 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001086 if (strcmp(name, stktable_data_types[type].name) == 0)
1087 return type;
1088 }
1089 return -1;
1090}
1091
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001092/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1093 * it up into this table. Returns true if found, false otherwise. The input
1094 * type is STR so that input samples are converted to string (since all types
1095 * can be converted to strings), then the function casts the string again into
1096 * the table's type. This is a double conversion, but in the future we might
1097 * support automatic input types to perform the cast on the fly.
1098 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001099static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001100{
1101 struct stktable *t;
1102 struct stktable_key *key;
1103 struct stksess *ts;
1104
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001105 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001106
1107 key = smp_to_stkey(smp, t);
1108 if (!key)
1109 return 0;
1110
1111 ts = stktable_lookup_key(t, key);
1112
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001113 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001114 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001115 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001116 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001117 return 1;
1118}
1119
1120/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1121 * it up into this table. Returns the data rate received from clients in bytes/s
1122 * if the key is present in the table, otherwise zero, so that comparisons can
1123 * be easily performed. If the inspected parameter is not stored in the table,
1124 * <not found> is returned.
1125 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001126static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001127{
1128 struct stktable *t;
1129 struct stktable_key *key;
1130 struct stksess *ts;
1131 void *ptr;
1132
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001133 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001134
1135 key = smp_to_stkey(smp, t);
1136 if (!key)
1137 return 0;
1138
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001139 ts = stktable_lookup_key(t, key);
1140
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001141 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001142 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001143 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001144
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001145 if (!ts) /* key not present */
1146 return 1;
1147
1148 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001149 if (ptr)
1150 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1151 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001152
Daniel Corbett3e60b112018-05-27 09:47:12 -04001153 stktable_release(t, ts);
1154 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001155}
1156
1157/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1158 * it up into this table. Returns the cumulated number of connections for the key
1159 * if the key is present in the table, otherwise zero, so that comparisons can
1160 * be easily performed. If the inspected parameter is not stored in the table,
1161 * <not found> is returned.
1162 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001163static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001164{
1165 struct stktable *t;
1166 struct stktable_key *key;
1167 struct stksess *ts;
1168 void *ptr;
1169
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001170 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001171
1172 key = smp_to_stkey(smp, t);
1173 if (!key)
1174 return 0;
1175
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001176 ts = stktable_lookup_key(t, key);
1177
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001178 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001179 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001180 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001181
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001182 if (!ts) /* key not present */
1183 return 1;
1184
1185 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001186 if (ptr)
1187 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001188
Daniel Corbett3e60b112018-05-27 09:47:12 -04001189 stktable_release(t, ts);
1190 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001191}
1192
1193/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1194 * it up into this table. Returns the number of concurrent connections for the
1195 * key if the key is present in the table, otherwise zero, so that comparisons
1196 * can be easily performed. If the inspected parameter is not stored in the
1197 * table, <not found> is returned.
1198 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001199static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001200{
1201 struct stktable *t;
1202 struct stktable_key *key;
1203 struct stksess *ts;
1204 void *ptr;
1205
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001206 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001207
1208 key = smp_to_stkey(smp, t);
1209 if (!key)
1210 return 0;
1211
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001212 ts = stktable_lookup_key(t, key);
1213
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001214 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001215 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001216 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001217
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001218 if (!ts) /* key not present */
1219 return 1;
1220
1221 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001222 if (ptr)
1223 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001224
Daniel Corbett3e60b112018-05-27 09:47:12 -04001225 stktable_release(t, ts);
1226 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001227}
1228
1229/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1230 * it up into this table. Returns the rate of incoming connections from the key
1231 * if the key is present in the table, otherwise zero, so that comparisons can
1232 * be easily performed. If the inspected parameter is not stored in the table,
1233 * <not found> is returned.
1234 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001235static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001236{
1237 struct stktable *t;
1238 struct stktable_key *key;
1239 struct stksess *ts;
1240 void *ptr;
1241
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001242 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001243
1244 key = smp_to_stkey(smp, t);
1245 if (!key)
1246 return 0;
1247
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001248 ts = stktable_lookup_key(t, key);
1249
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001250 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001251 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001252 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001253
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254 if (!ts) /* key not present */
1255 return 1;
1256
1257 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001258 if (ptr)
1259 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1260 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261
Daniel Corbett3e60b112018-05-27 09:47:12 -04001262 stktable_release(t, ts);
1263 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001264}
1265
1266/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1267 * it up into this table. Returns the data rate sent to clients in bytes/s
1268 * if the key is present in the table, otherwise zero, so that comparisons can
1269 * be easily performed. If the inspected parameter is not stored in the table,
1270 * <not found> is returned.
1271 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001272static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001273{
1274 struct stktable *t;
1275 struct stktable_key *key;
1276 struct stksess *ts;
1277 void *ptr;
1278
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001279 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001280
1281 key = smp_to_stkey(smp, t);
1282 if (!key)
1283 return 0;
1284
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001285 ts = stktable_lookup_key(t, key);
1286
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001287 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001288 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001289 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001290
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001291 if (!ts) /* key not present */
1292 return 1;
1293
1294 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001295 if (ptr)
1296 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1297 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001298
Daniel Corbett3e60b112018-05-27 09:47:12 -04001299 stktable_release(t, ts);
1300 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301}
1302
1303/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001304 * it up into this table. Returns the value of the GPT0 tag for the key
1305 * if the key is present in the table, otherwise false, so that comparisons can
1306 * be easily performed. If the inspected parameter is not stored in the table,
1307 * <not found> is returned.
1308 */
1309static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1310{
1311 struct stktable *t;
1312 struct stktable_key *key;
1313 struct stksess *ts;
1314 void *ptr;
1315
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001316 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001317
1318 key = smp_to_stkey(smp, t);
1319 if (!key)
1320 return 0;
1321
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001322 ts = stktable_lookup_key(t, key);
1323
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001324 smp->flags = SMP_F_VOL_TEST;
1325 smp->data.type = SMP_T_SINT;
1326 smp->data.u.sint = 0;
1327
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001328 if (!ts) /* key not present */
1329 return 1;
1330
1331 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001332 if (ptr)
1333 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001334
Daniel Corbett3e60b112018-05-27 09:47:12 -04001335 stktable_release(t, ts);
1336 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001337}
1338
1339/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001340 * it up into this table. Returns the value of the GPC0 counter for the key
1341 * if the key is present in the table, otherwise zero, so that comparisons can
1342 * be easily performed. If the inspected parameter is not stored in the table,
1343 * <not found> is returned.
1344 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001345static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346{
1347 struct stktable *t;
1348 struct stktable_key *key;
1349 struct stksess *ts;
1350 void *ptr;
1351
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001352 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001353
1354 key = smp_to_stkey(smp, t);
1355 if (!key)
1356 return 0;
1357
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001358 ts = stktable_lookup_key(t, key);
1359
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001361 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001362 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001364 if (!ts) /* key not present */
1365 return 1;
1366
1367 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001368 if (ptr)
1369 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370
Daniel Corbett3e60b112018-05-27 09:47:12 -04001371 stktable_release(t, ts);
1372 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001373}
1374
1375/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1376 * it up into this table. Returns the event rate of the GPC0 counter for the key
1377 * if the key is present in the table, otherwise zero, so that comparisons can
1378 * be easily performed. If the inspected parameter is not stored in the table,
1379 * <not found> is returned.
1380 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001381static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382{
1383 struct stktable *t;
1384 struct stktable_key *key;
1385 struct stksess *ts;
1386 void *ptr;
1387
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001388 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001389
1390 key = smp_to_stkey(smp, t);
1391 if (!key)
1392 return 0;
1393
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001394 ts = stktable_lookup_key(t, key);
1395
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001396 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001397 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001398 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001399
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400 if (!ts) /* key not present */
1401 return 1;
1402
1403 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001404 if (ptr)
1405 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1406 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001407
Daniel Corbett3e60b112018-05-27 09:47:12 -04001408 stktable_release(t, ts);
1409 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001410}
1411
1412/* 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 +01001413 * it up into this table. Returns the value of the GPC1 counter for the key
1414 * if the key is present in the table, otherwise zero, so that comparisons can
1415 * be easily performed. If the inspected parameter is not stored in the table,
1416 * <not found> is returned.
1417 */
1418static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1419{
1420 struct stktable *t;
1421 struct stktable_key *key;
1422 struct stksess *ts;
1423 void *ptr;
1424
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001425 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001426
1427 key = smp_to_stkey(smp, t);
1428 if (!key)
1429 return 0;
1430
1431 ts = stktable_lookup_key(t, key);
1432
1433 smp->flags = SMP_F_VOL_TEST;
1434 smp->data.type = SMP_T_SINT;
1435 smp->data.u.sint = 0;
1436
1437 if (!ts) /* key not present */
1438 return 1;
1439
1440 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001441 if (ptr)
1442 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001443
Daniel Corbett3e60b112018-05-27 09:47:12 -04001444 stktable_release(t, ts);
1445 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001446}
1447
1448/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1449 * it up into this table. Returns the event rate of the GPC1 counter for the key
1450 * if the key is present in the table, otherwise zero, so that comparisons can
1451 * be easily performed. If the inspected parameter is not stored in the table,
1452 * <not found> is returned.
1453 */
1454static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1455{
1456 struct stktable *t;
1457 struct stktable_key *key;
1458 struct stksess *ts;
1459 void *ptr;
1460
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001461 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001462
1463 key = smp_to_stkey(smp, t);
1464 if (!key)
1465 return 0;
1466
1467 ts = stktable_lookup_key(t, key);
1468
1469 smp->flags = SMP_F_VOL_TEST;
1470 smp->data.type = SMP_T_SINT;
1471 smp->data.u.sint = 0;
1472
1473 if (!ts) /* key not present */
1474 return 1;
1475
1476 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001477 if (ptr)
1478 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1479 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001480
Daniel Corbett3e60b112018-05-27 09:47:12 -04001481 stktable_release(t, ts);
1482 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001483}
1484
1485/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001486 * it up into this table. Returns the cumulated number of HTTP request errors
1487 * for the key if the key is present in the table, otherwise zero, so that
1488 * comparisons can be easily performed. If the inspected parameter is not stored
1489 * in the table, <not found> is returned.
1490 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001491static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001492{
1493 struct stktable *t;
1494 struct stktable_key *key;
1495 struct stksess *ts;
1496 void *ptr;
1497
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001498 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001499
1500 key = smp_to_stkey(smp, t);
1501 if (!key)
1502 return 0;
1503
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001504 ts = stktable_lookup_key(t, key);
1505
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001506 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001507 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001508 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001509
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001510 if (!ts) /* key not present */
1511 return 1;
1512
1513 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001514 if (ptr)
1515 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001516
Daniel Corbett3e60b112018-05-27 09:47:12 -04001517 stktable_release(t, ts);
1518 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001519}
1520
1521/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1522 * it up into this table. Returns the HTTP request error rate the key
1523 * if the key is present in the table, otherwise zero, so that comparisons can
1524 * be easily performed. If the inspected parameter is not stored in the table,
1525 * <not found> is returned.
1526 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001527static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001528{
1529 struct stktable *t;
1530 struct stktable_key *key;
1531 struct stksess *ts;
1532 void *ptr;
1533
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001534 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001535
1536 key = smp_to_stkey(smp, t);
1537 if (!key)
1538 return 0;
1539
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001540 ts = stktable_lookup_key(t, key);
1541
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001542 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001543 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001544 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001545
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001546 if (!ts) /* key not present */
1547 return 1;
1548
1549 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001550 if (ptr)
1551 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1552 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001553
Daniel Corbett3e60b112018-05-27 09:47:12 -04001554 stktable_release(t, ts);
1555 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001556}
1557
1558/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1559 * it up into this table. Returns the cumulated number of HTTP request for the
1560 * key if the key is present in the table, otherwise zero, so that comparisons
1561 * can be easily performed. If the inspected parameter is not stored in the
1562 * table, <not found> is returned.
1563 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001564static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001565{
1566 struct stktable *t;
1567 struct stktable_key *key;
1568 struct stksess *ts;
1569 void *ptr;
1570
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001571 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001572
1573 key = smp_to_stkey(smp, t);
1574 if (!key)
1575 return 0;
1576
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001577 ts = stktable_lookup_key(t, key);
1578
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001579 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001580 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001581 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001582
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001583 if (!ts) /* key not present */
1584 return 1;
1585
1586 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001587 if (ptr)
1588 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589
Daniel Corbett3e60b112018-05-27 09:47:12 -04001590 stktable_release(t, ts);
1591 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001592}
1593
1594/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1595 * it up into this table. Returns the HTTP request rate the key if the key is
1596 * present in the table, otherwise zero, so that comparisons can be easily
1597 * performed. If the inspected parameter is not stored in the table, <not found>
1598 * is returned.
1599 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001600static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001601{
1602 struct stktable *t;
1603 struct stktable_key *key;
1604 struct stksess *ts;
1605 void *ptr;
1606
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001607 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001608
1609 key = smp_to_stkey(smp, t);
1610 if (!key)
1611 return 0;
1612
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001613 ts = stktable_lookup_key(t, key);
1614
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001615 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001616 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001617 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001618
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001619 if (!ts) /* key not present */
1620 return 1;
1621
1622 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001623 if (ptr)
1624 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1625 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001626
Daniel Corbett3e60b112018-05-27 09:47:12 -04001627 stktable_release(t, ts);
1628 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001629}
1630
1631/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1632 * it up into this table. Returns the volume of datareceived from clients in kbytes
1633 * if the key is present in the table, otherwise zero, so that comparisons can
1634 * be easily performed. If the inspected parameter is not stored in the table,
1635 * <not found> is returned.
1636 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001637static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001638{
1639 struct stktable *t;
1640 struct stktable_key *key;
1641 struct stksess *ts;
1642 void *ptr;
1643
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001644 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001645
1646 key = smp_to_stkey(smp, t);
1647 if (!key)
1648 return 0;
1649
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001650 ts = stktable_lookup_key(t, key);
1651
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001652 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001653 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001654 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001655
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001656 if (!ts) /* key not present */
1657 return 1;
1658
1659 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001660 if (ptr)
1661 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001662
Daniel Corbett3e60b112018-05-27 09:47:12 -04001663 stktable_release(t, ts);
1664 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001665}
1666
1667/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1668 * it up into this table. Returns the volume of data sent to clients in kbytes
1669 * if the key is present in the table, otherwise zero, so that comparisons can
1670 * be easily performed. If the inspected parameter is not stored in the table,
1671 * <not found> is returned.
1672 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001673static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001674{
1675 struct stktable *t;
1676 struct stktable_key *key;
1677 struct stksess *ts;
1678 void *ptr;
1679
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001680 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001681
1682 key = smp_to_stkey(smp, t);
1683 if (!key)
1684 return 0;
1685
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001686 ts = stktable_lookup_key(t, key);
1687
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001688 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001689 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001690 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001691
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001692 if (!ts) /* key not present */
1693 return 1;
1694
1695 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001696 if (ptr)
1697 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001698
Daniel Corbett3e60b112018-05-27 09:47:12 -04001699 stktable_release(t, ts);
1700 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001701}
1702
1703/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1704 * it up into this table. Returns the server ID associated with the key if the
1705 * key is present in the table, otherwise zero, so that comparisons can be
1706 * easily performed. If the inspected parameter is not stored in the table,
1707 * <not found> is returned.
1708 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001709static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001710{
1711 struct stktable *t;
1712 struct stktable_key *key;
1713 struct stksess *ts;
1714 void *ptr;
1715
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001716 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001717
1718 key = smp_to_stkey(smp, t);
1719 if (!key)
1720 return 0;
1721
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001722 ts = stktable_lookup_key(t, key);
1723
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001724 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001725 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001726 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001728 if (!ts) /* key not present */
1729 return 1;
1730
1731 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001732 if (ptr)
1733 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001734
Daniel Corbett3e60b112018-05-27 09:47:12 -04001735 stktable_release(t, ts);
1736 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001737}
1738
1739/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1740 * it up into this table. Returns the cumulated number of sessions for the
1741 * key if the key is present in the table, otherwise zero, so that comparisons
1742 * can be easily performed. If the inspected parameter is not stored in the
1743 * table, <not found> is returned.
1744 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001745static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001746{
1747 struct stktable *t;
1748 struct stktable_key *key;
1749 struct stksess *ts;
1750 void *ptr;
1751
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001752 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001753
1754 key = smp_to_stkey(smp, t);
1755 if (!key)
1756 return 0;
1757
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001758 ts = stktable_lookup_key(t, key);
1759
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001760 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001761 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001762 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001763
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001764 if (!ts) /* key not present */
1765 return 1;
1766
1767 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001768 if (ptr)
1769 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001770
Daniel Corbett3e60b112018-05-27 09:47:12 -04001771 stktable_release(t, ts);
1772 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773}
1774
1775/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1776 * it up into this table. Returns the session rate the key if the key is
1777 * present in the table, otherwise zero, so that comparisons can be easily
1778 * performed. If the inspected parameter is not stored in the table, <not found>
1779 * is returned.
1780 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001781static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782{
1783 struct stktable *t;
1784 struct stktable_key *key;
1785 struct stksess *ts;
1786 void *ptr;
1787
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001788 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001789
1790 key = smp_to_stkey(smp, t);
1791 if (!key)
1792 return 0;
1793
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001794 ts = stktable_lookup_key(t, key);
1795
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001796 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001797 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001798 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800 if (!ts) /* key not present */
1801 return 1;
1802
1803 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001804 if (ptr)
1805 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1806 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001807
Daniel Corbett3e60b112018-05-27 09:47:12 -04001808 stktable_release(t, ts);
1809 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001810}
1811
1812/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1813 * it up into this table. Returns the amount of concurrent connections tracking
1814 * the same key if the key is present in the table, otherwise zero, so that
1815 * comparisons can be easily performed. If the inspected parameter is not
1816 * stored in the table, <not found> is returned.
1817 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001818static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001819{
1820 struct stktable *t;
1821 struct stktable_key *key;
1822 struct stksess *ts;
1823
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001824 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001825
1826 key = smp_to_stkey(smp, t);
1827 if (!key)
1828 return 0;
1829
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001830 ts = stktable_lookup_key(t, key);
1831
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001832 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001833 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001834 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001835
Tim Duesterhus65189c12018-06-26 15:57:29 +02001836 if (!ts)
1837 return 1;
1838
1839 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001840
Daniel Corbett3e60b112018-05-27 09:47:12 -04001841 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001842 return 1;
1843}
1844
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001845/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001846static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001847 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001848{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001849 struct stksess *ts;
1850 struct stkctr *stkctr;
1851
1852 /* Extract the stksess, return OK if no stksess available. */
1853 if (s)
1854 stkctr = &s->stkctr[rule->arg.gpc.sc];
1855 else
1856 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001857
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001858 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001859 if (ts) {
1860 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001861
Willy Tarreau79c1e912016-01-25 14:54:45 +01001862 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1863 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001864 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1865 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001866 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001867
1868 if (ptr1)
1869 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001870 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001871
Emeric Brun819fc6f2017-06-13 19:37:32 +02001872 if (ptr2)
1873 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001874
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001875 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001876
1877 /* If data was modified, we need to touch to re-schedule sync */
1878 stktable_touch_local(stkctr->table, ts, 0);
1879 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001880 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001881 return ACT_RET_CONT;
1882}
1883
1884/* This function is a common parser for using variables. It understands
1885 * the formats:
1886 *
1887 * sc-inc-gpc0(<stick-table ID>)
1888 *
1889 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1890 * it returns 1 and the variable <expr> is filled with the pointer to the
1891 * expression to execute.
1892 */
1893static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1894 struct act_rule *rule, char **err)
1895{
1896 const char *cmd_name = args[*arg-1];
1897 char *error;
1898
1899 cmd_name += strlen("sc-inc-gpc0");
1900 if (*cmd_name == '\0') {
1901 /* default stick table id. */
1902 rule->arg.gpc.sc = 0;
1903 } else {
1904 /* parse the stick table id. */
1905 if (*cmd_name != '(') {
1906 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1907 return ACT_RET_PRS_ERR;
1908 }
1909 cmd_name++; /* jump the '(' */
1910 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1911 if (*error != ')') {
1912 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1913 return ACT_RET_PRS_ERR;
1914 }
1915
Christopher Faulet28436e22019-12-18 10:25:46 +01001916 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001917 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001918 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001919 return ACT_RET_PRS_ERR;
1920 }
1921 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001922 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001923 rule->action_ptr = action_inc_gpc0;
1924 return ACT_RET_PRS_OK;
1925}
1926
1927/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001928static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1929 struct session *sess, struct stream *s, int flags)
1930{
1931 struct stksess *ts;
1932 struct stkctr *stkctr;
1933
1934 /* Extract the stksess, return OK if no stksess available. */
1935 if (s)
1936 stkctr = &s->stkctr[rule->arg.gpc.sc];
1937 else
1938 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1939
1940 ts = stkctr_entry(stkctr);
1941 if (ts) {
1942 void *ptr1, *ptr2;
1943
1944 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1945 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1946 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1947 if (ptr1 || ptr2) {
1948 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1949
1950 if (ptr1)
1951 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1952 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1953
1954 if (ptr2)
1955 stktable_data_cast(ptr2, gpc1)++;
1956
1957 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1958
1959 /* If data was modified, we need to touch to re-schedule sync */
1960 stktable_touch_local(stkctr->table, ts, 0);
1961 }
1962 }
1963 return ACT_RET_CONT;
1964}
1965
1966/* This function is a common parser for using variables. It understands
1967 * the formats:
1968 *
1969 * sc-inc-gpc1(<stick-table ID>)
1970 *
1971 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1972 * it returns 1 and the variable <expr> is filled with the pointer to the
1973 * expression to execute.
1974 */
1975static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1976 struct act_rule *rule, char **err)
1977{
1978 const char *cmd_name = args[*arg-1];
1979 char *error;
1980
1981 cmd_name += strlen("sc-inc-gpc1");
1982 if (*cmd_name == '\0') {
1983 /* default stick table id. */
1984 rule->arg.gpc.sc = 0;
1985 } else {
1986 /* parse the stick table id. */
1987 if (*cmd_name != '(') {
1988 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1989 return ACT_RET_PRS_ERR;
1990 }
1991 cmd_name++; /* jump the '(' */
1992 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1993 if (*error != ')') {
1994 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1995 return ACT_RET_PRS_ERR;
1996 }
1997
Christopher Faulet28436e22019-12-18 10:25:46 +01001998 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001999 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002000 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002001 return ACT_RET_PRS_ERR;
2002 }
2003 }
2004 rule->action = ACT_CUSTOM;
2005 rule->action_ptr = action_inc_gpc1;
2006 return ACT_RET_PRS_OK;
2007}
2008
2009/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002010static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002011 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002012{
2013 void *ptr;
2014 struct stksess *ts;
2015 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002016 unsigned int value = 0;
2017 struct sample *smp;
2018 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002019
2020 /* Extract the stksess, return OK if no stksess available. */
2021 if (s)
2022 stkctr = &s->stkctr[rule->arg.gpt.sc];
2023 else
2024 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002025
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002026 ts = stkctr_entry(stkctr);
2027 if (!ts)
2028 return ACT_RET_CONT;
2029
2030 /* Store the sample in the required sc, and ignore errors. */
2031 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002032 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002033 if (!rule->arg.gpt.expr)
2034 value = (unsigned int)(rule->arg.gpt.value);
2035 else {
2036 switch (rule->from) {
2037 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2038 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2039 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2040 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2041 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2042 default:
2043 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2044 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2045 ha_alert("stick table: internal error while executing setting gpt0.\n");
2046 return ACT_RET_CONT;
2047 }
2048
2049 /* Fetch and cast the expression. */
2050 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2051 if (!smp) {
2052 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2053 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2054 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2055 return ACT_RET_CONT;
2056 }
2057 value = (unsigned int)(smp->data.u.sint);
2058 }
2059
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002060 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002061
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002062 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002063
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002064 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002065
2066 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002067 }
2068
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002069 return ACT_RET_CONT;
2070}
2071
2072/* This function is a common parser for using variables. It understands
2073 * the format:
2074 *
2075 * set-gpt0(<stick-table ID>) <expression>
2076 *
2077 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2078 * it returns 1 and the variable <expr> is filled with the pointer to the
2079 * expression to execute.
2080 */
2081static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2082 struct act_rule *rule, char **err)
2083
2084
2085{
2086 const char *cmd_name = args[*arg-1];
2087 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002088 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002089
2090 cmd_name += strlen("sc-set-gpt0");
2091 if (*cmd_name == '\0') {
2092 /* default stick table id. */
2093 rule->arg.gpt.sc = 0;
2094 } else {
2095 /* parse the stick table id. */
2096 if (*cmd_name != '(') {
2097 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2098 return ACT_RET_PRS_ERR;
2099 }
2100 cmd_name++; /* jump the '(' */
2101 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2102 if (*error != ')') {
2103 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2104 return ACT_RET_PRS_ERR;
2105 }
2106
Christopher Faulet28436e22019-12-18 10:25:46 +01002107 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002108 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002109 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002110 return ACT_RET_PRS_ERR;
2111 }
2112 }
2113
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002114 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002115 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2116 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002117 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002118 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002119 if (!rule->arg.gpt.expr)
2120 return ACT_RET_PRS_ERR;
2121
2122 switch (rule->from) {
2123 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2124 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2125 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2126 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2127 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2128 default:
2129 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2130 return ACT_RET_PRS_ERR;
2131 }
2132 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2133 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2134 sample_src_names(rule->arg.gpt.expr->fetch->use));
2135 free(rule->arg.gpt.expr);
2136 return ACT_RET_PRS_ERR;
2137 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002138 }
2139 (*arg)++;
2140
Thierry FOURNIER42148732015-09-02 17:17:33 +02002141 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002142 rule->action_ptr = action_set_gpt0;
2143
2144 return ACT_RET_PRS_OK;
2145}
2146
Willy Tarreau7d562212016-11-25 16:10:05 +01002147/* set temp integer to the number of used entries in the table pointed to by expr.
2148 * Accepts exactly 1 argument of type table.
2149 */
2150static int
2151smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2152{
2153 smp->flags = SMP_F_VOL_TEST;
2154 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002155 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002156 return 1;
2157}
2158
2159/* set temp integer to the number of free entries in the table pointed to by expr.
2160 * Accepts exactly 1 argument of type table.
2161 */
2162static int
2163smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2164{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002165 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002166
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002167 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002168 smp->flags = SMP_F_VOL_TEST;
2169 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002170 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002171 return 1;
2172}
2173
2174/* Returns a pointer to a stkctr depending on the fetch keyword name.
2175 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2176 * sc[0-9]_* will return a pointer to the respective field in the
2177 * stream <l4>. sc_* requires an UINT argument specifying the stick
2178 * counter number. src_* will fill a locally allocated structure with
2179 * the table and entry corresponding to what is specified with src_*.
2180 * NULL may be returned if the designated stkctr is not tracked. For
2181 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2182 * passed. When present, the currently tracked key is then looked up
2183 * in the specified table instead of the current table. The purpose is
2184 * to be able to convery multiple values per key (eg: have gpc0 from
2185 * multiple tables). <strm> is allowed to be NULL, in which case only
2186 * the session will be consulted.
2187 */
2188struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002189smp_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 +01002190{
Willy Tarreau7d562212016-11-25 16:10:05 +01002191 struct stkctr *stkptr;
2192 struct stksess *stksess;
2193 unsigned int num = kw[2] - '0';
2194 int arg = 0;
2195
2196 if (num == '_' - '0') {
2197 /* sc_* variant, args[0] = ctr# (mandatory) */
2198 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002199 }
2200 else if (num > 9) { /* src_* variant, args[0] = table */
2201 struct stktable_key *key;
2202 struct connection *conn = objt_conn(sess->origin);
2203 struct sample smp;
2204
2205 if (!conn)
2206 return NULL;
2207
Joseph Herlant5662fa42018-11-15 13:43:28 -08002208 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002209 smp.px = NULL;
2210 smp.sess = sess;
2211 smp.strm = strm;
2212 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2213 return NULL;
2214
2215 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002216 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002217 if (!key)
2218 return NULL;
2219
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002220 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002221 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2222 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002223 }
2224
2225 /* Here, <num> contains the counter number from 0 to 9 for
2226 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2227 * args[arg] is the first optional argument. We first lookup the
2228 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002229 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002230 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002231 if (num >= MAX_SESS_STKCTR)
2232 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002233
2234 if (strm)
2235 stkptr = &strm->stkctr[num];
2236 if (!strm || !stkctr_entry(stkptr)) {
2237 stkptr = &sess->stkctr[num];
2238 if (!stkctr_entry(stkptr))
2239 return NULL;
2240 }
2241
2242 stksess = stkctr_entry(stkptr);
2243 if (!stksess)
2244 return NULL;
2245
2246 if (unlikely(args[arg].type == ARGT_TAB)) {
2247 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002248 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002249 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2250 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002251 }
2252 return stkptr;
2253}
2254
2255/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2256 * the entry if it doesn't exist yet. This is needed for a few fetch
2257 * functions which need to create an entry, such as src_inc_gpc* and
2258 * src_clr_gpc*.
2259 */
2260struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002261smp_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 +01002262{
Willy Tarreau7d562212016-11-25 16:10:05 +01002263 struct stktable_key *key;
2264 struct connection *conn = objt_conn(sess->origin);
2265 struct sample smp;
2266
2267 if (strncmp(kw, "src_", 4) != 0)
2268 return NULL;
2269
2270 if (!conn)
2271 return NULL;
2272
Joseph Herlant5662fa42018-11-15 13:43:28 -08002273 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002274 smp.px = NULL;
2275 smp.sess = sess;
2276 smp.strm = strm;
2277 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2278 return NULL;
2279
2280 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002281 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002282 if (!key)
2283 return NULL;
2284
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002285 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002286 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2287 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002288}
2289
2290/* set return a boolean indicating if the requested stream counter is
2291 * currently being tracked or not.
2292 * Supports being called as "sc[0-9]_tracked" only.
2293 */
2294static int
2295smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2296{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002297 struct stkctr tmpstkctr;
2298 struct stkctr *stkctr;
2299
Willy Tarreau7d562212016-11-25 16:10:05 +01002300 smp->flags = SMP_F_VOL_TEST;
2301 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002302 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2303 smp->data.u.sint = !!stkctr;
2304
2305 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002306 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002307 stktable_release(stkctr->table, stkctr_entry(stkctr));
2308
Willy Tarreau7d562212016-11-25 16:10:05 +01002309 return 1;
2310}
2311
2312/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2313 * frontend counters or from the src.
2314 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2315 * zero is returned if the key is new.
2316 */
2317static int
2318smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2319{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002320 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002321 struct stkctr *stkctr;
2322
Emeric Brun819fc6f2017-06-13 19:37:32 +02002323 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002324 if (!stkctr)
2325 return 0;
2326
2327 smp->flags = SMP_F_VOL_TEST;
2328 smp->data.type = SMP_T_SINT;
2329 smp->data.u.sint = 0;
2330
Emeric Brun819fc6f2017-06-13 19:37:32 +02002331 if (stkctr_entry(stkctr)) {
2332 void *ptr;
2333
2334 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2335 if (!ptr) {
2336 if (stkctr == &tmpstkctr)
2337 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002338 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002339 }
2340
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002341 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002342
Willy Tarreau7d562212016-11-25 16:10:05 +01002343 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002344
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002345 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002346
2347 if (stkctr == &tmpstkctr)
2348 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002349 }
2350 return 1;
2351}
2352
2353/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2354 * frontend counters or from the src.
2355 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2356 * zero is returned if the key is new.
2357 */
2358static int
2359smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2360{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002361 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002362 struct stkctr *stkctr;
2363
Emeric Brun819fc6f2017-06-13 19:37:32 +02002364 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002365 if (!stkctr)
2366 return 0;
2367
2368 smp->flags = SMP_F_VOL_TEST;
2369 smp->data.type = SMP_T_SINT;
2370 smp->data.u.sint = 0;
2371
2372 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002373 void *ptr;
2374
2375 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2376 if (!ptr) {
2377 if (stkctr == &tmpstkctr)
2378 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002379 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002380 }
2381
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002382 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002383
Willy Tarreau7d562212016-11-25 16:10:05 +01002384 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002385
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002386 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002387
2388 if (stkctr == &tmpstkctr)
2389 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002390 }
2391 return 1;
2392}
2393
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002394/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2395 * frontend counters or from the src.
2396 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2397 * zero is returned if the key is new.
2398 */
2399static int
2400smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2401{
2402 struct stkctr tmpstkctr;
2403 struct stkctr *stkctr;
2404
2405 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2406 if (!stkctr)
2407 return 0;
2408
2409 smp->flags = SMP_F_VOL_TEST;
2410 smp->data.type = SMP_T_SINT;
2411 smp->data.u.sint = 0;
2412
2413 if (stkctr_entry(stkctr) != NULL) {
2414 void *ptr;
2415
2416 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2417 if (!ptr) {
2418 if (stkctr == &tmpstkctr)
2419 stktable_release(stkctr->table, stkctr_entry(stkctr));
2420 return 0; /* parameter not stored */
2421 }
2422
2423 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2424
2425 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2426
2427 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2428
2429 if (stkctr == &tmpstkctr)
2430 stktable_release(stkctr->table, stkctr_entry(stkctr));
2431 }
2432 return 1;
2433}
2434
Willy Tarreau7d562212016-11-25 16:10:05 +01002435/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2436 * tracked frontend counters or from the src.
2437 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2438 * Value zero is returned if the key is new.
2439 */
2440static int
2441smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2442{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002443 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002444 struct stkctr *stkctr;
2445
Emeric Brun819fc6f2017-06-13 19:37:32 +02002446 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002447 if (!stkctr)
2448 return 0;
2449
2450 smp->flags = SMP_F_VOL_TEST;
2451 smp->data.type = SMP_T_SINT;
2452 smp->data.u.sint = 0;
2453 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002454 void *ptr;
2455
2456 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2457 if (!ptr) {
2458 if (stkctr == &tmpstkctr)
2459 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002460 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002461 }
2462
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002463 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002464
Willy Tarreau7d562212016-11-25 16:10:05 +01002465 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2466 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002467
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002468 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002469
2470 if (stkctr == &tmpstkctr)
2471 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002472 }
2473 return 1;
2474}
2475
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002476/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2477 * tracked frontend counters or from the src.
2478 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2479 * Value zero is returned if the key is new.
2480 */
2481static int
2482smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2483{
2484 struct stkctr tmpstkctr;
2485 struct stkctr *stkctr;
2486
2487 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2488 if (!stkctr)
2489 return 0;
2490
2491 smp->flags = SMP_F_VOL_TEST;
2492 smp->data.type = SMP_T_SINT;
2493 smp->data.u.sint = 0;
2494 if (stkctr_entry(stkctr) != NULL) {
2495 void *ptr;
2496
2497 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2498 if (!ptr) {
2499 if (stkctr == &tmpstkctr)
2500 stktable_release(stkctr->table, stkctr_entry(stkctr));
2501 return 0; /* parameter not stored */
2502 }
2503
2504 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2505
2506 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2507 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2508
2509 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2510
2511 if (stkctr == &tmpstkctr)
2512 stktable_release(stkctr->table, stkctr_entry(stkctr));
2513 }
2514 return 1;
2515}
2516
Willy Tarreau7d562212016-11-25 16:10:05 +01002517/* Increment the General Purpose Counter 0 value from the stream's tracked
2518 * frontend counters and return it into temp integer.
2519 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2520 */
2521static int
2522smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2523{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002524 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002525 struct stkctr *stkctr;
2526
Emeric Brun819fc6f2017-06-13 19:37:32 +02002527 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002528 if (!stkctr)
2529 return 0;
2530
2531 smp->flags = SMP_F_VOL_TEST;
2532 smp->data.type = SMP_T_SINT;
2533 smp->data.u.sint = 0;
2534
Emeric Brun819fc6f2017-06-13 19:37:32 +02002535 if (!stkctr_entry(stkctr))
2536 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002537
2538 if (stkctr && stkctr_entry(stkctr)) {
2539 void *ptr1,*ptr2;
2540
Emeric Brun819fc6f2017-06-13 19:37:32 +02002541
Willy Tarreau7d562212016-11-25 16:10:05 +01002542 /* First, update gpc0_rate if it's tracked. Second, update its
2543 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2544 */
2545 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002546 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002547 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002548 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002549
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550 if (ptr1) {
2551 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2552 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2553 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2554 }
2555
2556 if (ptr2)
2557 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2558
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002559 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002560
2561 /* If data was modified, we need to touch to re-schedule sync */
2562 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2563 }
2564 else if (stkctr == &tmpstkctr)
2565 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002566 }
2567 return 1;
2568}
2569
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002570/* Increment the General Purpose Counter 1 value from the stream's tracked
2571 * frontend counters and return it into temp integer.
2572 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2573 */
2574static int
2575smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2576{
2577 struct stkctr tmpstkctr;
2578 struct stkctr *stkctr;
2579
2580 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2581 if (!stkctr)
2582 return 0;
2583
2584 smp->flags = SMP_F_VOL_TEST;
2585 smp->data.type = SMP_T_SINT;
2586 smp->data.u.sint = 0;
2587
2588 if (!stkctr_entry(stkctr))
2589 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2590
2591 if (stkctr && stkctr_entry(stkctr)) {
2592 void *ptr1,*ptr2;
2593
2594
2595 /* First, update gpc1_rate if it's tracked. Second, update its
2596 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2597 */
2598 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2599 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2600 if (ptr1 || ptr2) {
2601 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2602
2603 if (ptr1) {
2604 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2605 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2606 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2607 }
2608
2609 if (ptr2)
2610 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2611
2612 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2613
2614 /* If data was modified, we need to touch to re-schedule sync */
2615 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2616 }
2617 else if (stkctr == &tmpstkctr)
2618 stktable_release(stkctr->table, stkctr_entry(stkctr));
2619 }
2620 return 1;
2621}
2622
Willy Tarreau7d562212016-11-25 16:10:05 +01002623/* Clear the General Purpose Counter 0 value from the stream's tracked
2624 * frontend counters and return its previous value into temp integer.
2625 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2626 */
2627static int
2628smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2629{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002630 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002631 struct stkctr *stkctr;
2632
Emeric Brun819fc6f2017-06-13 19:37:32 +02002633 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002634 if (!stkctr)
2635 return 0;
2636
2637 smp->flags = SMP_F_VOL_TEST;
2638 smp->data.type = SMP_T_SINT;
2639 smp->data.u.sint = 0;
2640
Emeric Brun819fc6f2017-06-13 19:37:32 +02002641 if (!stkctr_entry(stkctr))
2642 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002643
Emeric Brun819fc6f2017-06-13 19:37:32 +02002644 if (stkctr && stkctr_entry(stkctr)) {
2645 void *ptr;
2646
2647 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2648 if (!ptr) {
2649 if (stkctr == &tmpstkctr)
2650 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002651 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002652 }
2653
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002654 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002655
Willy Tarreau7d562212016-11-25 16:10:05 +01002656 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2657 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002658
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002659 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002660
Willy Tarreau7d562212016-11-25 16:10:05 +01002661 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002663 }
2664 return 1;
2665}
2666
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002667/* Clear the General Purpose Counter 1 value from the stream's tracked
2668 * frontend counters and return its previous value into temp integer.
2669 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2670 */
2671static int
2672smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2673{
2674 struct stkctr tmpstkctr;
2675 struct stkctr *stkctr;
2676
2677 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2678 if (!stkctr)
2679 return 0;
2680
2681 smp->flags = SMP_F_VOL_TEST;
2682 smp->data.type = SMP_T_SINT;
2683 smp->data.u.sint = 0;
2684
2685 if (!stkctr_entry(stkctr))
2686 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2687
2688 if (stkctr && stkctr_entry(stkctr)) {
2689 void *ptr;
2690
2691 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2692 if (!ptr) {
2693 if (stkctr == &tmpstkctr)
2694 stktable_release(stkctr->table, stkctr_entry(stkctr));
2695 return 0; /* parameter not stored */
2696 }
2697
2698 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2699
2700 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2701 stktable_data_cast(ptr, gpc1) = 0;
2702
2703 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2704
2705 /* If data was modified, we need to touch to re-schedule sync */
2706 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2707 }
2708 return 1;
2709}
2710
Willy Tarreau7d562212016-11-25 16:10:05 +01002711/* set <smp> to the cumulated number of connections from the stream's tracked
2712 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2713 * "src_conn_cnt" only.
2714 */
2715static int
2716smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2717{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002718 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002719 struct stkctr *stkctr;
2720
Emeric Brun819fc6f2017-06-13 19:37:32 +02002721 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002722 if (!stkctr)
2723 return 0;
2724
2725 smp->flags = SMP_F_VOL_TEST;
2726 smp->data.type = SMP_T_SINT;
2727 smp->data.u.sint = 0;
2728 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002729 void *ptr;
2730
2731 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2732 if (!ptr) {
2733 if (stkctr == &tmpstkctr)
2734 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002735 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002736 }
2737
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002738 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002739
Willy Tarreau7d562212016-11-25 16:10:05 +01002740 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002741
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002742 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002743
2744 if (stkctr == &tmpstkctr)
2745 stktable_release(stkctr->table, stkctr_entry(stkctr));
2746
2747
Willy Tarreau7d562212016-11-25 16:10:05 +01002748 }
2749 return 1;
2750}
2751
2752/* set <smp> to the connection rate from the stream's tracked frontend
2753 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2754 * only.
2755 */
2756static int
2757smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2758{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002759 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002760 struct stkctr *stkctr;
2761
Emeric Brun819fc6f2017-06-13 19:37:32 +02002762 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002763 if (!stkctr)
2764 return 0;
2765
2766 smp->flags = SMP_F_VOL_TEST;
2767 smp->data.type = SMP_T_SINT;
2768 smp->data.u.sint = 0;
2769 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002770 void *ptr;
2771
2772 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2773 if (!ptr) {
2774 if (stkctr == &tmpstkctr)
2775 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002776 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002777 }
2778
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002779 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780
Willy Tarreau7d562212016-11-25 16:10:05 +01002781 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2782 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002783
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002784 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002785
2786 if (stkctr == &tmpstkctr)
2787 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002788 }
2789 return 1;
2790}
2791
2792/* set temp integer to the number of connections from the stream's source address
2793 * in the table pointed to by expr, after updating it.
2794 * Accepts exactly 1 argument of type table.
2795 */
2796static int
2797smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2798{
2799 struct connection *conn = objt_conn(smp->sess->origin);
2800 struct stksess *ts;
2801 struct stktable_key *key;
2802 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002803 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002804
2805 if (!conn)
2806 return 0;
2807
Joseph Herlant5662fa42018-11-15 13:43:28 -08002808 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002809 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2810 return 0;
2811
2812 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002813 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002814 if (!key)
2815 return 0;
2816
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002817 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002818
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002819 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002820 /* entry does not exist and could not be created */
2821 return 0;
2822
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002823 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002824 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002825 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002826 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002827
2828 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002829
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002830 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002831
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002834 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835
Willy Tarreau7d562212016-11-25 16:10:05 +01002836 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002837
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002838 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002839
2840 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002841 return 1;
2842}
2843
2844/* set <smp> to the number of concurrent connections from the stream's tracked
2845 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2846 * "src_conn_cur" only.
2847 */
2848static int
2849smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2850{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002851 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002852 struct stkctr *stkctr;
2853
Emeric Brun819fc6f2017-06-13 19:37:32 +02002854 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002855 if (!stkctr)
2856 return 0;
2857
2858 smp->flags = SMP_F_VOL_TEST;
2859 smp->data.type = SMP_T_SINT;
2860 smp->data.u.sint = 0;
2861 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002862 void *ptr;
2863
2864 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2865 if (!ptr) {
2866 if (stkctr == &tmpstkctr)
2867 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002868 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002869 }
2870
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002871 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002872
Willy Tarreau7d562212016-11-25 16:10:05 +01002873 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002874
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002875 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002876
2877 if (stkctr == &tmpstkctr)
2878 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 }
2880 return 1;
2881}
2882
2883/* set <smp> to the cumulated number of streams from the stream's tracked
2884 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2885 * "src_sess_cnt" only.
2886 */
2887static int
2888smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2889{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002890 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002891 struct stkctr *stkctr;
2892
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 if (!stkctr)
2895 return 0;
2896
2897 smp->flags = SMP_F_VOL_TEST;
2898 smp->data.type = SMP_T_SINT;
2899 smp->data.u.sint = 0;
2900 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002901 void *ptr;
2902
2903 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2904 if (!ptr) {
2905 if (stkctr == &tmpstkctr)
2906 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002907 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002908 }
2909
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002910 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002911
Willy Tarreau7d562212016-11-25 16:10:05 +01002912 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002913
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002914 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002915
2916 if (stkctr == &tmpstkctr)
2917 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002918 }
2919 return 1;
2920}
2921
2922/* set <smp> to the stream rate from the stream's tracked frontend counters.
2923 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2924 */
2925static int
2926smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2927{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002928 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002929 struct stkctr *stkctr;
2930
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002932 if (!stkctr)
2933 return 0;
2934
2935 smp->flags = SMP_F_VOL_TEST;
2936 smp->data.type = SMP_T_SINT;
2937 smp->data.u.sint = 0;
2938 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002939 void *ptr;
2940
2941 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2942 if (!ptr) {
2943 if (stkctr == &tmpstkctr)
2944 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002946 }
2947
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002948 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949
Willy Tarreau7d562212016-11-25 16:10:05 +01002950 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2951 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002953 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002954
2955 if (stkctr == &tmpstkctr)
2956 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 }
2958 return 1;
2959}
2960
2961/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2962 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2963 * "src_http_req_cnt" only.
2964 */
2965static int
2966smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2967{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002968 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002969 struct stkctr *stkctr;
2970
Emeric Brun819fc6f2017-06-13 19:37:32 +02002971 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002972 if (!stkctr)
2973 return 0;
2974
2975 smp->flags = SMP_F_VOL_TEST;
2976 smp->data.type = SMP_T_SINT;
2977 smp->data.u.sint = 0;
2978 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002979 void *ptr;
2980
2981 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2982 if (!ptr) {
2983 if (stkctr == &tmpstkctr)
2984 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002985 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002986 }
2987
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002988 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002989
Willy Tarreau7d562212016-11-25 16:10:05 +01002990 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002991
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002992 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002993
2994 if (stkctr == &tmpstkctr)
2995 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002996 }
2997 return 1;
2998}
2999
3000/* set <smp> to the HTTP request rate from the stream's tracked frontend
3001 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3002 * "src_http_req_rate" only.
3003 */
3004static int
3005smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3006{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003007 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003008 struct stkctr *stkctr;
3009
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003011 if (!stkctr)
3012 return 0;
3013
3014 smp->flags = SMP_F_VOL_TEST;
3015 smp->data.type = SMP_T_SINT;
3016 smp->data.u.sint = 0;
3017 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003018 void *ptr;
3019
3020 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3021 if (!ptr) {
3022 if (stkctr == &tmpstkctr)
3023 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003024 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003025 }
3026
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003027 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003028
Willy Tarreau7d562212016-11-25 16:10:05 +01003029 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3030 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003031
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003032 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003033
3034 if (stkctr == &tmpstkctr)
3035 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003036 }
3037 return 1;
3038}
3039
3040/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3041 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3042 * "src_http_err_cnt" only.
3043 */
3044static int
3045smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3046{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003047 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003048 struct stkctr *stkctr;
3049
Emeric Brun819fc6f2017-06-13 19:37:32 +02003050 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003051 if (!stkctr)
3052 return 0;
3053
3054 smp->flags = SMP_F_VOL_TEST;
3055 smp->data.type = SMP_T_SINT;
3056 smp->data.u.sint = 0;
3057 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003058 void *ptr;
3059
3060 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3061 if (!ptr) {
3062 if (stkctr == &tmpstkctr)
3063 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003064 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003065 }
3066
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003067 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068
Willy Tarreau7d562212016-11-25 16:10:05 +01003069 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003070
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003071 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003072
3073 if (stkctr == &tmpstkctr)
3074 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003075 }
3076 return 1;
3077}
3078
3079/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3080 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3081 * "src_http_err_rate" only.
3082 */
3083static int
3084smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3085{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003086 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003087 struct stkctr *stkctr;
3088
Emeric Brun819fc6f2017-06-13 19:37:32 +02003089 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003090 if (!stkctr)
3091 return 0;
3092
3093 smp->flags = SMP_F_VOL_TEST;
3094 smp->data.type = SMP_T_SINT;
3095 smp->data.u.sint = 0;
3096 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003097 void *ptr;
3098
3099 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3100 if (!ptr) {
3101 if (stkctr == &tmpstkctr)
3102 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003103 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003104 }
3105
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003106 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003107
Willy Tarreau7d562212016-11-25 16:10:05 +01003108 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3109 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003110
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003111 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003112
3113 if (stkctr == &tmpstkctr)
3114 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003115 }
3116 return 1;
3117}
3118
3119/* set <smp> to the number of kbytes received from clients, as found in the
3120 * stream's tracked frontend counters. Supports being called as
3121 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3122 */
3123static int
3124smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3125{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003126 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003127 struct stkctr *stkctr;
3128
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003130 if (!stkctr)
3131 return 0;
3132
3133 smp->flags = SMP_F_VOL_TEST;
3134 smp->data.type = SMP_T_SINT;
3135 smp->data.u.sint = 0;
3136 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003137 void *ptr;
3138
3139 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3140 if (!ptr) {
3141 if (stkctr == &tmpstkctr)
3142 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003143 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003144 }
3145
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003146 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003147
Willy Tarreau7d562212016-11-25 16:10:05 +01003148 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003149
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003150 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003151
3152 if (stkctr == &tmpstkctr)
3153 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003154 }
3155 return 1;
3156}
3157
3158/* set <smp> to the data rate received from clients in bytes/s, as found
3159 * in the stream's tracked frontend counters. Supports being called as
3160 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3161 */
3162static int
3163smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3164{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003165 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003166 struct stkctr *stkctr;
3167
Emeric Brun819fc6f2017-06-13 19:37:32 +02003168 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003169 if (!stkctr)
3170 return 0;
3171
3172 smp->flags = SMP_F_VOL_TEST;
3173 smp->data.type = SMP_T_SINT;
3174 smp->data.u.sint = 0;
3175 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003176 void *ptr;
3177
3178 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3179 if (!ptr) {
3180 if (stkctr == &tmpstkctr)
3181 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003182 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003183 }
3184
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003185 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003186
Willy Tarreau7d562212016-11-25 16:10:05 +01003187 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3188 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003189
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003190 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003191
3192 if (stkctr == &tmpstkctr)
3193 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003194 }
3195 return 1;
3196}
3197
3198/* set <smp> to the number of kbytes sent to clients, as found in the
3199 * stream's tracked frontend counters. Supports being called as
3200 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3201 */
3202static int
3203smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3204{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003205 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003206 struct stkctr *stkctr;
3207
Emeric Brun819fc6f2017-06-13 19:37:32 +02003208 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003209 if (!stkctr)
3210 return 0;
3211
3212 smp->flags = SMP_F_VOL_TEST;
3213 smp->data.type = SMP_T_SINT;
3214 smp->data.u.sint = 0;
3215 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003216 void *ptr;
3217
3218 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3219 if (!ptr) {
3220 if (stkctr == &tmpstkctr)
3221 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003222 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003223 }
3224
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003225 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003226
Willy Tarreau7d562212016-11-25 16:10:05 +01003227 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003229 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230
3231 if (stkctr == &tmpstkctr)
3232 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003233 }
3234 return 1;
3235}
3236
3237/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3238 * stream's tracked frontend counters. Supports being called as
3239 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3240 */
3241static int
3242smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3243{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003244 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003245 struct stkctr *stkctr;
3246
Emeric Brun819fc6f2017-06-13 19:37:32 +02003247 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003248 if (!stkctr)
3249 return 0;
3250
3251 smp->flags = SMP_F_VOL_TEST;
3252 smp->data.type = SMP_T_SINT;
3253 smp->data.u.sint = 0;
3254 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003255 void *ptr;
3256
3257 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3258 if (!ptr) {
3259 if (stkctr == &tmpstkctr)
3260 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003261 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003262 }
3263
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003264 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003265
Willy Tarreau7d562212016-11-25 16:10:05 +01003266 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3267 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003268
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003269 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003270
3271 if (stkctr == &tmpstkctr)
3272 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003273 }
3274 return 1;
3275}
3276
3277/* set <smp> to the number of active trackers on the SC entry in the stream's
3278 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3279 */
3280static int
3281smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3282{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003283 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003284 struct stkctr *stkctr;
3285
Emeric Brun819fc6f2017-06-13 19:37:32 +02003286 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003287 if (!stkctr)
3288 return 0;
3289
3290 smp->flags = SMP_F_VOL_TEST;
3291 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003292 if (stkctr == &tmpstkctr) {
3293 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3294 stktable_release(stkctr->table, stkctr_entry(stkctr));
3295 }
3296 else {
3297 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3298 }
3299
Willy Tarreau7d562212016-11-25 16:10:05 +01003300 return 1;
3301}
3302
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003303
3304/* The functions below are used to manipulate table contents from the CLI.
3305 * There are 3 main actions, "clear", "set" and "show". The code is shared
3306 * between all actions, and the action is encoded in the void *private in
3307 * the appctx as well as in the keyword registration, among one of the
3308 * following values.
3309 */
3310
3311enum {
3312 STK_CLI_ACT_CLR,
3313 STK_CLI_ACT_SET,
3314 STK_CLI_ACT_SHOW,
3315};
3316
3317/* Dump the status of a table to a stream interface's
3318 * read buffer. It returns 0 if the output buffer is full
3319 * and needs to be called again, otherwise non-zero.
3320 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003321static int table_dump_head_to_buffer(struct buffer *msg,
3322 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003323 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003324{
3325 struct stream *s = si_strm(si);
3326
3327 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003328 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003329
3330 /* any other information should be dumped here */
3331
William Lallemand07a62f72017-05-24 00:57:40 +02003332 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003333 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3334
Willy Tarreau06d80a92017-10-19 14:32:15 +02003335 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003336 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003337 return 0;
3338 }
3339
3340 return 1;
3341}
3342
3343/* Dump a table entry to a stream interface's
3344 * read buffer. It returns 0 if the output buffer is full
3345 * and needs to be called again, otherwise non-zero.
3346 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003347static int table_dump_entry_to_buffer(struct buffer *msg,
3348 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003349 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003350{
3351 int dt;
3352
3353 chunk_appendf(msg, "%p:", entry);
3354
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003355 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003356 char addr[INET_ADDRSTRLEN];
3357 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3358 chunk_appendf(msg, " key=%s", addr);
3359 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003360 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003361 char addr[INET6_ADDRSTRLEN];
3362 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3363 chunk_appendf(msg, " key=%s", addr);
3364 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003365 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003366 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003367 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003368 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003369 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003370 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003371 }
3372 else {
3373 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003374 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003375 }
3376
3377 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3378
3379 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3380 void *ptr;
3381
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003382 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003383 continue;
3384 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003385 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003386 else
3387 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3388
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003389 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003390 switch (stktable_data_types[dt].std_type) {
3391 case STD_T_SINT:
3392 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3393 break;
3394 case STD_T_UINT:
3395 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3396 break;
3397 case STD_T_ULL:
3398 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3399 break;
3400 case STD_T_FRQP:
3401 chunk_appendf(msg, "%d",
3402 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003403 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003404 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003405 case STD_T_DICT: {
3406 struct dict_entry *de;
3407 de = stktable_data_cast(ptr, std_t_dict);
3408 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3409 break;
3410 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003411 }
3412 }
3413 chunk_appendf(msg, "\n");
3414
Willy Tarreau06d80a92017-10-19 14:32:15 +02003415 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003416 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003417 return 0;
3418 }
3419
3420 return 1;
3421}
3422
3423
3424/* Processes a single table entry matching a specific key passed in argument.
3425 * returns 0 if wants to be called again, 1 if has ended processing.
3426 */
3427static int table_process_entry_per_key(struct appctx *appctx, char **args)
3428{
3429 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003430 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003431 struct stksess *ts;
3432 uint32_t uint32_key;
3433 unsigned char ip6_key[sizeof(struct in6_addr)];
3434 long long value;
3435 int data_type;
3436 int cur_arg;
3437 void *ptr;
3438 struct freq_ctr_period *frqp;
3439
Willy Tarreau9d008692019-08-09 11:21:01 +02003440 if (!*args[4])
3441 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003442
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003443 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003444 case SMP_T_IPV4:
3445 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003446 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003447 break;
3448 case SMP_T_IPV6:
3449 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003450 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003451 break;
3452 case SMP_T_SINT:
3453 {
3454 char *endptr;
3455 unsigned long val;
3456 errno = 0;
3457 val = strtoul(args[4], &endptr, 10);
3458 if ((errno == ERANGE && val == ULONG_MAX) ||
3459 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003460 val > 0xffffffff)
3461 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003462 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003463 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003464 break;
3465 }
3466 break;
3467 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003468 static_table_key.key = args[4];
3469 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003470 break;
3471 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003472 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003473 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003474 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 +01003475 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003476 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 +01003477 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003478 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 +01003479 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003480 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003481 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003482 }
3483
3484 /* check permissions */
3485 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3486 return 1;
3487
Willy Tarreaua24bc782016-12-14 15:50:35 +01003488 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003489 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003490 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003491 if (!ts)
3492 return 1;
3493 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003494 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3495 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003496 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003497 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003498 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003499 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003500 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003501 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003502 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003503 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003504 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003505 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003506 break;
3507
3508 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003509 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003510 if (!ts)
3511 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003512
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003513 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003514 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003515 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003516 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003517 break;
3518
3519 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003520 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003521 if (!ts) {
3522 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003523 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003524 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003525 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003526 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3527 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003528 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003529 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003530 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003531 return 1;
3532 }
3533
3534 data_type = stktable_get_data_type(args[cur_arg] + 5);
3535 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003536 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003537 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003538 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003539 return 1;
3540 }
3541
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003542 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003543 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003544 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003545 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003546 return 1;
3547 }
3548
3549 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003550 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003551 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003552 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003553 return 1;
3554 }
3555
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003556 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003557
3558 switch (stktable_data_types[data_type].std_type) {
3559 case STD_T_SINT:
3560 stktable_data_cast(ptr, std_t_sint) = value;
3561 break;
3562 case STD_T_UINT:
3563 stktable_data_cast(ptr, std_t_uint) = value;
3564 break;
3565 case STD_T_ULL:
3566 stktable_data_cast(ptr, std_t_ull) = value;
3567 break;
3568 case STD_T_FRQP:
3569 /* We set both the current and previous values. That way
3570 * the reported frequency is stable during all the period
3571 * then slowly fades out. This allows external tools to
3572 * push measures without having to update them too often.
3573 */
3574 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003575 /* First bit is reserved for the freq_ctr_period lock
3576 Note: here we're still protected by the stksess lock
3577 so we don't need to update the update the freq_ctr_period
3578 using its internal lock */
3579 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003580 frqp->prev_ctr = 0;
3581 frqp->curr_ctr = value;
3582 break;
3583 }
3584 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003585 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003586 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003587 break;
3588
3589 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003590 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003591 }
3592 return 1;
3593}
3594
3595/* Prepares the appctx fields with the data-based filters from the command line.
3596 * Returns 0 if the dump can proceed, 1 if has ended processing.
3597 */
3598static int table_prepare_data_request(struct appctx *appctx, char **args)
3599{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003600 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003601 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003602
Willy Tarreau9d008692019-08-09 11:21:01 +02003603 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3604 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003605
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003606 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3607 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3608 break;
3609 /* condition on stored data value */
3610 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3611 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003612 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003613
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003614 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003615 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 +01003616
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003617 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003618 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003619 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 +01003620
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003621 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 +01003622 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3623 }
3624
3625 if (*args[3+3*i]) {
3626 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 +01003627 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003628
3629 /* OK we're done, all the fields are set */
3630 return 0;
3631}
3632
3633/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003634static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003635{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003636 int i;
3637
3638 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3639 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003640 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003641 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003642 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643
3644 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003645 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003646 if (!appctx->ctx.table.target)
3647 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003648 }
3649 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003650 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003651 goto err_args;
3652 return 0;
3653 }
3654
3655 if (strcmp(args[3], "key") == 0)
3656 return table_process_entry_per_key(appctx, args);
3657 else if (strncmp(args[3], "data.", 5) == 0)
3658 return table_prepare_data_request(appctx, args);
3659 else if (*args[3])
3660 goto err_args;
3661
3662 return 0;
3663
3664err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003665 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003666 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003667 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 +01003668 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003669 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 +01003670 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003671 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003672 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003673 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003674 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003675}
3676
3677/* This function is used to deal with table operations (dump or clear depending
3678 * on the action stored in appctx->private). It returns 0 if the output buffer is
3679 * full and it needs to be called again, otherwise non-zero.
3680 */
3681static int cli_io_handler_table(struct appctx *appctx)
3682{
3683 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003684 struct stream *s = si_strm(si);
3685 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003686 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003687 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003688
3689 /*
3690 * We have 3 possible states in appctx->st2 :
3691 * - STAT_ST_INIT : the first call
3692 * - STAT_ST_INFO : the proxy pointer points to the next table to
3693 * dump, the entry pointer is NULL ;
3694 * - STAT_ST_LIST : the proxy pointer points to the current table
3695 * and the entry pointer points to the next entry to be dumped,
3696 * and the refcount on the next entry is held ;
3697 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3698 * data though.
3699 */
3700
3701 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3702 /* in case of abort, remove any refcount we might have set on an entry */
3703 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003704 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003705 }
3706 return 1;
3707 }
3708
3709 chunk_reset(&trash);
3710
3711 while (appctx->st2 != STAT_ST_FIN) {
3712 switch (appctx->st2) {
3713 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003714 appctx->ctx.table.t = appctx->ctx.table.target;
3715 if (!appctx->ctx.table.t)
3716 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003717
3718 appctx->ctx.table.entry = NULL;
3719 appctx->st2 = STAT_ST_INFO;
3720 break;
3721
3722 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003723 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003724 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003725 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003726 appctx->st2 = STAT_ST_END;
3727 break;
3728 }
3729
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003730 if (appctx->ctx.table.t->size) {
3731 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003732 return 0;
3733
3734 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003735 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003736 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003737 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3738 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003739 if (eb) {
3740 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3741 appctx->ctx.table.entry->ref_cnt++;
3742 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003743 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003744 break;
3745 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003746 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003747 }
3748 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003749 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003750 break;
3751
3752 case STAT_ST_LIST:
3753 skip_entry = 0;
3754
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003755 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003756
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003757 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003758 /* we're filtering on some data contents */
3759 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003760 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003761 signed char op;
3762 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003763
Emeric Brun819fc6f2017-06-13 19:37:32 +02003764
Willy Tarreau2b64a352020-01-22 17:09:47 +01003765 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003766 if (appctx->ctx.table.data_type[i] == -1)
3767 break;
3768 dt = appctx->ctx.table.data_type[i];
3769 ptr = stktable_data_ptr(appctx->ctx.table.t,
3770 appctx->ctx.table.entry,
3771 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003772
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003773 data = 0;
3774 switch (stktable_data_types[dt].std_type) {
3775 case STD_T_SINT:
3776 data = stktable_data_cast(ptr, std_t_sint);
3777 break;
3778 case STD_T_UINT:
3779 data = stktable_data_cast(ptr, std_t_uint);
3780 break;
3781 case STD_T_ULL:
3782 data = stktable_data_cast(ptr, std_t_ull);
3783 break;
3784 case STD_T_FRQP:
3785 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3786 appctx->ctx.table.t->data_arg[dt].u);
3787 break;
3788 }
3789
3790 op = appctx->ctx.table.data_op[i];
3791 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003792
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003793 /* skip the entry if the data does not match the test and the value */
3794 if ((data < value &&
3795 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3796 (data == value &&
3797 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3798 (data > value &&
3799 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3800 skip_entry = 1;
3801 break;
3802 }
3803 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003804 }
3805
3806 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003807 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003808 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003809 return 0;
3810 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003811
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003812 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003813
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003814 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003815 appctx->ctx.table.entry->ref_cnt--;
3816
3817 eb = ebmb_next(&appctx->ctx.table.entry->key);
3818 if (eb) {
3819 struct stksess *old = appctx->ctx.table.entry;
3820 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3821 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003822 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003823 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003824 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003825 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003826 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003827 break;
3828 }
3829
3830
3831 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003832 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003833 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003834 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003835
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003836 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003837
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003838 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003839 appctx->st2 = STAT_ST_INFO;
3840 break;
3841
3842 case STAT_ST_END:
3843 appctx->st2 = STAT_ST_FIN;
3844 break;
3845 }
3846 }
3847 return 1;
3848}
3849
3850static void cli_release_show_table(struct appctx *appctx)
3851{
3852 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003853 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003854 }
3855}
3856
3857/* register cli keywords */
3858static struct cli_kw_list cli_kws = {{ },{
3859 { { "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 },
3860 { { "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 },
3861 { { "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 },
3862 {{},}
3863}};
3864
Willy Tarreau0108d902018-11-25 19:14:37 +01003865INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003866
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003867static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003868 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003869 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003870 { "sc-set-gpt0", parse_set_gpt0, 1 },
3871 { /* END */ }
3872}};
3873
Willy Tarreau0108d902018-11-25 19:14:37 +01003874INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3875
Willy Tarreau620408f2016-10-21 16:37:51 +02003876static struct action_kw_list tcp_sess_kws = { { }, {
3877 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003878 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003879 { "sc-set-gpt0", parse_set_gpt0, 1 },
3880 { /* END */ }
3881}};
3882
Willy Tarreau0108d902018-11-25 19:14:37 +01003883INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3884
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003885static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003886 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003887 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003888 { "sc-set-gpt0", parse_set_gpt0, 1 },
3889 { /* END */ }
3890}};
3891
Willy Tarreau0108d902018-11-25 19:14:37 +01003892INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3893
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003894static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003895 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003896 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003897 { "sc-set-gpt0", parse_set_gpt0, 1 },
3898 { /* END */ }
3899}};
3900
Willy Tarreau0108d902018-11-25 19:14:37 +01003901INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3902
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003903static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003904 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003905 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003906 { "sc-set-gpt0", parse_set_gpt0, 1 },
3907 { /* END */ }
3908}};
3909
Willy Tarreau0108d902018-11-25 19:14:37 +01003910INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3911
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003912static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003913 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003914 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003915 { "sc-set-gpt0", parse_set_gpt0, 1 },
3916 { /* END */ }
3917}};
3918
Willy Tarreau0108d902018-11-25 19:14:37 +01003919INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3920
Willy Tarreau7d562212016-11-25 16:10:05 +01003921///* Note: must not be declared <const> as its list will be overwritten.
3922// * Please take care of keeping this list alphabetically sorted.
3923// */
3924//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3925// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3926// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3927// { /* END */ },
3928//}};
3929/* Note: must not be declared <const> as its list will be overwritten.
3930 * Please take care of keeping this list alphabetically sorted.
3931 */
3932static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3933 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3934 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3935 { "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 +01003936 { "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 +01003937 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3938 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3939 { "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 +01003940 { "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 +01003941 { "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 +01003942 { "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 +01003943 { "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 +01003944 { "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 +01003945 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3946 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3947 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3948 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3949 { "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 +01003950 { "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 +01003951 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3952 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3953 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3954 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3955 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3956 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3957 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3958 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3959 { "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 +01003960 { "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 +01003961 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3962 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3963 { "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 +01003964 { "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 +01003965 { "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 +01003966 { "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 +01003967 { "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 +01003968 { "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 +01003969 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3970 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3971 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3972 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3973 { "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 +01003974 { "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 +01003975 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3976 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3977 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3978 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3979 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3980 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3981 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3982 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "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 +01003984 { "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 +01003985 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3986 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3987 { "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 +01003988 { "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 +01003989 { "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 +01003990 { "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 +01003991 { "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 +01003992 { "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 +01003993 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3994 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3995 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3996 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3997 { "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 +01003998 { "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 +01003999 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4000 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4001 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4002 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4003 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4004 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4005 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4007 { "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 +01004008 { "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 +01004009 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4010 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4011 { "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 +01004012 { "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 +01004013 { "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 +01004014 { "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 +01004015 { "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 +01004016 { "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 +01004017 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4018 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4019 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4020 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4021 { "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 +01004022 { "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 +01004023 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4024 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4025 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4026 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4027 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4028 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4029 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4030 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4031 { "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 +01004032 { "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 +01004033 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4034 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4035 { "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 +01004036 { "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 +01004037 { "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 +01004038 { "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 +01004039 { "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 +01004040 { "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 +01004041 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4042 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4043 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4044 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4045 { "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 +01004046 { "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 +01004047 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4048 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4049 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4050 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4051 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4052 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4053 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4054 { /* END */ },
4055}};
4056
Willy Tarreau0108d902018-11-25 19:14:37 +01004057INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004058
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004059/* Note: must not be declared <const> as its list will be overwritten */
4060static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004061 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4062 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4063 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4064 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4065 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4066 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4067 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4068 { "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 +01004069 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004070 { "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 +01004071 { "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 +02004072 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4073 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4074 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4075 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4076 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4077 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4078 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4079 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4080 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4081 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004082 { /* END */ },
4083}};
4084
Willy Tarreau0108d902018-11-25 19:14:37 +01004085INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);