blob: b1288eb5c237413257c4494e9367871220fdd0e0 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
Willy Tarreaub2551052020-06-09 09:07:15 +020017#include <import/ebmbtree.h>
18#include <import/ebsttree.h>
19#include <import/ebistree.h>
20
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020023#include <haproxy/cfgparse.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020024#include <haproxy/cli.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020025#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020026#include <haproxy/global.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020027#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +020028#include <haproxy/list.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020029#include <haproxy/log.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +020030#include <haproxy/net_helper.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +020031#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020032#include <haproxy/pool.h>
33#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020034#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020035#include <haproxy/sample.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020036#include <haproxy/stats-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037#include <haproxy/stick_table.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020038#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020039#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020040#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020041#include <haproxy/tcp_rules.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020042#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020043#include <haproxy/tools.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010044
Emeric Brun3bd697e2010-01-04 15:23:48 +010045
Willy Tarreau12785782012-04-27 21:37:17 +020046/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020047static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreau478331d2020-08-28 11:31:31 +020048static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020049
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010050struct stktable *stktables_list;
51struct eb_root stktable_by_name = EB_ROOT;
52
Olivier Houchard52dabbc2018-11-14 17:54:36 +010053#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +010054
55/* This function inserts stktable <t> into the tree of known stick-table.
56 * The stick-table ID is used as the storing key so it must already have
57 * been initialized.
58 */
59void stktable_store_name(struct stktable *t)
60{
61 t->name.key = t->id;
62 ebis_insert(&stktable_by_name, &t->name);
63}
64
65struct stktable *stktable_find_by_name(const char *name)
66{
67 struct ebpt_node *node;
68 struct stktable *t;
69
70 node = ebis_lookup(&stktable_by_name, name);
71 if (node) {
72 t = container_of(node, struct stktable, name);
73 if (!strcmp(t->id, name))
74 return t;
75 }
76
77 return NULL;
78}
79
Emeric Brun3bd697e2010-01-04 15:23:48 +010080/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020081 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
82 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010083 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020084void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010085{
86 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010087 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010088}
89
90/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020091 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
92 * in table <t>.
93 * This function locks the table
94 */
95void stksess_free(struct stktable *t, struct stksess *ts)
96{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010097 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020098 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010099 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200100}
101
102/*
Willy Tarreauf6efda12010-08-03 20:34:06 +0200103 * Kill an stksess (only if its ref_cnt is zero).
104 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200105int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +0200106{
107 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200108 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200109
110 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +0200111 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +0200112 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200113 __stksess_free(t, ts);
114 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +0200115}
116
117/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200118 * Decrease the refcount if decrefcnt is not 0.
119 * and try to kill the stksess
120 * This function locks the table
121 */
122int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
123{
124 int ret;
125
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100126 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200127 if (decrefcnt)
128 ts->ref_cnt--;
129 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100130 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200131
132 return ret;
133}
134
135/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200136 * Initialize or update the key in the sticky session <ts> present in table <t>
137 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100138 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200139void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100140{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200141 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200142 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100143 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200144 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
145 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100146 }
147}
148
149
150/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200151 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
152 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200154static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100155{
Willy Tarreau393379c2010-06-06 12:11:37 +0200156 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200157 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200158 ts->key.node.leaf_p = NULL;
159 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200160 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200161 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100162 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100163 return ts;
164}
165
166/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200167 * Trash oldest <to_batch> sticky sessions from table <t>
Willy Tarreaudfe79252020-11-03 17:47:41 +0100168 * Returns number of trashed sticky sessions. It may actually trash less
169 * than expected if finding these requires too long a search time (e.g.
170 * most of them have ts->ref_cnt>0).
Emeric Brun3bd697e2010-01-04 15:23:48 +0100171 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200172int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100173{
174 struct stksess *ts;
175 struct eb32_node *eb;
Willy Tarreaudfe79252020-11-03 17:47:41 +0100176 int max_search = to_batch * 2; // no more than 50% misses
Emeric Brun3bd697e2010-01-04 15:23:48 +0100177 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200178 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100179
180 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
181
182 while (batched < to_batch) {
183
184 if (unlikely(!eb)) {
185 /* we might have reached the end of the tree, typically because
186 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200187 * half. Let's loop back to the beginning of the tree now if we
188 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100189 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200190 if (looped)
191 break;
192 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100193 eb = eb32_first(&t->exps);
194 if (likely(!eb))
195 break;
196 }
197
Willy Tarreaudfe79252020-11-03 17:47:41 +0100198 if (--max_search < 0)
199 break;
200
Emeric Brun3bd697e2010-01-04 15:23:48 +0100201 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200202 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100203 eb = eb32_next(eb);
204
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200205 /* don't delete an entry which is currently referenced */
206 if (ts->ref_cnt)
207 continue;
208
Willy Tarreau86257dc2010-06-06 12:57:10 +0200209 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100210
Willy Tarreau86257dc2010-06-06 12:57:10 +0200211 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100212 if (!tick_isset(ts->expire))
213 continue;
214
Willy Tarreau86257dc2010-06-06 12:57:10 +0200215 ts->exp.key = ts->expire;
216 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217
Willy Tarreau86257dc2010-06-06 12:57:10 +0200218 if (!eb || eb->key > ts->exp.key)
219 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100220
221 continue;
222 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100223
Willy Tarreauaea940e2010-06-06 11:56:36 +0200224 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200225 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200226 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200227 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100228 batched++;
229 }
230
231 return batched;
232}
233
234/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200235 * Trash oldest <to_batch> sticky sessions from table <t>
236 * Returns number of trashed sticky sessions.
237 * This function locks the table
238 */
239int stktable_trash_oldest(struct stktable *t, int to_batch)
240{
241 int ret;
242
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100243 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200244 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100245 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200246
247 return ret;
248}
249/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200250 * Allocate and initialise a new sticky session.
251 * The new sticky session is returned or NULL in case of lack of memory.
252 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200253 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
254 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100255 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200256struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100257{
258 struct stksess *ts;
259
260 if (unlikely(t->current == t->size)) {
261 if ( t->nopurge )
262 return NULL;
263
Emeric Brun819fc6f2017-06-13 19:37:32 +0200264 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265 return NULL;
266 }
267
Willy Tarreaubafbe012017-11-24 17:34:44 +0100268 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100269 if (ts) {
270 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100271 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200272 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200273 if (key)
274 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100275 }
276
277 return ts;
278}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200279/*
280 * Allocate and initialise a new sticky session.
281 * The new sticky session is returned or NULL in case of lack of memory.
282 * Sticky sessions should only be allocated this way, and must be freed using
283 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
284 * is not NULL, it is assigned to the new session.
285 * This function locks the table
286 */
287struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
288{
289 struct stksess *ts;
290
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100291 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200292 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100293 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200294
295 return ts;
296}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100297
298/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200299 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200300 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100301 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200302struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100303{
304 struct ebmb_node *eb;
305
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200306 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200307 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 +0100308 else
309 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
310
311 if (unlikely(!eb)) {
312 /* no session found */
313 return NULL;
314 }
315
Willy Tarreau86257dc2010-06-06 12:57:10 +0200316 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100317}
318
Emeric Brun819fc6f2017-06-13 19:37:32 +0200319/*
320 * Looks in table <t> for a sticky session matching key <key>.
321 * Returns pointer on requested sticky session or NULL if none was found.
322 * The refcount of the found entry is increased and this function
323 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200324 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200325struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200326{
327 struct stksess *ts;
328
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100329 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200330 ts = __stktable_lookup_key(t, key);
331 if (ts)
332 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100333 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200334
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200335 return ts;
336}
337
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200338/*
339 * Looks in table <t> for a sticky session with same key as <ts>.
340 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100341 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200342struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100343{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100344 struct ebmb_node *eb;
345
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200346 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200347 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100348 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200349 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200351 if (unlikely(!eb))
352 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100353
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200354 return ebmb_entry(eb, struct stksess, key);
355}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100356
Emeric Brun819fc6f2017-06-13 19:37:32 +0200357/*
358 * Looks in table <t> for a sticky session with same key as <ts>.
359 * Returns pointer on requested sticky session or NULL if none was found.
360 * The refcount of the found entry is increased and this function
361 * is protected using the table lock
362 */
363struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
364{
365 struct stksess *lts;
366
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100367 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200368 lts = __stktable_lookup(t, ts);
369 if (lts)
370 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100371 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372
373 return lts;
374}
375
Willy Tarreaucb183642010-06-06 17:58:34 +0200376/* Update the expiration timer for <ts> but do not touch its expiration node.
377 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200378 * The node will be also inserted into the update tree if needed, at a position
379 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200380 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200381void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200382{
Emeric Brun85e77c72010-09-23 18:16:52 +0200383 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200384 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200385 if (t->expire) {
386 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
387 task_queue(t->exp_task);
388 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200389
Emeric Brun819fc6f2017-06-13 19:37:32 +0200390 /* If sync is enabled */
391 if (t->sync_task) {
392 if (local) {
393 /* If this entry is not in the tree
394 or not scheduled for at least one peer */
395 if (!ts->upd.node.leaf_p
396 || (int)(t->commitupdate - ts->upd.key) >= 0
397 || (int)(ts->upd.key - t->localupdate) >= 0) {
398 ts->upd.key = ++t->update;
399 t->localupdate = t->update;
400 eb32_delete(&ts->upd);
401 eb = eb32_insert(&t->updates, &ts->upd);
402 if (eb != &ts->upd) {
403 eb32_delete(eb);
404 eb32_insert(&t->updates, &ts->upd);
405 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200406 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200407 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200408 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200409 else {
410 /* If this entry is not in the tree */
411 if (!ts->upd.node.leaf_p) {
412 ts->upd.key= (++t->update)+(2147483648U);
413 eb = eb32_insert(&t->updates, &ts->upd);
414 if (eb != &ts->upd) {
415 eb32_delete(eb);
416 eb32_insert(&t->updates, &ts->upd);
417 }
418 }
419 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200420 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200421}
422
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200423/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200424 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200425 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200426 * The node will be also inserted into the update tree if needed, at a position
427 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200428 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200429void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
430{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100431 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200432 __stktable_touch_with_exp(t, ts, 0, ts->expire);
433 if (decrefcnt)
434 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100435 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200436}
437
438/* Update the expiration timer for <ts> but do not touch its expiration node.
439 * The table's expiration timer is updated using the date of expiration coming from
440 * <t> stick-table configuration.
441 * The node will be also inserted into the update tree if needed, at a position
442 * considering the update was made locally
443 */
444void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200445{
446 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
447
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100448 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200449 __stktable_touch_with_exp(t, ts, 1, expire);
450 if (decrefcnt)
451 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100452 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453}
Willy Tarreau43e90352018-06-27 06:25:57 +0200454/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
455static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456{
Willy Tarreau43e90352018-06-27 06:25:57 +0200457 if (!ts)
458 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100459 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100461 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200462}
463
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200464/* Insert new sticky session <ts> in the table. It is assumed that it does not
465 * yet exist (the caller must check this). The table's timeout is updated if it
466 * is set. <ts> is returned.
467 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200468void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200469{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100470
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200471 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200472 ts->exp.key = ts->expire;
473 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200474 if (t->expire) {
475 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
476 task_queue(t->exp_task);
477 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200478}
479
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200480/* Returns a valid or initialized stksess for the specified stktable_key in the
481 * specified table, or NULL if the key was NULL, or if no entry was found nor
482 * could be created. The entry's expiration is updated.
483 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200484struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200485{
486 struct stksess *ts;
487
488 if (!key)
489 return NULL;
490
Emeric Brun819fc6f2017-06-13 19:37:32 +0200491 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200492 if (ts == NULL) {
493 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200494 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200495 if (!ts)
496 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200497 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200498 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200499 return ts;
500}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200501/* Returns a valid or initialized stksess for the specified stktable_key in the
502 * specified table, or NULL if the key was NULL, or if no entry was found nor
503 * could be created. The entry's expiration is updated.
504 * This function locks the table, and the refcount of the entry is increased.
505 */
506struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
507{
508 struct stksess *ts;
509
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100510 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200511 ts = __stktable_get_entry(table, key);
512 if (ts)
513 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100514 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200515
516 return ts;
517}
518
519/* Lookup for an entry with the same key and store the submitted
520 * stksess if not found.
521 */
522struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
523{
524 struct stksess *ts;
525
526 ts = __stktable_lookup(table, nts);
527 if (ts == NULL) {
528 ts = nts;
529 __stktable_store(table, ts);
530 }
531 return ts;
532}
533
534/* Lookup for an entry with the same key and store the submitted
535 * stksess if not found.
536 * This function locks the table, and the refcount of the entry is increased.
537 */
538struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
539{
540 struct stksess *ts;
541
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100542 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200543 ts = __stktable_set_entry(table, nts);
544 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100545 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200546
Emeric Brun819fc6f2017-06-13 19:37:32 +0200547 return ts;
548}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100549/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200550 * Trash expired sticky sessions from table <t>. The next expiration date is
551 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100552 */
553static int stktable_trash_expired(struct stktable *t)
554{
555 struct stksess *ts;
556 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200557 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100558
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100559 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100560 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
561
562 while (1) {
563 if (unlikely(!eb)) {
564 /* we might have reached the end of the tree, typically because
565 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200566 * half. Let's loop back to the beginning of the tree now if we
567 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100568 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200569 if (looped)
570 break;
571 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100572 eb = eb32_first(&t->exps);
573 if (likely(!eb))
574 break;
575 }
576
577 if (likely(tick_is_lt(now_ms, eb->key))) {
578 /* timer not expired yet, revisit it later */
579 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100580 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100581 }
582
583 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200584 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100585 eb = eb32_next(eb);
586
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200587 /* don't delete an entry which is currently referenced */
588 if (ts->ref_cnt)
589 continue;
590
Willy Tarreau86257dc2010-06-06 12:57:10 +0200591 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592
593 if (!tick_is_expired(ts->expire, now_ms)) {
594 if (!tick_isset(ts->expire))
595 continue;
596
Willy Tarreau86257dc2010-06-06 12:57:10 +0200597 ts->exp.key = ts->expire;
598 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
Willy Tarreau86257dc2010-06-06 12:57:10 +0200600 if (!eb || eb->key > ts->exp.key)
601 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100602 continue;
603 }
604
605 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200606 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200607 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200608 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 }
610
611 /* We have found no task to expire in any tree */
612 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100613out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100614 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100615 return t->exp_next;
616}
617
618/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200619 * Task processing function to trash expired sticky sessions. A pointer to the
620 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100621 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200622static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100623{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200624 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100625
626 task->expire = stktable_trash_expired(t);
627 return task;
628}
629
Willy Tarreauaea940e2010-06-06 11:56:36 +0200630/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100631int stktable_init(struct stktable *t)
632{
Remi Tricot-Le Bretoncff2df92021-05-12 17:39:04 +0200633 int peers_retval = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100634 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200635 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100636 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100637 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100638 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100640 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 +0100641
642 t->exp_next = TICK_ETERNITY;
643 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200644 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200645 if (!t->exp_task)
646 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100648 t->exp_task->context = (void *)t;
649 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200650 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Remi Tricot-Le Bretoncff2df92021-05-12 17:39:04 +0200651 peers_retval = peers_register_table(t->peers.p, t);
Emeric Brun32da3c42010-09-23 18:39:19 +0200652 }
653
Remi Tricot-Le Bretoncff2df92021-05-12 17:39:04 +0200654 return (t->pool != NULL) && !peers_retval;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 }
656 return 1;
657}
658
659/*
660 * Configuration keywords of known table types
661 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200662struct stktable_type stktable_types[SMP_TYPES] = {
663 [SMP_T_SINT] = { "integer", 0, 4 },
664 [SMP_T_IPV4] = { "ip", 0, 4 },
665 [SMP_T_IPV6] = { "ipv6", 0, 16 },
666 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
667 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
668};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100669
670/*
671 * Parse table type configuration.
672 * Returns 0 on successful parsing, else 1.
673 * <myidx> is set at next configuration <args> index.
674 */
675int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
676{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200677 for (*type = 0; *type < SMP_TYPES; (*type)++) {
678 if (!stktable_types[*type].kw)
679 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100680 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
681 continue;
682
683 *key_size = stktable_types[*type].default_size;
684 (*myidx)++;
685
Willy Tarreauaea940e2010-06-06 11:56:36 +0200686 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100687 if (strcmp("len", args[*myidx]) == 0) {
688 (*myidx)++;
689 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200690 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100691 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200692 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200693 /* null terminated string needs +1 for '\0'. */
694 (*key_size)++;
695 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100696 (*myidx)++;
697 }
698 }
699 return 0;
700 }
701 return 1;
702}
703
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100704/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100705 * Parse a line with <linenum> as number in <file> configuration file to configure
706 * the stick-table with <t> as address and <id> as ID.
707 * <peers> provides the "peers" section pointer only if this function is called
708 * from a "peers" section.
709 * <nid> is the stick-table name which is sent over the network. It must be equal
710 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
711 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500712 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100713 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
714 */
715int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100716 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100717{
718 int err_code = 0;
719 int idx = 1;
720 unsigned int val;
721
722 if (!id || !*id) {
723 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
724 err_code |= ERR_ALERT | ERR_ABORT;
725 goto out;
726 }
727
728 /* Store the "peers" section if this function is called from a "peers" section. */
729 if (peers) {
730 t->peers.p = peers;
731 idx++;
732 }
733
734 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100735 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100736 t->type = (unsigned int)-1;
737 t->conf.file = file;
738 t->conf.line = linenum;
739
740 while (*args[idx]) {
741 const char *err;
742
743 if (strcmp(args[idx], "size") == 0) {
744 idx++;
745 if (!*(args[idx])) {
746 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
747 file, linenum, args[0], args[idx-1]);
748 err_code |= ERR_ALERT | ERR_FATAL;
749 goto out;
750 }
751 if ((err = parse_size_err(args[idx], &t->size))) {
752 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
753 file, linenum, args[0], *err, args[idx-1]);
754 err_code |= ERR_ALERT | ERR_FATAL;
755 goto out;
756 }
757 idx++;
758 }
759 /* This argument does not exit in "peers" section. */
760 else if (!peers && strcmp(args[idx], "peers") == 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 t->peers.name = strdup(args[idx++]);
769 }
770 else if (strcmp(args[idx], "expire") == 0) {
771 idx++;
772 if (!*(args[idx])) {
773 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
774 file, linenum, args[0], args[idx-1]);
775 err_code |= ERR_ALERT | ERR_FATAL;
776 goto out;
777 }
778 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200779 if (err == PARSE_TIME_OVER) {
780 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
781 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100782 err_code |= ERR_ALERT | ERR_FATAL;
783 goto out;
784 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200785 else if (err == PARSE_TIME_UNDER) {
786 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
787 file, linenum, args[0], args[idx], args[idx-1]);
788 err_code |= ERR_ALERT | ERR_FATAL;
789 goto out;
790 }
791 else if (err) {
792 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
793 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100794 err_code |= ERR_ALERT | ERR_FATAL;
795 goto out;
796 }
797 t->expire = val;
798 idx++;
799 }
800 else if (strcmp(args[idx], "nopurge") == 0) {
801 t->nopurge = 1;
802 idx++;
803 }
804 else if (strcmp(args[idx], "type") == 0) {
805 idx++;
806 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
807 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
808 file, linenum, args[0], args[idx]);
809 err_code |= ERR_ALERT | ERR_FATAL;
810 goto out;
811 }
812 /* idx already points to next arg */
813 }
814 else if (strcmp(args[idx], "store") == 0) {
815 int type, err;
816 char *cw, *nw, *sa;
817
818 idx++;
819 nw = args[idx];
820 while (*nw) {
821 /* the "store" keyword supports a comma-separated list */
822 cw = nw;
823 sa = NULL; /* store arg */
824 while (*nw && *nw != ',') {
825 if (*nw == '(') {
826 *nw = 0;
827 sa = ++nw;
828 while (*nw != ')') {
829 if (!*nw) {
830 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
831 file, linenum, args[0], cw);
832 err_code |= ERR_ALERT | ERR_FATAL;
833 goto out;
834 }
835 nw++;
836 }
837 *nw = '\0';
838 }
839 nw++;
840 }
841 if (*nw)
842 *nw++ = '\0';
843 type = stktable_get_data_type(cw);
844 if (type < 0) {
845 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
846 file, linenum, args[0], cw);
847 err_code |= ERR_ALERT | ERR_FATAL;
848 goto out;
849 }
850
851 err = stktable_alloc_data_type(t, type, sa);
852 switch (err) {
853 case PE_NONE: break;
854 case PE_EXIST:
855 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
856 file, linenum, args[0], cw);
857 err_code |= ERR_WARN;
858 break;
859
860 case PE_ARG_MISSING:
861 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
862 file, linenum, args[0], cw);
863 err_code |= ERR_ALERT | ERR_FATAL;
864 goto out;
865
866 case PE_ARG_NOT_USED:
867 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
868 file, linenum, args[0], cw);
869 err_code |= ERR_ALERT | ERR_FATAL;
870 goto out;
871
872 default:
873 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
874 file, linenum, args[0], cw);
875 err_code |= ERR_ALERT | ERR_FATAL;
876 goto out;
877 }
878 }
879 idx++;
880 }
881 else {
882 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
883 file, linenum, args[0], args[idx]);
884 err_code |= ERR_ALERT | ERR_FATAL;
885 goto out;
886 }
887 }
888
889 if (!t->size) {
890 ha_alert("parsing [%s:%d] : %s: missing size.\n",
891 file, linenum, args[0]);
892 err_code |= ERR_ALERT | ERR_FATAL;
893 goto out;
894 }
895
896 if (t->type == (unsigned int)-1) {
897 ha_alert("parsing [%s:%d] : %s: missing type.\n",
898 file, linenum, args[0]);
899 err_code |= ERR_ALERT | ERR_FATAL;
900 goto out;
901 }
902
903 out:
904 return err_code;
905}
906
Willy Tarreau8fed9032014-07-03 17:02:46 +0200907/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200908 * Note that the sample *is* modified and that the returned key may point
909 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200910 * Returns NULL if the sample could not be converted (eg: no matching type),
911 * otherwise a pointer to the static stktable_key filled with what is needed
912 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200913 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200914struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200915{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200916 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200917 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200918 return NULL;
919
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200920 /* Fill static_table_key. */
921 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200922
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200923 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200924 static_table_key.key = &smp->data.u.ipv4;
925 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200926 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200927
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200928 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200929 static_table_key.key = &smp->data.u.ipv6;
930 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200931 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200932
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200933 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200934 /* The stick table require a 32bit unsigned int, "sint" is a
935 * signed 64 it, so we can convert it inplace.
936 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200937 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200938 static_table_key.key = &smp->data.u.sint;
939 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200940 break;
941
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200942 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200943 if (!smp_make_safe(smp))
944 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200945 static_table_key.key = smp->data.u.str.area;
946 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200947 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200948
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200949 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200950 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200951 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200952 if (!smp_make_rw(smp))
953 return NULL;
954
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200955 if (smp->data.u.str.size < t->key_size)
956 if (!smp_dup(smp))
957 return NULL;
958 if (smp->data.u.str.size < t->key_size)
959 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200960 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
961 t->key_size - smp->data.u.str.data);
962 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200963 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200964 static_table_key.key = smp->data.u.str.area;
965 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200966 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200967
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200968 default: /* impossible case. */
969 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200970 }
971
Christopher Fauletca20d022017-08-29 15:30:31 +0200972 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200973}
974
975/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200976 * Process a fetch + format conversion as defined by the sample expression <expr>
977 * on request or response considering the <opt> parameter. Returns either NULL if
978 * no key could be extracted, or a pointer to the converted result stored in
979 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
980 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200981 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
982 * without SMP_OPT_FINAL). The output will be usable like this :
983 *
984 * return MAY_CHANGE FINAL Meaning for the sample
985 * NULL 0 * Not present and will never be (eg: header)
986 * NULL 1 0 Not present or unstable, could change (eg: req_len)
987 * NULL 1 1 Not present, will not change anymore
988 * smp 0 * Present and will not change (eg: header)
989 * smp 1 0 not possible
990 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200991 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200992struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200993 unsigned int opt, struct sample_expr *expr, struct sample *smp)
994{
995 if (smp)
996 memset(smp, 0, sizeof(*smp));
997
Willy Tarreau192252e2015-04-04 01:47:55 +0200998 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200999 if (!smp)
1000 return NULL;
1001
1002 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1003 return NULL; /* we can only use stable samples */
1004
1005 return smp_to_stkey(smp, t);
1006}
1007
1008/*
Willy Tarreau12785782012-04-27 21:37:17 +02001009 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001010 * type <table_type>, otherwise zero. Used in configuration check.
1011 */
Willy Tarreau12785782012-04-27 21:37:17 +02001012int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001013{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001014 int out_type;
1015
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001016 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001017 return 0;
1018
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001019 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001020
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001021 /* Convert sample. */
1022 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001023 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001024
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001025 return 1;
1026}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001027
Willy Tarreauedee1d62014-07-15 16:44:27 +02001028/* Extra data types processing : after the last one, some room may remain
1029 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1030 * at run time.
1031 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001032struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001033 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001034 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001035 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001036 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001037 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1038 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1039 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1040 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1041 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1042 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1043 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1044 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1045 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1046 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1047 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1048 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1049 [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 +01001050 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1051 [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 +02001052 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001053};
1054
Willy Tarreauedee1d62014-07-15 16:44:27 +02001055/* Registers stick-table extra data type with index <idx>, name <name>, type
1056 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1057 * index is automatically allocated. The allocated index is returned, or -1 if
1058 * no free index was found or <name> was already registered. The <name> is used
1059 * directly as a pointer, so if it's not stable, the caller must allocate it.
1060 */
1061int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1062{
1063 if (idx < 0) {
1064 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1065 if (!stktable_data_types[idx].name)
1066 break;
1067
1068 if (strcmp(stktable_data_types[idx].name, name) == 0)
1069 return -1;
1070 }
1071 }
1072
1073 if (idx >= STKTABLE_DATA_TYPES)
1074 return -1;
1075
1076 if (stktable_data_types[idx].name != NULL)
1077 return -1;
1078
1079 stktable_data_types[idx].name = name;
1080 stktable_data_types[idx].std_type = std_type;
1081 stktable_data_types[idx].arg_type = arg_type;
1082 return idx;
1083}
1084
Willy Tarreau08d5f982010-06-06 13:34:54 +02001085/*
1086 * Returns the data type number for the stktable_data_type whose name is <name>,
1087 * or <0 if not found.
1088 */
1089int stktable_get_data_type(char *name)
1090{
1091 int type;
1092
1093 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001094 if (!stktable_data_types[type].name)
1095 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001096 if (strcmp(name, stktable_data_types[type].name) == 0)
1097 return type;
1098 }
1099 return -1;
1100}
1101
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001102/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1103 * it up into this table. Returns true if found, false otherwise. The input
1104 * type is STR so that input samples are converted to string (since all types
1105 * can be converted to strings), then the function casts the string again into
1106 * the table's type. This is a double conversion, but in the future we might
1107 * support automatic input types to perform the cast on the fly.
1108 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001109static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001110{
1111 struct stktable *t;
1112 struct stktable_key *key;
1113 struct stksess *ts;
1114
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001115 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001116
1117 key = smp_to_stkey(smp, t);
1118 if (!key)
1119 return 0;
1120
1121 ts = stktable_lookup_key(t, key);
1122
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001123 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001124 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001125 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001126 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001127 return 1;
1128}
1129
1130/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1131 * it up into this table. Returns the data rate received from clients in bytes/s
1132 * if the key is present in the table, otherwise zero, so that comparisons can
1133 * be easily performed. If the inspected parameter is not stored in the table,
1134 * <not found> is returned.
1135 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001136static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001137{
1138 struct stktable *t;
1139 struct stktable_key *key;
1140 struct stksess *ts;
1141 void *ptr;
1142
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001143 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001144
1145 key = smp_to_stkey(smp, t);
1146 if (!key)
1147 return 0;
1148
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001149 ts = stktable_lookup_key(t, key);
1150
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001151 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001152 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001153 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001154
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001155 if (!ts) /* key not present */
1156 return 1;
1157
1158 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001159 if (ptr)
1160 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1161 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001162
Daniel Corbett3e60b112018-05-27 09:47:12 -04001163 stktable_release(t, ts);
1164 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001165}
1166
1167/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1168 * it up into this table. Returns the cumulated number of connections for the key
1169 * if the key is present in the table, otherwise zero, so that comparisons can
1170 * be easily performed. If the inspected parameter is not stored in the table,
1171 * <not found> is returned.
1172 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001173static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001174{
1175 struct stktable *t;
1176 struct stktable_key *key;
1177 struct stksess *ts;
1178 void *ptr;
1179
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001180 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001181
1182 key = smp_to_stkey(smp, t);
1183 if (!key)
1184 return 0;
1185
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001186 ts = stktable_lookup_key(t, key);
1187
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001188 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001189 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001190 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001191
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001192 if (!ts) /* key not present */
1193 return 1;
1194
1195 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001196 if (ptr)
1197 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001198
Daniel Corbett3e60b112018-05-27 09:47:12 -04001199 stktable_release(t, ts);
1200 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001201}
1202
1203/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1204 * it up into this table. Returns the number of concurrent connections for the
1205 * key if the key is present in the table, otherwise zero, so that comparisons
1206 * can be easily performed. If the inspected parameter is not stored in the
1207 * table, <not found> is returned.
1208 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001209static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001210{
1211 struct stktable *t;
1212 struct stktable_key *key;
1213 struct stksess *ts;
1214 void *ptr;
1215
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001216 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001217
1218 key = smp_to_stkey(smp, t);
1219 if (!key)
1220 return 0;
1221
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001222 ts = stktable_lookup_key(t, key);
1223
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001224 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001225 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001226 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001227
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001228 if (!ts) /* key not present */
1229 return 1;
1230
1231 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001232 if (ptr)
1233 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001234
Daniel Corbett3e60b112018-05-27 09:47:12 -04001235 stktable_release(t, ts);
1236 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001237}
1238
1239/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1240 * it up into this table. Returns the rate of incoming connections from the key
1241 * if the key is present in the table, otherwise zero, so that comparisons can
1242 * be easily performed. If the inspected parameter is not stored in the table,
1243 * <not found> is returned.
1244 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001245static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001246{
1247 struct stktable *t;
1248 struct stktable_key *key;
1249 struct stksess *ts;
1250 void *ptr;
1251
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001252 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001253
1254 key = smp_to_stkey(smp, t);
1255 if (!key)
1256 return 0;
1257
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001258 ts = stktable_lookup_key(t, key);
1259
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001260 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001261 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001262 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001263
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001264 if (!ts) /* key not present */
1265 return 1;
1266
1267 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001268 if (ptr)
1269 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1270 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271
Daniel Corbett3e60b112018-05-27 09:47:12 -04001272 stktable_release(t, ts);
1273 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001274}
1275
1276/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1277 * it up into this table. Returns the data rate sent to clients in bytes/s
1278 * if the key is present in the table, otherwise zero, so that comparisons can
1279 * be easily performed. If the inspected parameter is not stored in the table,
1280 * <not found> is returned.
1281 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001282static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001283{
1284 struct stktable *t;
1285 struct stktable_key *key;
1286 struct stksess *ts;
1287 void *ptr;
1288
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001289 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001290
1291 key = smp_to_stkey(smp, t);
1292 if (!key)
1293 return 0;
1294
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001295 ts = stktable_lookup_key(t, key);
1296
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001297 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001298 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001299 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001300
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301 if (!ts) /* key not present */
1302 return 1;
1303
1304 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001305 if (ptr)
1306 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1307 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001308
Daniel Corbett3e60b112018-05-27 09:47:12 -04001309 stktable_release(t, ts);
1310 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311}
1312
1313/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001314 * it up into this table. Returns the value of the GPT0 tag for the key
1315 * if the key is present in the table, otherwise false, so that comparisons can
1316 * be easily performed. If the inspected parameter is not stored in the table,
1317 * <not found> is returned.
1318 */
1319static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1320{
1321 struct stktable *t;
1322 struct stktable_key *key;
1323 struct stksess *ts;
1324 void *ptr;
1325
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001326 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001327
1328 key = smp_to_stkey(smp, t);
1329 if (!key)
1330 return 0;
1331
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001332 ts = stktable_lookup_key(t, key);
1333
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001334 smp->flags = SMP_F_VOL_TEST;
1335 smp->data.type = SMP_T_SINT;
1336 smp->data.u.sint = 0;
1337
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001338 if (!ts) /* key not present */
1339 return 1;
1340
1341 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001342 if (ptr)
1343 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001344
Daniel Corbett3e60b112018-05-27 09:47:12 -04001345 stktable_release(t, ts);
1346 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001347}
1348
1349/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350 * it up into this table. Returns the value of the GPC0 counter for the key
1351 * if the key is present in the table, otherwise zero, so that comparisons can
1352 * be easily performed. If the inspected parameter is not stored in the table,
1353 * <not found> is returned.
1354 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001355static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356{
1357 struct stktable *t;
1358 struct stktable_key *key;
1359 struct stksess *ts;
1360 void *ptr;
1361
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001362 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363
1364 key = smp_to_stkey(smp, t);
1365 if (!key)
1366 return 0;
1367
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001368 ts = stktable_lookup_key(t, key);
1369
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001371 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001372 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001373
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001374 if (!ts) /* key not present */
1375 return 1;
1376
1377 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001378 if (ptr)
1379 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380
Daniel Corbett3e60b112018-05-27 09:47:12 -04001381 stktable_release(t, ts);
1382 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001383}
1384
1385/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1386 * it up into this table. Returns the event rate of the GPC0 counter for the key
1387 * if the key is present in the table, otherwise zero, so that comparisons can
1388 * be easily performed. If the inspected parameter is not stored in the table,
1389 * <not found> is returned.
1390 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001391static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001392{
1393 struct stktable *t;
1394 struct stktable_key *key;
1395 struct stksess *ts;
1396 void *ptr;
1397
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001398 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001399
1400 key = smp_to_stkey(smp, t);
1401 if (!key)
1402 return 0;
1403
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001404 ts = stktable_lookup_key(t, key);
1405
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001406 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001407 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001408 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001410 if (!ts) /* key not present */
1411 return 1;
1412
1413 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001414 if (ptr)
1415 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1416 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417
Daniel Corbett3e60b112018-05-27 09:47:12 -04001418 stktable_release(t, ts);
1419 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420}
1421
1422/* 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 +01001423 * it up into this table. Returns the value of the GPC1 counter for the key
1424 * if the key is present in the table, otherwise zero, so that comparisons can
1425 * be easily performed. If the inspected parameter is not stored in the table,
1426 * <not found> is returned.
1427 */
1428static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1429{
1430 struct stktable *t;
1431 struct stktable_key *key;
1432 struct stksess *ts;
1433 void *ptr;
1434
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001435 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001436
1437 key = smp_to_stkey(smp, t);
1438 if (!key)
1439 return 0;
1440
1441 ts = stktable_lookup_key(t, key);
1442
1443 smp->flags = SMP_F_VOL_TEST;
1444 smp->data.type = SMP_T_SINT;
1445 smp->data.u.sint = 0;
1446
1447 if (!ts) /* key not present */
1448 return 1;
1449
1450 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001451 if (ptr)
1452 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001453
Daniel Corbett3e60b112018-05-27 09:47:12 -04001454 stktable_release(t, ts);
1455 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001456}
1457
1458/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1459 * it up into this table. Returns the event rate of the GPC1 counter for the key
1460 * if the key is present in the table, otherwise zero, so that comparisons can
1461 * be easily performed. If the inspected parameter is not stored in the table,
1462 * <not found> is returned.
1463 */
1464static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1465{
1466 struct stktable *t;
1467 struct stktable_key *key;
1468 struct stksess *ts;
1469 void *ptr;
1470
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001471 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001472
1473 key = smp_to_stkey(smp, t);
1474 if (!key)
1475 return 0;
1476
1477 ts = stktable_lookup_key(t, key);
1478
1479 smp->flags = SMP_F_VOL_TEST;
1480 smp->data.type = SMP_T_SINT;
1481 smp->data.u.sint = 0;
1482
1483 if (!ts) /* key not present */
1484 return 1;
1485
1486 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001487 if (ptr)
1488 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1489 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001490
Daniel Corbett3e60b112018-05-27 09:47:12 -04001491 stktable_release(t, ts);
1492 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001493}
1494
1495/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496 * it up into this table. Returns the cumulated number of HTTP request errors
1497 * for the key if the key is present in the table, otherwise zero, so that
1498 * comparisons can be easily performed. If the inspected parameter is not stored
1499 * in the table, <not found> is returned.
1500 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001501static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001502{
1503 struct stktable *t;
1504 struct stktable_key *key;
1505 struct stksess *ts;
1506 void *ptr;
1507
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001508 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001509
1510 key = smp_to_stkey(smp, t);
1511 if (!key)
1512 return 0;
1513
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001514 ts = stktable_lookup_key(t, key);
1515
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001516 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001517 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001518 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001519
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001520 if (!ts) /* key not present */
1521 return 1;
1522
1523 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001524 if (ptr)
1525 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001526
Daniel Corbett3e60b112018-05-27 09:47:12 -04001527 stktable_release(t, ts);
1528 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001529}
1530
1531/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1532 * it up into this table. Returns the HTTP request error rate the key
1533 * if the key is present in the table, otherwise zero, so that comparisons can
1534 * be easily performed. If the inspected parameter is not stored in the table,
1535 * <not found> is returned.
1536 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001537static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001538{
1539 struct stktable *t;
1540 struct stktable_key *key;
1541 struct stksess *ts;
1542 void *ptr;
1543
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001544 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001545
1546 key = smp_to_stkey(smp, t);
1547 if (!key)
1548 return 0;
1549
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001550 ts = stktable_lookup_key(t, key);
1551
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001552 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001553 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001554 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001555
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001556 if (!ts) /* key not present */
1557 return 1;
1558
1559 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001560 if (ptr)
1561 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1562 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001563
Daniel Corbett3e60b112018-05-27 09:47:12 -04001564 stktable_release(t, ts);
1565 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001566}
1567
1568/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1569 * it up into this table. Returns the cumulated number of HTTP request for the
1570 * key if the key is present in the table, otherwise zero, so that comparisons
1571 * can be easily performed. If the inspected parameter is not stored in the
1572 * table, <not found> is returned.
1573 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001574static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001575{
1576 struct stktable *t;
1577 struct stktable_key *key;
1578 struct stksess *ts;
1579 void *ptr;
1580
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001581 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001582
1583 key = smp_to_stkey(smp, t);
1584 if (!key)
1585 return 0;
1586
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001587 ts = stktable_lookup_key(t, key);
1588
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001590 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001591 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001592
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593 if (!ts) /* key not present */
1594 return 1;
1595
1596 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001597 if (ptr)
1598 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599
Daniel Corbett3e60b112018-05-27 09:47:12 -04001600 stktable_release(t, ts);
1601 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001602}
1603
1604/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1605 * it up into this table. Returns the HTTP request rate the key if the key is
1606 * present in the table, otherwise zero, so that comparisons can be easily
1607 * performed. If the inspected parameter is not stored in the table, <not found>
1608 * is returned.
1609 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001610static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001611{
1612 struct stktable *t;
1613 struct stktable_key *key;
1614 struct stksess *ts;
1615 void *ptr;
1616
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001617 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001618
1619 key = smp_to_stkey(smp, t);
1620 if (!key)
1621 return 0;
1622
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001623 ts = stktable_lookup_key(t, key);
1624
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001625 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001626 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001627 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001628
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001629 if (!ts) /* key not present */
1630 return 1;
1631
1632 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001633 if (ptr)
1634 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1635 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001636
Daniel Corbett3e60b112018-05-27 09:47:12 -04001637 stktable_release(t, ts);
1638 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001639}
1640
1641/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1642 * it up into this table. Returns the volume of datareceived from clients in kbytes
1643 * if the key is present in the table, otherwise zero, so that comparisons can
1644 * be easily performed. If the inspected parameter is not stored in the table,
1645 * <not found> is returned.
1646 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001647static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001648{
1649 struct stktable *t;
1650 struct stktable_key *key;
1651 struct stksess *ts;
1652 void *ptr;
1653
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001654 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001655
1656 key = smp_to_stkey(smp, t);
1657 if (!key)
1658 return 0;
1659
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001660 ts = stktable_lookup_key(t, key);
1661
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001662 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001663 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001664 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001665
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001666 if (!ts) /* key not present */
1667 return 1;
1668
1669 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001670 if (ptr)
1671 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001672
Daniel Corbett3e60b112018-05-27 09:47:12 -04001673 stktable_release(t, ts);
1674 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001675}
1676
1677/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1678 * it up into this table. Returns the volume of data sent to clients in kbytes
1679 * if the key is present in the table, otherwise zero, so that comparisons can
1680 * be easily performed. If the inspected parameter is not stored in the table,
1681 * <not found> is returned.
1682 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001683static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001684{
1685 struct stktable *t;
1686 struct stktable_key *key;
1687 struct stksess *ts;
1688 void *ptr;
1689
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001690 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001691
1692 key = smp_to_stkey(smp, t);
1693 if (!key)
1694 return 0;
1695
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001696 ts = stktable_lookup_key(t, key);
1697
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001698 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001699 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001700 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001701
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001702 if (!ts) /* key not present */
1703 return 1;
1704
1705 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001706 if (ptr)
1707 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001708
Daniel Corbett3e60b112018-05-27 09:47:12 -04001709 stktable_release(t, ts);
1710 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001711}
1712
1713/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1714 * it up into this table. Returns the server ID associated with the key if the
1715 * key is present in the table, otherwise zero, so that comparisons can be
1716 * easily performed. If the inspected parameter is not stored in the table,
1717 * <not found> is returned.
1718 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001719static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001720{
1721 struct stktable *t;
1722 struct stktable_key *key;
1723 struct stksess *ts;
1724 void *ptr;
1725
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001726 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727
1728 key = smp_to_stkey(smp, t);
1729 if (!key)
1730 return 0;
1731
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001732 ts = stktable_lookup_key(t, key);
1733
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001734 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001735 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001736 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001737
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001738 if (!ts) /* key not present */
1739 return 1;
1740
1741 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001742 if (ptr)
1743 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001744
Daniel Corbett3e60b112018-05-27 09:47:12 -04001745 stktable_release(t, ts);
1746 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001747}
1748
1749/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1750 * it up into this table. Returns the cumulated number of sessions for the
1751 * key if the key is present in the table, otherwise zero, so that comparisons
1752 * can be easily performed. If the inspected parameter is not stored in the
1753 * table, <not found> is returned.
1754 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001755static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001756{
1757 struct stktable *t;
1758 struct stktable_key *key;
1759 struct stksess *ts;
1760 void *ptr;
1761
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001762 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001763
1764 key = smp_to_stkey(smp, t);
1765 if (!key)
1766 return 0;
1767
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001768 ts = stktable_lookup_key(t, key);
1769
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001770 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001771 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001772 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001774 if (!ts) /* key not present */
1775 return 1;
1776
1777 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001778 if (ptr)
1779 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001780
Daniel Corbett3e60b112018-05-27 09:47:12 -04001781 stktable_release(t, ts);
1782 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001783}
1784
1785/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1786 * it up into this table. Returns the session rate the key if the key is
1787 * present in the table, otherwise zero, so that comparisons can be easily
1788 * performed. If the inspected parameter is not stored in the table, <not found>
1789 * is returned.
1790 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001791static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001792{
1793 struct stktable *t;
1794 struct stktable_key *key;
1795 struct stksess *ts;
1796 void *ptr;
1797
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001798 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799
1800 key = smp_to_stkey(smp, t);
1801 if (!key)
1802 return 0;
1803
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001804 ts = stktable_lookup_key(t, key);
1805
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001806 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001807 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001808 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001810 if (!ts) /* key not present */
1811 return 1;
1812
1813 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001814 if (ptr)
1815 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1816 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001817
Daniel Corbett3e60b112018-05-27 09:47:12 -04001818 stktable_release(t, ts);
1819 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001820}
1821
1822/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1823 * it up into this table. Returns the amount of concurrent connections tracking
1824 * the same key if the key is present in the table, otherwise zero, so that
1825 * comparisons can be easily performed. If the inspected parameter is not
1826 * stored in the table, <not found> is returned.
1827 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001828static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001829{
1830 struct stktable *t;
1831 struct stktable_key *key;
1832 struct stksess *ts;
1833
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001834 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001835
1836 key = smp_to_stkey(smp, t);
1837 if (!key)
1838 return 0;
1839
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001840 ts = stktable_lookup_key(t, key);
1841
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001842 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001843 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001844 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001845
Tim Duesterhus65189c12018-06-26 15:57:29 +02001846 if (!ts)
1847 return 1;
1848
1849 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001850
Daniel Corbett3e60b112018-05-27 09:47:12 -04001851 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001852 return 1;
1853}
1854
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001855/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001856static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001857 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001858{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001859 struct stksess *ts;
1860 struct stkctr *stkctr;
1861
1862 /* Extract the stksess, return OK if no stksess available. */
1863 if (s)
1864 stkctr = &s->stkctr[rule->arg.gpc.sc];
1865 else
1866 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001867
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001868 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001869 if (ts) {
1870 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001871
Willy Tarreau79c1e912016-01-25 14:54:45 +01001872 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1873 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001874 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1875 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001876 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001877
1878 if (ptr1)
1879 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001880 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001881
Emeric Brun819fc6f2017-06-13 19:37:32 +02001882 if (ptr2)
1883 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001884
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001885 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001886
1887 /* If data was modified, we need to touch to re-schedule sync */
1888 stktable_touch_local(stkctr->table, ts, 0);
1889 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001890 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001891 return ACT_RET_CONT;
1892}
1893
1894/* This function is a common parser for using variables. It understands
1895 * the formats:
1896 *
1897 * sc-inc-gpc0(<stick-table ID>)
1898 *
1899 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1900 * it returns 1 and the variable <expr> is filled with the pointer to the
1901 * expression to execute.
1902 */
1903static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1904 struct act_rule *rule, char **err)
1905{
1906 const char *cmd_name = args[*arg-1];
1907 char *error;
1908
1909 cmd_name += strlen("sc-inc-gpc0");
1910 if (*cmd_name == '\0') {
1911 /* default stick table id. */
1912 rule->arg.gpc.sc = 0;
1913 } else {
1914 /* parse the stick table id. */
1915 if (*cmd_name != '(') {
1916 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1917 return ACT_RET_PRS_ERR;
1918 }
1919 cmd_name++; /* jump the '(' */
1920 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1921 if (*error != ')') {
1922 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1923 return ACT_RET_PRS_ERR;
1924 }
1925
Christopher Faulet28436e22019-12-18 10:25:46 +01001926 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001927 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001928 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001929 return ACT_RET_PRS_ERR;
1930 }
1931 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001932 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001933 rule->action_ptr = action_inc_gpc0;
1934 return ACT_RET_PRS_OK;
1935}
1936
1937/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001938static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1939 struct session *sess, struct stream *s, int flags)
1940{
1941 struct stksess *ts;
1942 struct stkctr *stkctr;
1943
1944 /* Extract the stksess, return OK if no stksess available. */
1945 if (s)
1946 stkctr = &s->stkctr[rule->arg.gpc.sc];
1947 else
1948 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1949
1950 ts = stkctr_entry(stkctr);
1951 if (ts) {
1952 void *ptr1, *ptr2;
1953
1954 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1955 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1956 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1957 if (ptr1 || ptr2) {
1958 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1959
1960 if (ptr1)
1961 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1962 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1963
1964 if (ptr2)
1965 stktable_data_cast(ptr2, gpc1)++;
1966
1967 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1968
1969 /* If data was modified, we need to touch to re-schedule sync */
1970 stktable_touch_local(stkctr->table, ts, 0);
1971 }
1972 }
1973 return ACT_RET_CONT;
1974}
1975
1976/* This function is a common parser for using variables. It understands
1977 * the formats:
1978 *
1979 * sc-inc-gpc1(<stick-table ID>)
1980 *
1981 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1982 * it returns 1 and the variable <expr> is filled with the pointer to the
1983 * expression to execute.
1984 */
1985static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1986 struct act_rule *rule, char **err)
1987{
1988 const char *cmd_name = args[*arg-1];
1989 char *error;
1990
1991 cmd_name += strlen("sc-inc-gpc1");
1992 if (*cmd_name == '\0') {
1993 /* default stick table id. */
1994 rule->arg.gpc.sc = 0;
1995 } else {
1996 /* parse the stick table id. */
1997 if (*cmd_name != '(') {
1998 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1999 return ACT_RET_PRS_ERR;
2000 }
2001 cmd_name++; /* jump the '(' */
2002 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2003 if (*error != ')') {
2004 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2005 return ACT_RET_PRS_ERR;
2006 }
2007
Christopher Faulet28436e22019-12-18 10:25:46 +01002008 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002009 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002010 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002011 return ACT_RET_PRS_ERR;
2012 }
2013 }
2014 rule->action = ACT_CUSTOM;
2015 rule->action_ptr = action_inc_gpc1;
2016 return ACT_RET_PRS_OK;
2017}
2018
2019/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002020static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002021 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002022{
2023 void *ptr;
2024 struct stksess *ts;
2025 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002026 unsigned int value = 0;
2027 struct sample *smp;
2028 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002029
2030 /* Extract the stksess, return OK if no stksess available. */
2031 if (s)
2032 stkctr = &s->stkctr[rule->arg.gpt.sc];
2033 else
2034 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002035
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002036 ts = stkctr_entry(stkctr);
2037 if (!ts)
2038 return ACT_RET_CONT;
2039
2040 /* Store the sample in the required sc, and ignore errors. */
2041 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002042 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002043 if (!rule->arg.gpt.expr)
2044 value = (unsigned int)(rule->arg.gpt.value);
2045 else {
2046 switch (rule->from) {
2047 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2048 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2049 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2050 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2051 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2052 default:
2053 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2054 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2055 ha_alert("stick table: internal error while executing setting gpt0.\n");
2056 return ACT_RET_CONT;
2057 }
2058
2059 /* Fetch and cast the expression. */
2060 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2061 if (!smp) {
2062 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2063 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2064 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2065 return ACT_RET_CONT;
2066 }
2067 value = (unsigned int)(smp->data.u.sint);
2068 }
2069
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002070 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002071
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002072 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002073
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002074 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002075
2076 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002077 }
2078
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002079 return ACT_RET_CONT;
2080}
2081
2082/* This function is a common parser for using variables. It understands
2083 * the format:
2084 *
2085 * set-gpt0(<stick-table ID>) <expression>
2086 *
2087 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2088 * it returns 1 and the variable <expr> is filled with the pointer to the
2089 * expression to execute.
2090 */
2091static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2092 struct act_rule *rule, char **err)
2093
2094
2095{
2096 const char *cmd_name = args[*arg-1];
2097 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002098 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002099
2100 cmd_name += strlen("sc-set-gpt0");
2101 if (*cmd_name == '\0') {
2102 /* default stick table id. */
2103 rule->arg.gpt.sc = 0;
2104 } else {
2105 /* parse the stick table id. */
2106 if (*cmd_name != '(') {
2107 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2108 return ACT_RET_PRS_ERR;
2109 }
2110 cmd_name++; /* jump the '(' */
2111 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2112 if (*error != ')') {
2113 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2114 return ACT_RET_PRS_ERR;
2115 }
2116
Christopher Faulet28436e22019-12-18 10:25:46 +01002117 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002118 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002119 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002120 return ACT_RET_PRS_ERR;
2121 }
2122 }
2123
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002124 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002125 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2126 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002127 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002128 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002129 if (!rule->arg.gpt.expr)
2130 return ACT_RET_PRS_ERR;
2131
2132 switch (rule->from) {
2133 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2134 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2135 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2136 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2137 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2138 default:
2139 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2140 return ACT_RET_PRS_ERR;
2141 }
2142 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2143 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2144 sample_src_names(rule->arg.gpt.expr->fetch->use));
2145 free(rule->arg.gpt.expr);
2146 return ACT_RET_PRS_ERR;
2147 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002148 }
2149 (*arg)++;
2150
Thierry FOURNIER42148732015-09-02 17:17:33 +02002151 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002152 rule->action_ptr = action_set_gpt0;
2153
2154 return ACT_RET_PRS_OK;
2155}
2156
Willy Tarreau7d562212016-11-25 16:10:05 +01002157/* set temp integer to the number of used entries in the table pointed to by expr.
2158 * Accepts exactly 1 argument of type table.
2159 */
2160static int
2161smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2162{
2163 smp->flags = SMP_F_VOL_TEST;
2164 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002165 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002166 return 1;
2167}
2168
2169/* set temp integer to the number of free entries in the table pointed to by expr.
2170 * Accepts exactly 1 argument of type table.
2171 */
2172static int
2173smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2174{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002175 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002176
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002177 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002178 smp->flags = SMP_F_VOL_TEST;
2179 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002180 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002181 return 1;
2182}
2183
2184/* Returns a pointer to a stkctr depending on the fetch keyword name.
2185 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2186 * sc[0-9]_* will return a pointer to the respective field in the
2187 * stream <l4>. sc_* requires an UINT argument specifying the stick
2188 * counter number. src_* will fill a locally allocated structure with
2189 * the table and entry corresponding to what is specified with src_*.
2190 * NULL may be returned if the designated stkctr is not tracked. For
2191 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2192 * passed. When present, the currently tracked key is then looked up
2193 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002194 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002195 * multiple tables). <strm> is allowed to be NULL, in which case only
2196 * the session will be consulted.
2197 */
2198struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002199smp_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 +01002200{
Willy Tarreau7d562212016-11-25 16:10:05 +01002201 struct stkctr *stkptr;
2202 struct stksess *stksess;
2203 unsigned int num = kw[2] - '0';
2204 int arg = 0;
2205
2206 if (num == '_' - '0') {
2207 /* sc_* variant, args[0] = ctr# (mandatory) */
2208 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002209 }
2210 else if (num > 9) { /* src_* variant, args[0] = table */
2211 struct stktable_key *key;
2212 struct connection *conn = objt_conn(sess->origin);
2213 struct sample smp;
2214
2215 if (!conn)
2216 return NULL;
2217
Joseph Herlant5662fa42018-11-15 13:43:28 -08002218 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002219 smp.px = NULL;
2220 smp.sess = sess;
2221 smp.strm = strm;
Christopher Faulet19455292021-01-29 10:27:47 +01002222 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002223 return NULL;
2224
2225 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002226 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002227 if (!key)
2228 return NULL;
2229
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002230 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002231 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2232 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002233 }
2234
2235 /* Here, <num> contains the counter number from 0 to 9 for
2236 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2237 * args[arg] is the first optional argument. We first lookup the
2238 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002239 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002240 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002241 if (num >= MAX_SESS_STKCTR)
2242 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002243
2244 if (strm)
2245 stkptr = &strm->stkctr[num];
2246 if (!strm || !stkctr_entry(stkptr)) {
2247 stkptr = &sess->stkctr[num];
2248 if (!stkctr_entry(stkptr))
2249 return NULL;
2250 }
2251
2252 stksess = stkctr_entry(stkptr);
2253 if (!stksess)
2254 return NULL;
2255
2256 if (unlikely(args[arg].type == ARGT_TAB)) {
2257 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002258 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002259 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2260 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002261 }
2262 return stkptr;
2263}
2264
2265/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2266 * the entry if it doesn't exist yet. This is needed for a few fetch
2267 * functions which need to create an entry, such as src_inc_gpc* and
2268 * src_clr_gpc*.
2269 */
2270struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002271smp_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 +01002272{
Willy Tarreau7d562212016-11-25 16:10:05 +01002273 struct stktable_key *key;
2274 struct connection *conn = objt_conn(sess->origin);
2275 struct sample smp;
2276
2277 if (strncmp(kw, "src_", 4) != 0)
2278 return NULL;
2279
2280 if (!conn)
2281 return NULL;
2282
Joseph Herlant5662fa42018-11-15 13:43:28 -08002283 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002284 smp.px = NULL;
2285 smp.sess = sess;
2286 smp.strm = strm;
Christopher Faulet19455292021-01-29 10:27:47 +01002287 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002288 return NULL;
2289
2290 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002291 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002292 if (!key)
2293 return NULL;
2294
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002295 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002296 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2297 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002298}
2299
2300/* set return a boolean indicating if the requested stream counter is
2301 * currently being tracked or not.
2302 * Supports being called as "sc[0-9]_tracked" only.
2303 */
2304static int
2305smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2306{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002307 struct stkctr tmpstkctr;
2308 struct stkctr *stkctr;
2309
Willy Tarreau7d562212016-11-25 16:10:05 +01002310 smp->flags = SMP_F_VOL_TEST;
2311 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002312 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2313 smp->data.u.sint = !!stkctr;
2314
2315 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002316 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002317 stktable_release(stkctr->table, stkctr_entry(stkctr));
2318
Willy Tarreau7d562212016-11-25 16:10:05 +01002319 return 1;
2320}
2321
2322/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2323 * frontend counters or from the src.
2324 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2325 * zero is returned if the key is new.
2326 */
2327static int
2328smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2329{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002330 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002331 struct stkctr *stkctr;
2332
Emeric Brun819fc6f2017-06-13 19:37:32 +02002333 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002334 if (!stkctr)
2335 return 0;
2336
2337 smp->flags = SMP_F_VOL_TEST;
2338 smp->data.type = SMP_T_SINT;
2339 smp->data.u.sint = 0;
2340
Emeric Brun819fc6f2017-06-13 19:37:32 +02002341 if (stkctr_entry(stkctr)) {
2342 void *ptr;
2343
2344 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2345 if (!ptr) {
2346 if (stkctr == &tmpstkctr)
2347 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002348 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002349 }
2350
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002351 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002352
Willy Tarreau7d562212016-11-25 16:10:05 +01002353 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002354
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002355 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002356
2357 if (stkctr == &tmpstkctr)
2358 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002359 }
2360 return 1;
2361}
2362
2363/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2364 * frontend counters or from the src.
2365 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2366 * zero is returned if the key is new.
2367 */
2368static int
2369smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2370{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002371 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002372 struct stkctr *stkctr;
2373
Emeric Brun819fc6f2017-06-13 19:37:32 +02002374 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002375 if (!stkctr)
2376 return 0;
2377
2378 smp->flags = SMP_F_VOL_TEST;
2379 smp->data.type = SMP_T_SINT;
2380 smp->data.u.sint = 0;
2381
2382 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002383 void *ptr;
2384
2385 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2386 if (!ptr) {
2387 if (stkctr == &tmpstkctr)
2388 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002389 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002390 }
2391
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002392 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002393
Willy Tarreau7d562212016-11-25 16:10:05 +01002394 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002395
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002396 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002397
2398 if (stkctr == &tmpstkctr)
2399 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002400 }
2401 return 1;
2402}
2403
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002404/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2405 * frontend counters or from the src.
2406 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2407 * zero is returned if the key is new.
2408 */
2409static int
2410smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2411{
2412 struct stkctr tmpstkctr;
2413 struct stkctr *stkctr;
2414
2415 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2416 if (!stkctr)
2417 return 0;
2418
2419 smp->flags = SMP_F_VOL_TEST;
2420 smp->data.type = SMP_T_SINT;
2421 smp->data.u.sint = 0;
2422
2423 if (stkctr_entry(stkctr) != NULL) {
2424 void *ptr;
2425
2426 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2427 if (!ptr) {
2428 if (stkctr == &tmpstkctr)
2429 stktable_release(stkctr->table, stkctr_entry(stkctr));
2430 return 0; /* parameter not stored */
2431 }
2432
2433 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2434
2435 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2436
2437 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2438
2439 if (stkctr == &tmpstkctr)
2440 stktable_release(stkctr->table, stkctr_entry(stkctr));
2441 }
2442 return 1;
2443}
2444
Willy Tarreau7d562212016-11-25 16:10:05 +01002445/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2446 * tracked frontend counters or from the src.
2447 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2448 * Value zero is returned if the key is new.
2449 */
2450static int
2451smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2452{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002453 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002454 struct stkctr *stkctr;
2455
Emeric Brun819fc6f2017-06-13 19:37:32 +02002456 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002457 if (!stkctr)
2458 return 0;
2459
2460 smp->flags = SMP_F_VOL_TEST;
2461 smp->data.type = SMP_T_SINT;
2462 smp->data.u.sint = 0;
2463 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002464 void *ptr;
2465
2466 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2467 if (!ptr) {
2468 if (stkctr == &tmpstkctr)
2469 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002470 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002471 }
2472
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002473 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002474
Willy Tarreau7d562212016-11-25 16:10:05 +01002475 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2476 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002477
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002478 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002479
2480 if (stkctr == &tmpstkctr)
2481 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002482 }
2483 return 1;
2484}
2485
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002486/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2487 * tracked frontend counters or from the src.
2488 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2489 * Value zero is returned if the key is new.
2490 */
2491static int
2492smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2493{
2494 struct stkctr tmpstkctr;
2495 struct stkctr *stkctr;
2496
2497 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2498 if (!stkctr)
2499 return 0;
2500
2501 smp->flags = SMP_F_VOL_TEST;
2502 smp->data.type = SMP_T_SINT;
2503 smp->data.u.sint = 0;
2504 if (stkctr_entry(stkctr) != NULL) {
2505 void *ptr;
2506
2507 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2508 if (!ptr) {
2509 if (stkctr == &tmpstkctr)
2510 stktable_release(stkctr->table, stkctr_entry(stkctr));
2511 return 0; /* parameter not stored */
2512 }
2513
2514 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2515
2516 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2517 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2518
2519 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2520
2521 if (stkctr == &tmpstkctr)
2522 stktable_release(stkctr->table, stkctr_entry(stkctr));
2523 }
2524 return 1;
2525}
2526
Willy Tarreau7d562212016-11-25 16:10:05 +01002527/* Increment the General Purpose Counter 0 value from the stream's tracked
2528 * frontend counters and return it into temp integer.
2529 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2530 */
2531static int
2532smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2533{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002534 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002535 struct stkctr *stkctr;
2536
Emeric Brun819fc6f2017-06-13 19:37:32 +02002537 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002538 if (!stkctr)
2539 return 0;
2540
2541 smp->flags = SMP_F_VOL_TEST;
2542 smp->data.type = SMP_T_SINT;
2543 smp->data.u.sint = 0;
2544
Emeric Brun819fc6f2017-06-13 19:37:32 +02002545 if (!stkctr_entry(stkctr))
2546 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002547
2548 if (stkctr && stkctr_entry(stkctr)) {
2549 void *ptr1,*ptr2;
2550
Emeric Brun819fc6f2017-06-13 19:37:32 +02002551
Willy Tarreau7d562212016-11-25 16:10:05 +01002552 /* First, update gpc0_rate if it's tracked. Second, update its
2553 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2554 */
2555 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002556 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002557 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002558 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002559
Emeric Brun819fc6f2017-06-13 19:37:32 +02002560 if (ptr1) {
2561 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2562 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2563 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2564 }
2565
2566 if (ptr2)
2567 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2568
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002569 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002570
2571 /* If data was modified, we need to touch to re-schedule sync */
2572 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2573 }
2574 else if (stkctr == &tmpstkctr)
2575 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002576 }
2577 return 1;
2578}
2579
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002580/* Increment the General Purpose Counter 1 value from the stream's tracked
2581 * frontend counters and return it into temp integer.
2582 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2583 */
2584static int
2585smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2586{
2587 struct stkctr tmpstkctr;
2588 struct stkctr *stkctr;
2589
2590 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2591 if (!stkctr)
2592 return 0;
2593
2594 smp->flags = SMP_F_VOL_TEST;
2595 smp->data.type = SMP_T_SINT;
2596 smp->data.u.sint = 0;
2597
2598 if (!stkctr_entry(stkctr))
2599 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2600
2601 if (stkctr && stkctr_entry(stkctr)) {
2602 void *ptr1,*ptr2;
2603
2604
2605 /* First, update gpc1_rate if it's tracked. Second, update its
2606 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2607 */
2608 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2609 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2610 if (ptr1 || ptr2) {
2611 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2612
2613 if (ptr1) {
2614 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2615 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2616 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2617 }
2618
2619 if (ptr2)
2620 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2621
2622 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2623
2624 /* If data was modified, we need to touch to re-schedule sync */
2625 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2626 }
2627 else if (stkctr == &tmpstkctr)
2628 stktable_release(stkctr->table, stkctr_entry(stkctr));
2629 }
2630 return 1;
2631}
2632
Willy Tarreau7d562212016-11-25 16:10:05 +01002633/* Clear the General Purpose Counter 0 value from the stream's tracked
2634 * frontend counters and return its previous value into temp integer.
2635 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2636 */
2637static int
2638smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2639{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002640 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002641 struct stkctr *stkctr;
2642
Emeric Brun819fc6f2017-06-13 19:37:32 +02002643 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002644 if (!stkctr)
2645 return 0;
2646
2647 smp->flags = SMP_F_VOL_TEST;
2648 smp->data.type = SMP_T_SINT;
2649 smp->data.u.sint = 0;
2650
Emeric Brun819fc6f2017-06-13 19:37:32 +02002651 if (!stkctr_entry(stkctr))
2652 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002653
Emeric Brun819fc6f2017-06-13 19:37:32 +02002654 if (stkctr && stkctr_entry(stkctr)) {
2655 void *ptr;
2656
2657 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2658 if (!ptr) {
2659 if (stkctr == &tmpstkctr)
2660 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002661 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662 }
2663
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002664 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002665
Willy Tarreau7d562212016-11-25 16:10:05 +01002666 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2667 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002668
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002669 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002670
Willy Tarreau7d562212016-11-25 16:10:05 +01002671 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002672 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002673 }
2674 return 1;
2675}
2676
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002677/* Clear the General Purpose Counter 1 value from the stream's tracked
2678 * frontend counters and return its previous value into temp integer.
2679 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2680 */
2681static int
2682smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2683{
2684 struct stkctr tmpstkctr;
2685 struct stkctr *stkctr;
2686
2687 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2688 if (!stkctr)
2689 return 0;
2690
2691 smp->flags = SMP_F_VOL_TEST;
2692 smp->data.type = SMP_T_SINT;
2693 smp->data.u.sint = 0;
2694
2695 if (!stkctr_entry(stkctr))
2696 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2697
2698 if (stkctr && stkctr_entry(stkctr)) {
2699 void *ptr;
2700
2701 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2702 if (!ptr) {
2703 if (stkctr == &tmpstkctr)
2704 stktable_release(stkctr->table, stkctr_entry(stkctr));
2705 return 0; /* parameter not stored */
2706 }
2707
2708 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2709
2710 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2711 stktable_data_cast(ptr, gpc1) = 0;
2712
2713 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2714
2715 /* If data was modified, we need to touch to re-schedule sync */
2716 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2717 }
2718 return 1;
2719}
2720
Willy Tarreau7d562212016-11-25 16:10:05 +01002721/* set <smp> to the cumulated number of connections from the stream's tracked
2722 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2723 * "src_conn_cnt" only.
2724 */
2725static int
2726smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2727{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002728 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002729 struct stkctr *stkctr;
2730
Emeric Brun819fc6f2017-06-13 19:37:32 +02002731 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002732 if (!stkctr)
2733 return 0;
2734
2735 smp->flags = SMP_F_VOL_TEST;
2736 smp->data.type = SMP_T_SINT;
2737 smp->data.u.sint = 0;
2738 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002739 void *ptr;
2740
2741 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2742 if (!ptr) {
2743 if (stkctr == &tmpstkctr)
2744 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002745 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746 }
2747
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002748 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002749
Willy Tarreau7d562212016-11-25 16:10:05 +01002750 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002751
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002752 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002753
2754 if (stkctr == &tmpstkctr)
2755 stktable_release(stkctr->table, stkctr_entry(stkctr));
2756
2757
Willy Tarreau7d562212016-11-25 16:10:05 +01002758 }
2759 return 1;
2760}
2761
2762/* set <smp> to the connection rate from the stream's tracked frontend
2763 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2764 * only.
2765 */
2766static int
2767smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2768{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002769 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002770 struct stkctr *stkctr;
2771
Emeric Brun819fc6f2017-06-13 19:37:32 +02002772 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002773 if (!stkctr)
2774 return 0;
2775
2776 smp->flags = SMP_F_VOL_TEST;
2777 smp->data.type = SMP_T_SINT;
2778 smp->data.u.sint = 0;
2779 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780 void *ptr;
2781
2782 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2783 if (!ptr) {
2784 if (stkctr == &tmpstkctr)
2785 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002786 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002787 }
2788
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002789 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002790
Willy Tarreau7d562212016-11-25 16:10:05 +01002791 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2792 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002793
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002794 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002795
2796 if (stkctr == &tmpstkctr)
2797 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002798 }
2799 return 1;
2800}
2801
2802/* set temp integer to the number of connections from the stream's source address
2803 * in the table pointed to by expr, after updating it.
2804 * Accepts exactly 1 argument of type table.
2805 */
2806static int
2807smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2808{
2809 struct connection *conn = objt_conn(smp->sess->origin);
2810 struct stksess *ts;
2811 struct stktable_key *key;
2812 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002813 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002814
2815 if (!conn)
2816 return 0;
2817
Joseph Herlant5662fa42018-11-15 13:43:28 -08002818 /* Fetch source address in a sample. */
Christopher Faulet19455292021-01-29 10:27:47 +01002819 if (!smp_fetch_src || !smp_fetch_src(empty_arg_list, smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002820 return 0;
2821
2822 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002823 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002824 if (!key)
2825 return 0;
2826
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002827 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002828
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002829 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002830 /* entry does not exist and could not be created */
2831 return 0;
2832
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002833 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002834 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002835 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002836 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002837
2838 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002839
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002840 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002841
Willy Tarreau7d562212016-11-25 16:10:05 +01002842 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002843
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002844 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002845
Willy Tarreau7d562212016-11-25 16:10:05 +01002846 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002847
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002848 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002849
2850 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002851 return 1;
2852}
2853
2854/* set <smp> to the number of concurrent connections from the stream's tracked
2855 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2856 * "src_conn_cur" only.
2857 */
2858static int
2859smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2860{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002861 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002862 struct stkctr *stkctr;
2863
Emeric Brun819fc6f2017-06-13 19:37:32 +02002864 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002865 if (!stkctr)
2866 return 0;
2867
2868 smp->flags = SMP_F_VOL_TEST;
2869 smp->data.type = SMP_T_SINT;
2870 smp->data.u.sint = 0;
2871 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002872 void *ptr;
2873
2874 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2875 if (!ptr) {
2876 if (stkctr == &tmpstkctr)
2877 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002878 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002879 }
2880
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002881 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002882
Willy Tarreau7d562212016-11-25 16:10:05 +01002883 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002884
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002885 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002886
2887 if (stkctr == &tmpstkctr)
2888 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002889 }
2890 return 1;
2891}
2892
2893/* set <smp> to the cumulated number of streams from the stream's tracked
2894 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2895 * "src_sess_cnt" only.
2896 */
2897static int
2898smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2899{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002900 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002901 struct stkctr *stkctr;
2902
Emeric Brun819fc6f2017-06-13 19:37:32 +02002903 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002904 if (!stkctr)
2905 return 0;
2906
2907 smp->flags = SMP_F_VOL_TEST;
2908 smp->data.type = SMP_T_SINT;
2909 smp->data.u.sint = 0;
2910 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002911 void *ptr;
2912
2913 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2914 if (!ptr) {
2915 if (stkctr == &tmpstkctr)
2916 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002918 }
2919
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002920 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002921
Willy Tarreau7d562212016-11-25 16:10:05 +01002922 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002923
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002924 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002925
2926 if (stkctr == &tmpstkctr)
2927 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002928 }
2929 return 1;
2930}
2931
2932/* set <smp> to the stream rate from the stream's tracked frontend counters.
2933 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2934 */
2935static int
2936smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2937{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002938 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002939 struct stkctr *stkctr;
2940
Emeric Brun819fc6f2017-06-13 19:37:32 +02002941 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002942 if (!stkctr)
2943 return 0;
2944
2945 smp->flags = SMP_F_VOL_TEST;
2946 smp->data.type = SMP_T_SINT;
2947 smp->data.u.sint = 0;
2948 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949 void *ptr;
2950
2951 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2952 if (!ptr) {
2953 if (stkctr == &tmpstkctr)
2954 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002955 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956 }
2957
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002958 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002959
Willy Tarreau7d562212016-11-25 16:10:05 +01002960 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2961 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002962
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002963 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002964
2965 if (stkctr == &tmpstkctr)
2966 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 }
2968 return 1;
2969}
2970
2971/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2972 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2973 * "src_http_req_cnt" only.
2974 */
2975static int
2976smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2977{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002979 struct stkctr *stkctr;
2980
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002982 if (!stkctr)
2983 return 0;
2984
2985 smp->flags = SMP_F_VOL_TEST;
2986 smp->data.type = SMP_T_SINT;
2987 smp->data.u.sint = 0;
2988 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002989 void *ptr;
2990
2991 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2992 if (!ptr) {
2993 if (stkctr == &tmpstkctr)
2994 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002995 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996 }
2997
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002998 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002999
Willy Tarreau7d562212016-11-25 16:10:05 +01003000 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003001
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003002 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003003
3004 if (stkctr == &tmpstkctr)
3005 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003006 }
3007 return 1;
3008}
3009
3010/* set <smp> to the HTTP request rate from the stream's tracked frontend
3011 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3012 * "src_http_req_rate" only.
3013 */
3014static int
3015smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3016{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003017 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003018 struct stkctr *stkctr;
3019
Emeric Brun819fc6f2017-06-13 19:37:32 +02003020 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003021 if (!stkctr)
3022 return 0;
3023
3024 smp->flags = SMP_F_VOL_TEST;
3025 smp->data.type = SMP_T_SINT;
3026 smp->data.u.sint = 0;
3027 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003028 void *ptr;
3029
3030 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3031 if (!ptr) {
3032 if (stkctr == &tmpstkctr)
3033 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003034 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003035 }
3036
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003037 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003038
Willy Tarreau7d562212016-11-25 16:10:05 +01003039 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3040 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003041
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003042 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003043
3044 if (stkctr == &tmpstkctr)
3045 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003046 }
3047 return 1;
3048}
3049
3050/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3051 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3052 * "src_http_err_cnt" only.
3053 */
3054static int
3055smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3056{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003057 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003058 struct stkctr *stkctr;
3059
Emeric Brun819fc6f2017-06-13 19:37:32 +02003060 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003061 if (!stkctr)
3062 return 0;
3063
3064 smp->flags = SMP_F_VOL_TEST;
3065 smp->data.type = SMP_T_SINT;
3066 smp->data.u.sint = 0;
3067 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068 void *ptr;
3069
3070 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3071 if (!ptr) {
3072 if (stkctr == &tmpstkctr)
3073 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003074 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003075 }
3076
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003077 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003078
Willy Tarreau7d562212016-11-25 16:10:05 +01003079 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003080
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003081 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003082
3083 if (stkctr == &tmpstkctr)
3084 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003085 }
3086 return 1;
3087}
3088
3089/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3090 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3091 * "src_http_err_rate" only.
3092 */
3093static int
3094smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3095{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003096 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003097 struct stkctr *stkctr;
3098
Emeric Brun819fc6f2017-06-13 19:37:32 +02003099 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003100 if (!stkctr)
3101 return 0;
3102
3103 smp->flags = SMP_F_VOL_TEST;
3104 smp->data.type = SMP_T_SINT;
3105 smp->data.u.sint = 0;
3106 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003107 void *ptr;
3108
3109 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3110 if (!ptr) {
3111 if (stkctr == &tmpstkctr)
3112 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003113 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114 }
3115
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003116 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003117
Willy Tarreau7d562212016-11-25 16:10:05 +01003118 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3119 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003120
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003121 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003122
3123 if (stkctr == &tmpstkctr)
3124 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003125 }
3126 return 1;
3127}
3128
3129/* set <smp> to the number of kbytes received from clients, as found in the
3130 * stream's tracked frontend counters. Supports being called as
3131 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3132 */
3133static int
3134smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3135{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003136 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003137 struct stkctr *stkctr;
3138
Emeric Brun819fc6f2017-06-13 19:37:32 +02003139 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003140 if (!stkctr)
3141 return 0;
3142
3143 smp->flags = SMP_F_VOL_TEST;
3144 smp->data.type = SMP_T_SINT;
3145 smp->data.u.sint = 0;
3146 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003147 void *ptr;
3148
3149 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3150 if (!ptr) {
3151 if (stkctr == &tmpstkctr)
3152 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003153 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154 }
3155
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003156 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003157
Willy Tarreau7d562212016-11-25 16:10:05 +01003158 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003159
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003160 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003161
3162 if (stkctr == &tmpstkctr)
3163 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003164 }
3165 return 1;
3166}
3167
3168/* set <smp> to the data rate received from clients in bytes/s, as found
3169 * in the stream's tracked frontend counters. Supports being called as
3170 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3171 */
3172static int
3173smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3174{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003176 struct stkctr *stkctr;
3177
Emeric Brun819fc6f2017-06-13 19:37:32 +02003178 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003179 if (!stkctr)
3180 return 0;
3181
3182 smp->flags = SMP_F_VOL_TEST;
3183 smp->data.type = SMP_T_SINT;
3184 smp->data.u.sint = 0;
3185 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003186 void *ptr;
3187
3188 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3189 if (!ptr) {
3190 if (stkctr == &tmpstkctr)
3191 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003192 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003193 }
3194
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003195 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003196
Willy Tarreau7d562212016-11-25 16:10:05 +01003197 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3198 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003199
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003200 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003201
3202 if (stkctr == &tmpstkctr)
3203 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003204 }
3205 return 1;
3206}
3207
3208/* set <smp> to the number of kbytes sent to clients, as found in the
3209 * stream's tracked frontend counters. Supports being called as
3210 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3211 */
3212static int
3213smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3214{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003215 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003216 struct stkctr *stkctr;
3217
Emeric Brun819fc6f2017-06-13 19:37:32 +02003218 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003219 if (!stkctr)
3220 return 0;
3221
3222 smp->flags = SMP_F_VOL_TEST;
3223 smp->data.type = SMP_T_SINT;
3224 smp->data.u.sint = 0;
3225 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003226 void *ptr;
3227
3228 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3229 if (!ptr) {
3230 if (stkctr == &tmpstkctr)
3231 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003232 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003233 }
3234
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003235 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236
Willy Tarreau7d562212016-11-25 16:10:05 +01003237 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003238
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003239 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003240
3241 if (stkctr == &tmpstkctr)
3242 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003243 }
3244 return 1;
3245}
3246
3247/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3248 * stream's tracked frontend counters. Supports being called as
3249 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3250 */
3251static int
3252smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3253{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003254 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003255 struct stkctr *stkctr;
3256
Emeric Brun819fc6f2017-06-13 19:37:32 +02003257 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003258 if (!stkctr)
3259 return 0;
3260
3261 smp->flags = SMP_F_VOL_TEST;
3262 smp->data.type = SMP_T_SINT;
3263 smp->data.u.sint = 0;
3264 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003265 void *ptr;
3266
3267 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3268 if (!ptr) {
3269 if (stkctr == &tmpstkctr)
3270 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003271 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003272 }
3273
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003274 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003275
Willy Tarreau7d562212016-11-25 16:10:05 +01003276 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3277 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003278
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003279 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003280
3281 if (stkctr == &tmpstkctr)
3282 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003283 }
3284 return 1;
3285}
3286
3287/* set <smp> to the number of active trackers on the SC entry in the stream's
3288 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3289 */
3290static int
3291smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3292{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003293 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003294 struct stkctr *stkctr;
3295
Emeric Brun819fc6f2017-06-13 19:37:32 +02003296 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003297 if (!stkctr)
3298 return 0;
3299
3300 smp->flags = SMP_F_VOL_TEST;
3301 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003302 if (stkctr == &tmpstkctr) {
3303 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3304 stktable_release(stkctr->table, stkctr_entry(stkctr));
3305 }
3306 else {
3307 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3308 }
3309
Willy Tarreau7d562212016-11-25 16:10:05 +01003310 return 1;
3311}
3312
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003313
3314/* The functions below are used to manipulate table contents from the CLI.
3315 * There are 3 main actions, "clear", "set" and "show". The code is shared
3316 * between all actions, and the action is encoded in the void *private in
3317 * the appctx as well as in the keyword registration, among one of the
3318 * following values.
3319 */
3320
3321enum {
3322 STK_CLI_ACT_CLR,
3323 STK_CLI_ACT_SET,
3324 STK_CLI_ACT_SHOW,
3325};
3326
3327/* Dump the status of a table to a stream interface's
3328 * read buffer. It returns 0 if the output buffer is full
3329 * and needs to be called again, otherwise non-zero.
3330 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003331static int table_dump_head_to_buffer(struct buffer *msg,
3332 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003333 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003334{
3335 struct stream *s = si_strm(si);
3336
3337 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003338 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003339
3340 /* any other information should be dumped here */
3341
William Lallemand07a62f72017-05-24 00:57:40 +02003342 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003343 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3344
Willy Tarreau06d80a92017-10-19 14:32:15 +02003345 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003346 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003347 return 0;
3348 }
3349
3350 return 1;
3351}
3352
3353/* Dump a table entry to a stream interface's
3354 * read buffer. It returns 0 if the output buffer is full
3355 * and needs to be called again, otherwise non-zero.
3356 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003357static int table_dump_entry_to_buffer(struct buffer *msg,
3358 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003359 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003360{
3361 int dt;
3362
3363 chunk_appendf(msg, "%p:", entry);
3364
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003365 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003366 char addr[INET_ADDRSTRLEN];
3367 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3368 chunk_appendf(msg, " key=%s", addr);
3369 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003370 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003371 char addr[INET6_ADDRSTRLEN];
3372 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3373 chunk_appendf(msg, " key=%s", addr);
3374 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003375 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003376 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003377 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003378 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003379 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003380 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003381 }
3382 else {
3383 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003384 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003385 }
3386
3387 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3388
3389 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3390 void *ptr;
3391
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003392 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003393 continue;
3394 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Emeric Brunfc581172021-06-30 16:24:04 +02003395 chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003396 else
3397 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3398
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003399 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003400 switch (stktable_data_types[dt].std_type) {
3401 case STD_T_SINT:
3402 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3403 break;
3404 case STD_T_UINT:
3405 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3406 break;
3407 case STD_T_ULL:
Emeric Brunfc581172021-06-30 16:24:04 +02003408 chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003409 break;
3410 case STD_T_FRQP:
Emeric Brunfc581172021-06-30 16:24:04 +02003411 chunk_appendf(msg, "%u",
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003412 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003413 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003414 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003415 case STD_T_DICT: {
3416 struct dict_entry *de;
3417 de = stktable_data_cast(ptr, std_t_dict);
3418 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3419 break;
3420 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003421 }
3422 }
3423 chunk_appendf(msg, "\n");
3424
Willy Tarreau06d80a92017-10-19 14:32:15 +02003425 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003426 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003427 return 0;
3428 }
3429
3430 return 1;
3431}
3432
3433
3434/* Processes a single table entry matching a specific key passed in argument.
3435 * returns 0 if wants to be called again, 1 if has ended processing.
3436 */
3437static int table_process_entry_per_key(struct appctx *appctx, char **args)
3438{
3439 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003440 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003441 struct stksess *ts;
3442 uint32_t uint32_key;
3443 unsigned char ip6_key[sizeof(struct in6_addr)];
3444 long long value;
3445 int data_type;
3446 int cur_arg;
3447 void *ptr;
3448 struct freq_ctr_period *frqp;
3449
Willy Tarreau9d008692019-08-09 11:21:01 +02003450 if (!*args[4])
3451 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003452
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003453 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003454 case SMP_T_IPV4:
3455 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003456 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003457 break;
3458 case SMP_T_IPV6:
3459 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003460 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003461 break;
3462 case SMP_T_SINT:
3463 {
3464 char *endptr;
3465 unsigned long val;
3466 errno = 0;
3467 val = strtoul(args[4], &endptr, 10);
3468 if ((errno == ERANGE && val == ULONG_MAX) ||
3469 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003470 val > 0xffffffff)
3471 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003472 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003473 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003474 break;
3475 }
3476 break;
3477 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003478 static_table_key.key = args[4];
3479 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003480 break;
3481 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003482 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003483 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003484 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 +01003485 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003486 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 +01003487 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003488 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 +01003489 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003490 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003491 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003492 }
3493
3494 /* check permissions */
3495 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3496 return 1;
3497
Willy Tarreaua24bc782016-12-14 15:50:35 +01003498 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003499 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003500 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003501 if (!ts)
3502 return 1;
3503 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003504 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3505 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003506 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003507 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003508 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003509 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003510 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003511 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003512 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003513 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003514 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003515 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003516 break;
3517
3518 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003519 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003520 if (!ts)
3521 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003522
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003523 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003524 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003525 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003526 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003527 break;
3528
3529 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003530 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003531 if (!ts) {
3532 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003533 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003534 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003535 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003536 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3537 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003538 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003539 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003540 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003541 return 1;
3542 }
3543
3544 data_type = stktable_get_data_type(args[cur_arg] + 5);
3545 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003546 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003547 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003548 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003549 return 1;
3550 }
3551
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003552 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003553 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003554 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003555 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003556 return 1;
3557 }
3558
3559 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003560 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003561 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003562 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003563 return 1;
3564 }
3565
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003566 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003567
3568 switch (stktable_data_types[data_type].std_type) {
3569 case STD_T_SINT:
3570 stktable_data_cast(ptr, std_t_sint) = value;
3571 break;
3572 case STD_T_UINT:
3573 stktable_data_cast(ptr, std_t_uint) = value;
3574 break;
3575 case STD_T_ULL:
3576 stktable_data_cast(ptr, std_t_ull) = value;
3577 break;
3578 case STD_T_FRQP:
3579 /* We set both the current and previous values. That way
3580 * the reported frequency is stable during all the period
3581 * then slowly fades out. This allows external tools to
3582 * push measures without having to update them too often.
3583 */
3584 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003585 /* First bit is reserved for the freq_ctr_period lock
3586 Note: here we're still protected by the stksess lock
3587 so we don't need to update the update the freq_ctr_period
3588 using its internal lock */
3589 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003590 frqp->prev_ctr = 0;
3591 frqp->curr_ctr = value;
3592 break;
3593 }
3594 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003595 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003596 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597 break;
3598
3599 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003600 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003601 }
3602 return 1;
3603}
3604
3605/* Prepares the appctx fields with the data-based filters from the command line.
3606 * Returns 0 if the dump can proceed, 1 if has ended processing.
3607 */
3608static int table_prepare_data_request(struct appctx *appctx, char **args)
3609{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003610 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003611 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003612
Willy Tarreau9d008692019-08-09 11:21:01 +02003613 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3614 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003615
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003616 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3617 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3618 break;
3619 /* condition on stored data value */
3620 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3621 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003622 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003623
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003624 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003625 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 +01003626
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003627 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003628 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003629 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 +01003630
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003631 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 +01003632 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3633 }
3634
3635 if (*args[3+3*i]) {
3636 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 +01003637 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003638
3639 /* OK we're done, all the fields are set */
3640 return 0;
3641}
3642
3643/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003644static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003645{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003646 int i;
3647
3648 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3649 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003650 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003651 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003652 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003653
3654 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003655 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003656 if (!appctx->ctx.table.target)
3657 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003658 }
3659 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003660 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003661 goto err_args;
3662 return 0;
3663 }
3664
3665 if (strcmp(args[3], "key") == 0)
3666 return table_process_entry_per_key(appctx, args);
3667 else if (strncmp(args[3], "data.", 5) == 0)
3668 return table_prepare_data_request(appctx, args);
3669 else if (*args[3])
3670 goto err_args;
3671
3672 return 0;
3673
3674err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003675 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003676 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003677 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 +01003678 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003679 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 +01003680 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003681 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003682 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003683 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003684 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003685}
3686
3687/* This function is used to deal with table operations (dump or clear depending
3688 * on the action stored in appctx->private). It returns 0 if the output buffer is
3689 * full and it needs to be called again, otherwise non-zero.
3690 */
3691static int cli_io_handler_table(struct appctx *appctx)
3692{
3693 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003694 struct stream *s = si_strm(si);
3695 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003696 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003697 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003698
3699 /*
3700 * We have 3 possible states in appctx->st2 :
3701 * - STAT_ST_INIT : the first call
3702 * - STAT_ST_INFO : the proxy pointer points to the next table to
3703 * dump, the entry pointer is NULL ;
3704 * - STAT_ST_LIST : the proxy pointer points to the current table
3705 * and the entry pointer points to the next entry to be dumped,
3706 * and the refcount on the next entry is held ;
3707 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3708 * data though.
3709 */
3710
3711 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3712 /* in case of abort, remove any refcount we might have set on an entry */
3713 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003714 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003715 }
3716 return 1;
3717 }
3718
3719 chunk_reset(&trash);
3720
3721 while (appctx->st2 != STAT_ST_FIN) {
3722 switch (appctx->st2) {
3723 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003724 appctx->ctx.table.t = appctx->ctx.table.target;
3725 if (!appctx->ctx.table.t)
3726 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003727
3728 appctx->ctx.table.entry = NULL;
3729 appctx->st2 = STAT_ST_INFO;
3730 break;
3731
3732 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003733 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003734 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003735 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003736 appctx->st2 = STAT_ST_END;
3737 break;
3738 }
3739
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003740 if (appctx->ctx.table.t->size) {
3741 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003742 return 0;
3743
3744 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003745 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003746 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003747 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3748 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003749 if (eb) {
3750 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3751 appctx->ctx.table.entry->ref_cnt++;
3752 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003753 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003754 break;
3755 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003756 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003757 }
3758 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003759 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003760 break;
3761
3762 case STAT_ST_LIST:
3763 skip_entry = 0;
3764
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003765 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003766
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003767 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003768 /* we're filtering on some data contents */
3769 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003770 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003771 signed char op;
3772 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003773
Emeric Brun819fc6f2017-06-13 19:37:32 +02003774
Willy Tarreau2b64a352020-01-22 17:09:47 +01003775 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003776 if (appctx->ctx.table.data_type[i] == -1)
3777 break;
3778 dt = appctx->ctx.table.data_type[i];
3779 ptr = stktable_data_ptr(appctx->ctx.table.t,
3780 appctx->ctx.table.entry,
3781 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003782
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003783 data = 0;
3784 switch (stktable_data_types[dt].std_type) {
3785 case STD_T_SINT:
3786 data = stktable_data_cast(ptr, std_t_sint);
3787 break;
3788 case STD_T_UINT:
3789 data = stktable_data_cast(ptr, std_t_uint);
3790 break;
3791 case STD_T_ULL:
3792 data = stktable_data_cast(ptr, std_t_ull);
3793 break;
3794 case STD_T_FRQP:
3795 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3796 appctx->ctx.table.t->data_arg[dt].u);
3797 break;
3798 }
3799
3800 op = appctx->ctx.table.data_op[i];
3801 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003802
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003803 /* skip the entry if the data does not match the test and the value */
3804 if ((data < value &&
3805 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3806 (data == value &&
3807 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3808 (data > value &&
3809 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3810 skip_entry = 1;
3811 break;
3812 }
3813 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003814 }
3815
3816 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003817 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003818 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003819 return 0;
3820 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003821
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003822 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003823
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003824 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003825 appctx->ctx.table.entry->ref_cnt--;
3826
3827 eb = ebmb_next(&appctx->ctx.table.entry->key);
3828 if (eb) {
3829 struct stksess *old = appctx->ctx.table.entry;
3830 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3831 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003832 __stksess_kill_if_expired(appctx->ctx.table.t, old);
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, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003835 appctx->ctx.table.entry->ref_cnt++;
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 break;
3838 }
3839
3840
3841 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003842 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003843 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003844 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003845
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003846 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003847
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003848 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003849 appctx->st2 = STAT_ST_INFO;
3850 break;
3851
3852 case STAT_ST_END:
3853 appctx->st2 = STAT_ST_FIN;
3854 break;
3855 }
3856 }
3857 return 1;
3858}
3859
3860static void cli_release_show_table(struct appctx *appctx)
3861{
3862 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003863 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003864 }
3865}
3866
Willy Tarreau478331d2020-08-28 11:31:31 +02003867static void stkt_late_init(void)
3868{
3869 struct sample_fetch *f;
3870
3871 f = find_sample_fetch("src", strlen("src"));
3872 if (f)
3873 smp_fetch_src = f->process;
3874}
3875
3876INITCALL0(STG_INIT, stkt_late_init);
3877
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003878/* register cli keywords */
3879static struct cli_kw_list cli_kws = {{ },{
3880 { { "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 },
3881 { { "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 },
3882 { { "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 },
3883 {{},}
3884}};
3885
Willy Tarreau0108d902018-11-25 19:14:37 +01003886INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003887
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003888static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003889 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003890 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003891 { "sc-set-gpt0", parse_set_gpt0, 1 },
3892 { /* END */ }
3893}};
3894
Willy Tarreau0108d902018-11-25 19:14:37 +01003895INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3896
Willy Tarreau620408f2016-10-21 16:37:51 +02003897static struct action_kw_list tcp_sess_kws = { { }, {
3898 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003899 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003900 { "sc-set-gpt0", parse_set_gpt0, 1 },
3901 { /* END */ }
3902}};
3903
Willy Tarreau0108d902018-11-25 19:14:37 +01003904INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3905
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003906static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003907 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003908 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003909 { "sc-set-gpt0", parse_set_gpt0, 1 },
3910 { /* END */ }
3911}};
3912
Willy Tarreau0108d902018-11-25 19:14:37 +01003913INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3914
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003915static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003916 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003917 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003918 { "sc-set-gpt0", parse_set_gpt0, 1 },
3919 { /* END */ }
3920}};
3921
Willy Tarreau0108d902018-11-25 19:14:37 +01003922INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3923
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003924static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003925 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003926 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003927 { "sc-set-gpt0", parse_set_gpt0, 1 },
3928 { /* END */ }
3929}};
3930
Willy Tarreau0108d902018-11-25 19:14:37 +01003931INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3932
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003933static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003934 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003935 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003936 { "sc-set-gpt0", parse_set_gpt0, 1 },
3937 { /* END */ }
3938}};
3939
Willy Tarreau0108d902018-11-25 19:14:37 +01003940INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3941
Willy Tarreau7d562212016-11-25 16:10:05 +01003942///* Note: must not be declared <const> as its list will be overwritten.
3943// * Please take care of keeping this list alphabetically sorted.
3944// */
3945//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3946// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3947// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3948// { /* END */ },
3949//}};
3950/* Note: must not be declared <const> as its list will be overwritten.
3951 * Please take care of keeping this list alphabetically sorted.
3952 */
3953static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3954 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3955 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3956 { "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 +01003957 { "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 +01003958 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3959 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3960 { "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 +01003961 { "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 +01003962 { "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 +01003963 { "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 +01003964 { "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 +01003965 { "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 +01003966 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3967 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3968 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3969 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3970 { "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 +01003971 { "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 +01003972 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3973 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3974 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3975 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3976 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3977 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3978 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3979 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3980 { "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 +01003981 { "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 +01003982 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3984 { "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 +01003985 { "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 +01003986 { "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 +01003987 { "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 +01003988 { "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 +01003989 { "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 +01003990 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3991 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3992 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3993 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3994 { "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 +01003995 { "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 +01003996 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3997 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3998 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3999 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4000 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4001 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4002 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4003 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4004 { "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 +01004005 { "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 +01004006 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4007 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4008 { "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 +01004009 { "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 +01004010 { "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 +01004011 { "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 +01004012 { "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 +01004013 { "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 +01004014 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4015 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4016 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4017 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4018 { "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 +01004019 { "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 +01004020 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4021 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4022 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4023 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4024 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4025 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4026 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4027 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4028 { "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 +01004029 { "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 +01004030 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4031 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4032 { "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 +01004033 { "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 +01004034 { "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 +01004035 { "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 +01004036 { "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 +01004037 { "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 +01004038 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4039 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4040 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4041 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4042 { "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 +01004043 { "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 +01004044 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4045 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4046 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4047 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4048 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4049 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4050 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4051 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4052 { "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 +01004053 { "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 +01004054 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4055 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4056 { "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 +01004057 { "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 +01004058 { "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 +01004059 { "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 +01004060 { "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 +01004061 { "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 +01004062 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4063 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4064 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4065 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4066 { "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 +01004067 { "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 +01004068 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4069 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4070 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4071 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4072 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4073 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4074 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4075 { /* END */ },
4076}};
4077
Willy Tarreau0108d902018-11-25 19:14:37 +01004078INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004079
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004080/* Note: must not be declared <const> as its list will be overwritten */
4081static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004082 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4083 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4084 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4085 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4086 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4087 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4088 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4089 { "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 +01004090 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004091 { "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 +01004092 { "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 +02004093 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4094 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4095 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4096 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4097 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4098 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4099 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4100 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4101 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4102 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004103 { /* END */ },
4104}};
4105
Willy Tarreau0108d902018-11-25 19:14:37 +01004106INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);