blob: 505916421583ff88c0a0ffb09e3ae08f857ceddd [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{
633 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200634 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100635 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100636 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100637 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100639 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 +0100640
641 t->exp_next = TICK_ETERNITY;
642 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200643 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200644 if (!t->exp_task)
645 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647 t->exp_task->context = (void *)t;
648 }
Willy Tarreauc3914d42020-09-24 08:39:22 +0200649 if (t->peers.p && t->peers.p->peers_fe && !t->peers.p->peers_fe->disabled) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200650 peers_register_table(t->peers.p, t);
651 }
652
Emeric Brun3bd697e2010-01-04 15:23:48 +0100653 return t->pool != NULL;
654 }
655 return 1;
656}
657
658/*
659 * Configuration keywords of known table types
660 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200661struct stktable_type stktable_types[SMP_TYPES] = {
662 [SMP_T_SINT] = { "integer", 0, 4 },
663 [SMP_T_IPV4] = { "ip", 0, 4 },
664 [SMP_T_IPV6] = { "ipv6", 0, 16 },
665 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
666 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
667};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100668
669/*
670 * Parse table type configuration.
671 * Returns 0 on successful parsing, else 1.
672 * <myidx> is set at next configuration <args> index.
673 */
674int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
675{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200676 for (*type = 0; *type < SMP_TYPES; (*type)++) {
677 if (!stktable_types[*type].kw)
678 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100679 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
680 continue;
681
682 *key_size = stktable_types[*type].default_size;
683 (*myidx)++;
684
Willy Tarreauaea940e2010-06-06 11:56:36 +0200685 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100686 if (strcmp("len", args[*myidx]) == 0) {
687 (*myidx)++;
688 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200689 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100690 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200691 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200692 /* null terminated string needs +1 for '\0'. */
693 (*key_size)++;
694 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100695 (*myidx)++;
696 }
697 }
698 return 0;
699 }
700 return 1;
701}
702
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100703/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100704 * Parse a line with <linenum> as number in <file> configuration file to configure
705 * the stick-table with <t> as address and <id> as ID.
706 * <peers> provides the "peers" section pointer only if this function is called
707 * from a "peers" section.
708 * <nid> is the stick-table name which is sent over the network. It must be equal
709 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
710 * "peers" section name followed by a '/' character if parsed from a "peers" section.
Ilya Shipitsind4259502020-04-08 01:07:56 +0500711 * This is the responsibility of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100712 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
713 */
714int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100715 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100716{
717 int err_code = 0;
718 int idx = 1;
719 unsigned int val;
720
721 if (!id || !*id) {
722 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
723 err_code |= ERR_ALERT | ERR_ABORT;
724 goto out;
725 }
726
727 /* Store the "peers" section if this function is called from a "peers" section. */
728 if (peers) {
729 t->peers.p = peers;
730 idx++;
731 }
732
733 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100734 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100735 t->type = (unsigned int)-1;
736 t->conf.file = file;
737 t->conf.line = linenum;
738
739 while (*args[idx]) {
740 const char *err;
741
742 if (strcmp(args[idx], "size") == 0) {
743 idx++;
744 if (!*(args[idx])) {
745 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
746 file, linenum, args[0], args[idx-1]);
747 err_code |= ERR_ALERT | ERR_FATAL;
748 goto out;
749 }
750 if ((err = parse_size_err(args[idx], &t->size))) {
751 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
752 file, linenum, args[0], *err, args[idx-1]);
753 err_code |= ERR_ALERT | ERR_FATAL;
754 goto out;
755 }
756 idx++;
757 }
758 /* This argument does not exit in "peers" section. */
759 else if (!peers && strcmp(args[idx], "peers") == 0) {
760 idx++;
761 if (!*(args[idx])) {
762 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
763 file, linenum, args[0], args[idx-1]);
764 err_code |= ERR_ALERT | ERR_FATAL;
765 goto out;
766 }
767 t->peers.name = strdup(args[idx++]);
768 }
769 else if (strcmp(args[idx], "expire") == 0) {
770 idx++;
771 if (!*(args[idx])) {
772 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
773 file, linenum, args[0], args[idx-1]);
774 err_code |= ERR_ALERT | ERR_FATAL;
775 goto out;
776 }
777 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200778 if (err == PARSE_TIME_OVER) {
779 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
780 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100781 err_code |= ERR_ALERT | ERR_FATAL;
782 goto out;
783 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200784 else if (err == PARSE_TIME_UNDER) {
785 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
786 file, linenum, args[0], args[idx], args[idx-1]);
787 err_code |= ERR_ALERT | ERR_FATAL;
788 goto out;
789 }
790 else if (err) {
791 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
792 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100793 err_code |= ERR_ALERT | ERR_FATAL;
794 goto out;
795 }
796 t->expire = val;
797 idx++;
798 }
799 else if (strcmp(args[idx], "nopurge") == 0) {
800 t->nopurge = 1;
801 idx++;
802 }
803 else if (strcmp(args[idx], "type") == 0) {
804 idx++;
805 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
806 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
807 file, linenum, args[0], args[idx]);
808 err_code |= ERR_ALERT | ERR_FATAL;
809 goto out;
810 }
811 /* idx already points to next arg */
812 }
813 else if (strcmp(args[idx], "store") == 0) {
814 int type, err;
815 char *cw, *nw, *sa;
816
817 idx++;
818 nw = args[idx];
819 while (*nw) {
820 /* the "store" keyword supports a comma-separated list */
821 cw = nw;
822 sa = NULL; /* store arg */
823 while (*nw && *nw != ',') {
824 if (*nw == '(') {
825 *nw = 0;
826 sa = ++nw;
827 while (*nw != ')') {
828 if (!*nw) {
829 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
830 file, linenum, args[0], cw);
831 err_code |= ERR_ALERT | ERR_FATAL;
832 goto out;
833 }
834 nw++;
835 }
836 *nw = '\0';
837 }
838 nw++;
839 }
840 if (*nw)
841 *nw++ = '\0';
842 type = stktable_get_data_type(cw);
843 if (type < 0) {
844 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
845 file, linenum, args[0], cw);
846 err_code |= ERR_ALERT | ERR_FATAL;
847 goto out;
848 }
849
850 err = stktable_alloc_data_type(t, type, sa);
851 switch (err) {
852 case PE_NONE: break;
853 case PE_EXIST:
854 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
855 file, linenum, args[0], cw);
856 err_code |= ERR_WARN;
857 break;
858
859 case PE_ARG_MISSING:
860 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
861 file, linenum, args[0], cw);
862 err_code |= ERR_ALERT | ERR_FATAL;
863 goto out;
864
865 case PE_ARG_NOT_USED:
866 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
867 file, linenum, args[0], cw);
868 err_code |= ERR_ALERT | ERR_FATAL;
869 goto out;
870
871 default:
872 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
873 file, linenum, args[0], cw);
874 err_code |= ERR_ALERT | ERR_FATAL;
875 goto out;
876 }
877 }
878 idx++;
879 }
880 else {
881 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
882 file, linenum, args[0], args[idx]);
883 err_code |= ERR_ALERT | ERR_FATAL;
884 goto out;
885 }
886 }
887
888 if (!t->size) {
889 ha_alert("parsing [%s:%d] : %s: missing size.\n",
890 file, linenum, args[0]);
891 err_code |= ERR_ALERT | ERR_FATAL;
892 goto out;
893 }
894
895 if (t->type == (unsigned int)-1) {
896 ha_alert("parsing [%s:%d] : %s: missing type.\n",
897 file, linenum, args[0]);
898 err_code |= ERR_ALERT | ERR_FATAL;
899 goto out;
900 }
901
902 out:
903 return err_code;
904}
905
Willy Tarreau8fed9032014-07-03 17:02:46 +0200906/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200907 * Note that the sample *is* modified and that the returned key may point
908 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200909 * Returns NULL if the sample could not be converted (eg: no matching type),
910 * otherwise a pointer to the static stktable_key filled with what is needed
911 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200912 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200913struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200914{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200915 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200916 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200917 return NULL;
918
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200919 /* Fill static_table_key. */
920 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200921
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200922 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200923 static_table_key.key = &smp->data.u.ipv4;
924 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200925 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200926
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200927 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200928 static_table_key.key = &smp->data.u.ipv6;
929 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200930 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200931
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200932 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200933 /* The stick table require a 32bit unsigned int, "sint" is a
934 * signed 64 it, so we can convert it inplace.
935 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200936 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200937 static_table_key.key = &smp->data.u.sint;
938 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200939 break;
940
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200941 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200942 if (!smp_make_safe(smp))
943 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200944 static_table_key.key = smp->data.u.str.area;
945 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200946 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200947
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200948 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200949 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200950 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200951 if (!smp_make_rw(smp))
952 return NULL;
953
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200954 if (smp->data.u.str.size < t->key_size)
955 if (!smp_dup(smp))
956 return NULL;
957 if (smp->data.u.str.size < t->key_size)
958 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200959 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
960 t->key_size - smp->data.u.str.data);
961 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200962 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200963 static_table_key.key = smp->data.u.str.area;
964 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200965 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200966
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200967 default: /* impossible case. */
968 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200969 }
970
Christopher Fauletca20d022017-08-29 15:30:31 +0200971 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200972}
973
974/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200975 * Process a fetch + format conversion as defined by the sample expression <expr>
976 * on request or response considering the <opt> parameter. Returns either NULL if
977 * no key could be extracted, or a pointer to the converted result stored in
978 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
979 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200980 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
981 * without SMP_OPT_FINAL). The output will be usable like this :
982 *
983 * return MAY_CHANGE FINAL Meaning for the sample
984 * NULL 0 * Not present and will never be (eg: header)
985 * NULL 1 0 Not present or unstable, could change (eg: req_len)
986 * NULL 1 1 Not present, will not change anymore
987 * smp 0 * Present and will not change (eg: header)
988 * smp 1 0 not possible
989 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200990 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200991struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200992 unsigned int opt, struct sample_expr *expr, struct sample *smp)
993{
994 if (smp)
995 memset(smp, 0, sizeof(*smp));
996
Willy Tarreau192252e2015-04-04 01:47:55 +0200997 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200998 if (!smp)
999 return NULL;
1000
1001 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1002 return NULL; /* we can only use stable samples */
1003
1004 return smp_to_stkey(smp, t);
1005}
1006
1007/*
Willy Tarreau12785782012-04-27 21:37:17 +02001008 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001009 * type <table_type>, otherwise zero. Used in configuration check.
1010 */
Willy Tarreau12785782012-04-27 21:37:17 +02001011int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001012{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001013 int out_type;
1014
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001015 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001016 return 0;
1017
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001018 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001019
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001020 /* Convert sample. */
1021 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001022 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001023
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001024 return 1;
1025}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001026
Willy Tarreauedee1d62014-07-15 16:44:27 +02001027/* Extra data types processing : after the last one, some room may remain
1028 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1029 * at run time.
1030 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001031struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001032 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001033 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001034 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001035 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001036 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1037 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1038 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1039 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1040 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1041 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1042 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1043 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1044 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1045 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1046 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1047 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1048 [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 +01001049 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1050 [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 +02001051 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001052};
1053
Willy Tarreauedee1d62014-07-15 16:44:27 +02001054/* Registers stick-table extra data type with index <idx>, name <name>, type
1055 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1056 * index is automatically allocated. The allocated index is returned, or -1 if
1057 * no free index was found or <name> was already registered. The <name> is used
1058 * directly as a pointer, so if it's not stable, the caller must allocate it.
1059 */
1060int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1061{
1062 if (idx < 0) {
1063 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1064 if (!stktable_data_types[idx].name)
1065 break;
1066
1067 if (strcmp(stktable_data_types[idx].name, name) == 0)
1068 return -1;
1069 }
1070 }
1071
1072 if (idx >= STKTABLE_DATA_TYPES)
1073 return -1;
1074
1075 if (stktable_data_types[idx].name != NULL)
1076 return -1;
1077
1078 stktable_data_types[idx].name = name;
1079 stktable_data_types[idx].std_type = std_type;
1080 stktable_data_types[idx].arg_type = arg_type;
1081 return idx;
1082}
1083
Willy Tarreau08d5f982010-06-06 13:34:54 +02001084/*
1085 * Returns the data type number for the stktable_data_type whose name is <name>,
1086 * or <0 if not found.
1087 */
1088int stktable_get_data_type(char *name)
1089{
1090 int type;
1091
1092 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001093 if (!stktable_data_types[type].name)
1094 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001095 if (strcmp(name, stktable_data_types[type].name) == 0)
1096 return type;
1097 }
1098 return -1;
1099}
1100
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001101/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1102 * it up into this table. Returns true if found, false otherwise. The input
1103 * type is STR so that input samples are converted to string (since all types
1104 * can be converted to strings), then the function casts the string again into
1105 * the table's type. This is a double conversion, but in the future we might
1106 * support automatic input types to perform the cast on the fly.
1107 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001108static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001109{
1110 struct stktable *t;
1111 struct stktable_key *key;
1112 struct stksess *ts;
1113
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001114 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001115
1116 key = smp_to_stkey(smp, t);
1117 if (!key)
1118 return 0;
1119
1120 ts = stktable_lookup_key(t, key);
1121
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001122 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001123 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001124 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001125 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001126 return 1;
1127}
1128
1129/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1130 * it up into this table. Returns the data rate received from clients in bytes/s
1131 * if the key is present in the table, otherwise zero, so that comparisons can
1132 * be easily performed. If the inspected parameter is not stored in the table,
1133 * <not found> is returned.
1134 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001135static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001136{
1137 struct stktable *t;
1138 struct stktable_key *key;
1139 struct stksess *ts;
1140 void *ptr;
1141
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001142 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001143
1144 key = smp_to_stkey(smp, t);
1145 if (!key)
1146 return 0;
1147
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001148 ts = stktable_lookup_key(t, key);
1149
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001150 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001151 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001152 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001153
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001154 if (!ts) /* key not present */
1155 return 1;
1156
1157 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001158 if (ptr)
1159 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1160 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001161
Daniel Corbett3e60b112018-05-27 09:47:12 -04001162 stktable_release(t, ts);
1163 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001164}
1165
1166/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1167 * it up into this table. Returns the cumulated number of connections for the key
1168 * if the key is present in the table, otherwise zero, so that comparisons can
1169 * be easily performed. If the inspected parameter is not stored in the table,
1170 * <not found> is returned.
1171 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001172static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001173{
1174 struct stktable *t;
1175 struct stktable_key *key;
1176 struct stksess *ts;
1177 void *ptr;
1178
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001179 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001180
1181 key = smp_to_stkey(smp, t);
1182 if (!key)
1183 return 0;
1184
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001185 ts = stktable_lookup_key(t, key);
1186
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001187 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001188 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001189 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001190
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001191 if (!ts) /* key not present */
1192 return 1;
1193
1194 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001195 if (ptr)
1196 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001197
Daniel Corbett3e60b112018-05-27 09:47:12 -04001198 stktable_release(t, ts);
1199 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001200}
1201
1202/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1203 * it up into this table. Returns the number of concurrent connections for the
1204 * key if the key is present in the table, otherwise zero, so that comparisons
1205 * can be easily performed. If the inspected parameter is not stored in the
1206 * table, <not found> is returned.
1207 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001208static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001209{
1210 struct stktable *t;
1211 struct stktable_key *key;
1212 struct stksess *ts;
1213 void *ptr;
1214
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001215 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001216
1217 key = smp_to_stkey(smp, t);
1218 if (!key)
1219 return 0;
1220
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001221 ts = stktable_lookup_key(t, key);
1222
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001223 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001224 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001225 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001226
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001227 if (!ts) /* key not present */
1228 return 1;
1229
1230 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001231 if (ptr)
1232 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001233
Daniel Corbett3e60b112018-05-27 09:47:12 -04001234 stktable_release(t, ts);
1235 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001236}
1237
1238/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1239 * it up into this table. Returns the rate of incoming connections from the key
1240 * if the key is present in the table, otherwise zero, so that comparisons can
1241 * be easily performed. If the inspected parameter is not stored in the table,
1242 * <not found> is returned.
1243 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001244static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001245{
1246 struct stktable *t;
1247 struct stktable_key *key;
1248 struct stksess *ts;
1249 void *ptr;
1250
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001251 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252
1253 key = smp_to_stkey(smp, t);
1254 if (!key)
1255 return 0;
1256
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001257 ts = stktable_lookup_key(t, key);
1258
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001259 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001260 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001261 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001262
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001263 if (!ts) /* key not present */
1264 return 1;
1265
1266 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001267 if (ptr)
1268 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1269 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001270
Daniel Corbett3e60b112018-05-27 09:47:12 -04001271 stktable_release(t, ts);
1272 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001273}
1274
1275/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1276 * it up into this table. Returns the data rate sent to clients in bytes/s
1277 * if the key is present in the table, otherwise zero, so that comparisons can
1278 * be easily performed. If the inspected parameter is not stored in the table,
1279 * <not found> is returned.
1280 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001281static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001282{
1283 struct stktable *t;
1284 struct stktable_key *key;
1285 struct stksess *ts;
1286 void *ptr;
1287
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001288 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001289
1290 key = smp_to_stkey(smp, t);
1291 if (!key)
1292 return 0;
1293
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001294 ts = stktable_lookup_key(t, key);
1295
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001296 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001297 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001298 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001299
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001300 if (!ts) /* key not present */
1301 return 1;
1302
1303 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001304 if (ptr)
1305 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1306 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307
Daniel Corbett3e60b112018-05-27 09:47:12 -04001308 stktable_release(t, ts);
1309 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310}
1311
1312/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001313 * it up into this table. Returns the value of the GPT0 tag for the key
1314 * if the key is present in the table, otherwise false, so that comparisons can
1315 * be easily performed. If the inspected parameter is not stored in the table,
1316 * <not found> is returned.
1317 */
1318static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1319{
1320 struct stktable *t;
1321 struct stktable_key *key;
1322 struct stksess *ts;
1323 void *ptr;
1324
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001325 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001326
1327 key = smp_to_stkey(smp, t);
1328 if (!key)
1329 return 0;
1330
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001331 ts = stktable_lookup_key(t, key);
1332
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001333 smp->flags = SMP_F_VOL_TEST;
1334 smp->data.type = SMP_T_SINT;
1335 smp->data.u.sint = 0;
1336
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001337 if (!ts) /* key not present */
1338 return 1;
1339
1340 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001341 if (ptr)
1342 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001343
Daniel Corbett3e60b112018-05-27 09:47:12 -04001344 stktable_release(t, ts);
1345 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001346}
1347
1348/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001349 * it up into this table. Returns the value of the GPC0 counter for the key
1350 * if the key is present in the table, otherwise zero, so that comparisons can
1351 * be easily performed. If the inspected parameter is not stored in the table,
1352 * <not found> is returned.
1353 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001354static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001355{
1356 struct stktable *t;
1357 struct stktable_key *key;
1358 struct stksess *ts;
1359 void *ptr;
1360
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001361 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362
1363 key = smp_to_stkey(smp, t);
1364 if (!key)
1365 return 0;
1366
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001367 ts = stktable_lookup_key(t, key);
1368
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001369 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001370 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001371 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001373 if (!ts) /* key not present */
1374 return 1;
1375
1376 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001377 if (ptr)
1378 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379
Daniel Corbett3e60b112018-05-27 09:47:12 -04001380 stktable_release(t, ts);
1381 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382}
1383
1384/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1385 * it up into this table. Returns the event rate of the GPC0 counter for the key
1386 * if the key is present in the table, otherwise zero, so that comparisons can
1387 * be easily performed. If the inspected parameter is not stored in the table,
1388 * <not found> is returned.
1389 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001390static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391{
1392 struct stktable *t;
1393 struct stktable_key *key;
1394 struct stksess *ts;
1395 void *ptr;
1396
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001397 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398
1399 key = smp_to_stkey(smp, t);
1400 if (!key)
1401 return 0;
1402
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001403 ts = stktable_lookup_key(t, key);
1404
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001405 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001406 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001407 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001408
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001409 if (!ts) /* key not present */
1410 return 1;
1411
1412 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001413 if (ptr)
1414 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1415 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001416
Daniel Corbett3e60b112018-05-27 09:47:12 -04001417 stktable_release(t, ts);
1418 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001419}
1420
1421/* 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 +01001422 * it up into this table. Returns the value of the GPC1 counter for the key
1423 * if the key is present in the table, otherwise zero, so that comparisons can
1424 * be easily performed. If the inspected parameter is not stored in the table,
1425 * <not found> is returned.
1426 */
1427static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1428{
1429 struct stktable *t;
1430 struct stktable_key *key;
1431 struct stksess *ts;
1432 void *ptr;
1433
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001434 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001435
1436 key = smp_to_stkey(smp, t);
1437 if (!key)
1438 return 0;
1439
1440 ts = stktable_lookup_key(t, key);
1441
1442 smp->flags = SMP_F_VOL_TEST;
1443 smp->data.type = SMP_T_SINT;
1444 smp->data.u.sint = 0;
1445
1446 if (!ts) /* key not present */
1447 return 1;
1448
1449 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001450 if (ptr)
1451 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001452
Daniel Corbett3e60b112018-05-27 09:47:12 -04001453 stktable_release(t, ts);
1454 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001455}
1456
1457/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1458 * it up into this table. Returns the event rate of the GPC1 counter for the key
1459 * if the key is present in the table, otherwise zero, so that comparisons can
1460 * be easily performed. If the inspected parameter is not stored in the table,
1461 * <not found> is returned.
1462 */
1463static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1464{
1465 struct stktable *t;
1466 struct stktable_key *key;
1467 struct stksess *ts;
1468 void *ptr;
1469
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001470 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001471
1472 key = smp_to_stkey(smp, t);
1473 if (!key)
1474 return 0;
1475
1476 ts = stktable_lookup_key(t, key);
1477
1478 smp->flags = SMP_F_VOL_TEST;
1479 smp->data.type = SMP_T_SINT;
1480 smp->data.u.sint = 0;
1481
1482 if (!ts) /* key not present */
1483 return 1;
1484
1485 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001486 if (ptr)
1487 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1488 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001489
Daniel Corbett3e60b112018-05-27 09:47:12 -04001490 stktable_release(t, ts);
1491 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001492}
1493
1494/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001495 * it up into this table. Returns the cumulated number of HTTP request errors
1496 * for the key if the key is present in the table, otherwise zero, so that
1497 * comparisons can be easily performed. If the inspected parameter is not stored
1498 * in the table, <not found> is returned.
1499 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001500static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001501{
1502 struct stktable *t;
1503 struct stktable_key *key;
1504 struct stksess *ts;
1505 void *ptr;
1506
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001507 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001508
1509 key = smp_to_stkey(smp, t);
1510 if (!key)
1511 return 0;
1512
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001513 ts = stktable_lookup_key(t, key);
1514
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001515 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001516 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001517 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001518
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001519 if (!ts) /* key not present */
1520 return 1;
1521
1522 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001523 if (ptr)
1524 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001525
Daniel Corbett3e60b112018-05-27 09:47:12 -04001526 stktable_release(t, ts);
1527 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001528}
1529
1530/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1531 * it up into this table. Returns the HTTP request error rate the key
1532 * if the key is present in the table, otherwise zero, so that comparisons can
1533 * be easily performed. If the inspected parameter is not stored in the table,
1534 * <not found> is returned.
1535 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001536static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001537{
1538 struct stktable *t;
1539 struct stktable_key *key;
1540 struct stksess *ts;
1541 void *ptr;
1542
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001543 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001544
1545 key = smp_to_stkey(smp, t);
1546 if (!key)
1547 return 0;
1548
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001549 ts = stktable_lookup_key(t, key);
1550
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001551 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001552 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001553 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001554
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001555 if (!ts) /* key not present */
1556 return 1;
1557
1558 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001559 if (ptr)
1560 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1561 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001562
Daniel Corbett3e60b112018-05-27 09:47:12 -04001563 stktable_release(t, ts);
1564 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001565}
1566
1567/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1568 * it up into this table. Returns the cumulated number of HTTP request for the
1569 * key if the key is present in the table, otherwise zero, so that comparisons
1570 * can be easily performed. If the inspected parameter is not stored in the
1571 * table, <not found> is returned.
1572 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001573static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001574{
1575 struct stktable *t;
1576 struct stktable_key *key;
1577 struct stksess *ts;
1578 void *ptr;
1579
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001580 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001581
1582 key = smp_to_stkey(smp, t);
1583 if (!key)
1584 return 0;
1585
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001586 ts = stktable_lookup_key(t, key);
1587
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001588 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001589 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001590 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001591
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001592 if (!ts) /* key not present */
1593 return 1;
1594
1595 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001596 if (ptr)
1597 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001598
Daniel Corbett3e60b112018-05-27 09:47:12 -04001599 stktable_release(t, ts);
1600 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001601}
1602
1603/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1604 * it up into this table. Returns the HTTP request rate the key if the key is
1605 * present in the table, otherwise zero, so that comparisons can be easily
1606 * performed. If the inspected parameter is not stored in the table, <not found>
1607 * is returned.
1608 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001609static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001610{
1611 struct stktable *t;
1612 struct stktable_key *key;
1613 struct stksess *ts;
1614 void *ptr;
1615
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001616 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001617
1618 key = smp_to_stkey(smp, t);
1619 if (!key)
1620 return 0;
1621
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001622 ts = stktable_lookup_key(t, key);
1623
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001624 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001625 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001626 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001627
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001628 if (!ts) /* key not present */
1629 return 1;
1630
1631 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001632 if (ptr)
1633 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1634 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001635
Daniel Corbett3e60b112018-05-27 09:47:12 -04001636 stktable_release(t, ts);
1637 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001638}
1639
1640/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1641 * it up into this table. Returns the volume of datareceived from clients in kbytes
1642 * if the key is present in the table, otherwise zero, so that comparisons can
1643 * be easily performed. If the inspected parameter is not stored in the table,
1644 * <not found> is returned.
1645 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001646static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001647{
1648 struct stktable *t;
1649 struct stktable_key *key;
1650 struct stksess *ts;
1651 void *ptr;
1652
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001653 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001654
1655 key = smp_to_stkey(smp, t);
1656 if (!key)
1657 return 0;
1658
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001659 ts = stktable_lookup_key(t, key);
1660
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001661 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001662 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001663 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001664
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001665 if (!ts) /* key not present */
1666 return 1;
1667
1668 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001669 if (ptr)
1670 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001671
Daniel Corbett3e60b112018-05-27 09:47:12 -04001672 stktable_release(t, ts);
1673 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001674}
1675
1676/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1677 * it up into this table. Returns the volume of data sent to clients in kbytes
1678 * if the key is present in the table, otherwise zero, so that comparisons can
1679 * be easily performed. If the inspected parameter is not stored in the table,
1680 * <not found> is returned.
1681 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001682static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001683{
1684 struct stktable *t;
1685 struct stktable_key *key;
1686 struct stksess *ts;
1687 void *ptr;
1688
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001689 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001690
1691 key = smp_to_stkey(smp, t);
1692 if (!key)
1693 return 0;
1694
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001695 ts = stktable_lookup_key(t, key);
1696
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001697 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001698 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001699 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001700
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001701 if (!ts) /* key not present */
1702 return 1;
1703
1704 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001705 if (ptr)
1706 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001707
Daniel Corbett3e60b112018-05-27 09:47:12 -04001708 stktable_release(t, ts);
1709 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001710}
1711
1712/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1713 * it up into this table. Returns the server ID associated with the key if the
1714 * key is present in the table, otherwise zero, so that comparisons can be
1715 * easily performed. If the inspected parameter is not stored in the table,
1716 * <not found> is returned.
1717 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001718static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001719{
1720 struct stktable *t;
1721 struct stktable_key *key;
1722 struct stksess *ts;
1723 void *ptr;
1724
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001725 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001726
1727 key = smp_to_stkey(smp, t);
1728 if (!key)
1729 return 0;
1730
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001731 ts = stktable_lookup_key(t, key);
1732
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001733 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001734 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001735 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001737 if (!ts) /* key not present */
1738 return 1;
1739
1740 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001741 if (ptr)
1742 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001743
Daniel Corbett3e60b112018-05-27 09:47:12 -04001744 stktable_release(t, ts);
1745 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001746}
1747
1748/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1749 * it up into this table. Returns the cumulated number of sessions for the
1750 * key if the key is present in the table, otherwise zero, so that comparisons
1751 * can be easily performed. If the inspected parameter is not stored in the
1752 * table, <not found> is returned.
1753 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001754static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001755{
1756 struct stktable *t;
1757 struct stktable_key *key;
1758 struct stksess *ts;
1759 void *ptr;
1760
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001761 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001762
1763 key = smp_to_stkey(smp, t);
1764 if (!key)
1765 return 0;
1766
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001767 ts = stktable_lookup_key(t, key);
1768
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001769 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001770 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001771 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773 if (!ts) /* key not present */
1774 return 1;
1775
1776 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001777 if (ptr)
1778 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001779
Daniel Corbett3e60b112018-05-27 09:47:12 -04001780 stktable_release(t, ts);
1781 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001782}
1783
1784/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1785 * it up into this table. Returns the session rate the key if the key is
1786 * present in the table, otherwise zero, so that comparisons can be easily
1787 * performed. If the inspected parameter is not stored in the table, <not found>
1788 * is returned.
1789 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001790static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001791{
1792 struct stktable *t;
1793 struct stktable_key *key;
1794 struct stksess *ts;
1795 void *ptr;
1796
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001797 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001798
1799 key = smp_to_stkey(smp, t);
1800 if (!key)
1801 return 0;
1802
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001803 ts = stktable_lookup_key(t, key);
1804
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001805 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001806 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001807 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001808
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809 if (!ts) /* key not present */
1810 return 1;
1811
1812 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001813 if (ptr)
1814 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1815 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001816
Daniel Corbett3e60b112018-05-27 09:47:12 -04001817 stktable_release(t, ts);
1818 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001819}
1820
1821/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1822 * it up into this table. Returns the amount of concurrent connections tracking
1823 * the same key if the key is present in the table, otherwise zero, so that
1824 * comparisons can be easily performed. If the inspected parameter is not
1825 * stored in the table, <not found> is returned.
1826 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001827static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828{
1829 struct stktable *t;
1830 struct stktable_key *key;
1831 struct stksess *ts;
1832
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001833 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001834
1835 key = smp_to_stkey(smp, t);
1836 if (!key)
1837 return 0;
1838
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001839 ts = stktable_lookup_key(t, key);
1840
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001841 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001842 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001843 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001844
Tim Duesterhus65189c12018-06-26 15:57:29 +02001845 if (!ts)
1846 return 1;
1847
1848 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001849
Daniel Corbett3e60b112018-05-27 09:47:12 -04001850 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001851 return 1;
1852}
1853
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001854/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001855static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001856 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001857{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001858 struct stksess *ts;
1859 struct stkctr *stkctr;
1860
1861 /* Extract the stksess, return OK if no stksess available. */
1862 if (s)
1863 stkctr = &s->stkctr[rule->arg.gpc.sc];
1864 else
1865 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001866
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001867 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001868 if (ts) {
1869 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001870
Willy Tarreau79c1e912016-01-25 14:54:45 +01001871 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1872 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001873 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1874 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001875 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001876
1877 if (ptr1)
1878 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001879 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001880
Emeric Brun819fc6f2017-06-13 19:37:32 +02001881 if (ptr2)
1882 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001883
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001884 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001885
1886 /* If data was modified, we need to touch to re-schedule sync */
1887 stktable_touch_local(stkctr->table, ts, 0);
1888 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001889 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001890 return ACT_RET_CONT;
1891}
1892
1893/* This function is a common parser for using variables. It understands
1894 * the formats:
1895 *
1896 * sc-inc-gpc0(<stick-table ID>)
1897 *
1898 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1899 * it returns 1 and the variable <expr> is filled with the pointer to the
1900 * expression to execute.
1901 */
1902static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1903 struct act_rule *rule, char **err)
1904{
1905 const char *cmd_name = args[*arg-1];
1906 char *error;
1907
1908 cmd_name += strlen("sc-inc-gpc0");
1909 if (*cmd_name == '\0') {
1910 /* default stick table id. */
1911 rule->arg.gpc.sc = 0;
1912 } else {
1913 /* parse the stick table id. */
1914 if (*cmd_name != '(') {
1915 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1916 return ACT_RET_PRS_ERR;
1917 }
1918 cmd_name++; /* jump the '(' */
1919 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1920 if (*error != ')') {
1921 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1922 return ACT_RET_PRS_ERR;
1923 }
1924
Christopher Faulet28436e22019-12-18 10:25:46 +01001925 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001926 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001927 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001928 return ACT_RET_PRS_ERR;
1929 }
1930 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001931 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001932 rule->action_ptr = action_inc_gpc0;
1933 return ACT_RET_PRS_OK;
1934}
1935
1936/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001937static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1938 struct session *sess, struct stream *s, int flags)
1939{
1940 struct stksess *ts;
1941 struct stkctr *stkctr;
1942
1943 /* Extract the stksess, return OK if no stksess available. */
1944 if (s)
1945 stkctr = &s->stkctr[rule->arg.gpc.sc];
1946 else
1947 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1948
1949 ts = stkctr_entry(stkctr);
1950 if (ts) {
1951 void *ptr1, *ptr2;
1952
1953 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1954 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1955 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1956 if (ptr1 || ptr2) {
1957 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1958
1959 if (ptr1)
1960 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1961 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1962
1963 if (ptr2)
1964 stktable_data_cast(ptr2, gpc1)++;
1965
1966 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1967
1968 /* If data was modified, we need to touch to re-schedule sync */
1969 stktable_touch_local(stkctr->table, ts, 0);
1970 }
1971 }
1972 return ACT_RET_CONT;
1973}
1974
1975/* This function is a common parser for using variables. It understands
1976 * the formats:
1977 *
1978 * sc-inc-gpc1(<stick-table ID>)
1979 *
1980 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1981 * it returns 1 and the variable <expr> is filled with the pointer to the
1982 * expression to execute.
1983 */
1984static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1985 struct act_rule *rule, char **err)
1986{
1987 const char *cmd_name = args[*arg-1];
1988 char *error;
1989
1990 cmd_name += strlen("sc-inc-gpc1");
1991 if (*cmd_name == '\0') {
1992 /* default stick table id. */
1993 rule->arg.gpc.sc = 0;
1994 } else {
1995 /* parse the stick table id. */
1996 if (*cmd_name != '(') {
1997 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1998 return ACT_RET_PRS_ERR;
1999 }
2000 cmd_name++; /* jump the '(' */
2001 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2002 if (*error != ')') {
2003 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
2004 return ACT_RET_PRS_ERR;
2005 }
2006
Christopher Faulet28436e22019-12-18 10:25:46 +01002007 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002008 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002009 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002010 return ACT_RET_PRS_ERR;
2011 }
2012 }
2013 rule->action = ACT_CUSTOM;
2014 rule->action_ptr = action_inc_gpc1;
2015 return ACT_RET_PRS_OK;
2016}
2017
2018/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002019static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002020 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002021{
2022 void *ptr;
2023 struct stksess *ts;
2024 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002025 unsigned int value = 0;
2026 struct sample *smp;
2027 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002028
2029 /* Extract the stksess, return OK if no stksess available. */
2030 if (s)
2031 stkctr = &s->stkctr[rule->arg.gpt.sc];
2032 else
2033 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002034
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002035 ts = stkctr_entry(stkctr);
2036 if (!ts)
2037 return ACT_RET_CONT;
2038
2039 /* Store the sample in the required sc, and ignore errors. */
2040 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002041 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002042 if (!rule->arg.gpt.expr)
2043 value = (unsigned int)(rule->arg.gpt.value);
2044 else {
2045 switch (rule->from) {
2046 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2047 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2048 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2049 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2050 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2051 default:
2052 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2053 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2054 ha_alert("stick table: internal error while executing setting gpt0.\n");
2055 return ACT_RET_CONT;
2056 }
2057
2058 /* Fetch and cast the expression. */
2059 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2060 if (!smp) {
2061 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2062 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2063 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2064 return ACT_RET_CONT;
2065 }
2066 value = (unsigned int)(smp->data.u.sint);
2067 }
2068
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002069 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002070
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002071 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002072
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002073 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002074
2075 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002076 }
2077
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002078 return ACT_RET_CONT;
2079}
2080
2081/* This function is a common parser for using variables. It understands
2082 * the format:
2083 *
2084 * set-gpt0(<stick-table ID>) <expression>
2085 *
2086 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2087 * it returns 1 and the variable <expr> is filled with the pointer to the
2088 * expression to execute.
2089 */
2090static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2091 struct act_rule *rule, char **err)
2092
2093
2094{
2095 const char *cmd_name = args[*arg-1];
2096 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002097 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002098
2099 cmd_name += strlen("sc-set-gpt0");
2100 if (*cmd_name == '\0') {
2101 /* default stick table id. */
2102 rule->arg.gpt.sc = 0;
2103 } else {
2104 /* parse the stick table id. */
2105 if (*cmd_name != '(') {
2106 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2107 return ACT_RET_PRS_ERR;
2108 }
2109 cmd_name++; /* jump the '(' */
2110 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2111 if (*error != ')') {
2112 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2113 return ACT_RET_PRS_ERR;
2114 }
2115
Christopher Faulet28436e22019-12-18 10:25:46 +01002116 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002117 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002118 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002119 return ACT_RET_PRS_ERR;
2120 }
2121 }
2122
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002123 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002124 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2125 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002126 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002127 px->conf.args.line, err, &px->conf.args, NULL);
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002128 if (!rule->arg.gpt.expr)
2129 return ACT_RET_PRS_ERR;
2130
2131 switch (rule->from) {
2132 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2133 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2134 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2135 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2136 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2137 default:
2138 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2139 return ACT_RET_PRS_ERR;
2140 }
2141 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2142 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2143 sample_src_names(rule->arg.gpt.expr->fetch->use));
2144 free(rule->arg.gpt.expr);
2145 return ACT_RET_PRS_ERR;
2146 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002147 }
2148 (*arg)++;
2149
Thierry FOURNIER42148732015-09-02 17:17:33 +02002150 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002151 rule->action_ptr = action_set_gpt0;
2152
2153 return ACT_RET_PRS_OK;
2154}
2155
Willy Tarreau7d562212016-11-25 16:10:05 +01002156/* set temp integer to the number of used entries in the table pointed to by expr.
2157 * Accepts exactly 1 argument of type table.
2158 */
2159static int
2160smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2161{
2162 smp->flags = SMP_F_VOL_TEST;
2163 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002164 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002165 return 1;
2166}
2167
2168/* set temp integer to the number of free entries in the table pointed to by expr.
2169 * Accepts exactly 1 argument of type table.
2170 */
2171static int
2172smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2173{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002174 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002175
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002176 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002177 smp->flags = SMP_F_VOL_TEST;
2178 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002179 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002180 return 1;
2181}
2182
2183/* Returns a pointer to a stkctr depending on the fetch keyword name.
2184 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2185 * sc[0-9]_* will return a pointer to the respective field in the
2186 * stream <l4>. sc_* requires an UINT argument specifying the stick
2187 * counter number. src_* will fill a locally allocated structure with
2188 * the table and entry corresponding to what is specified with src_*.
2189 * NULL may be returned if the designated stkctr is not tracked. For
2190 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2191 * passed. When present, the currently tracked key is then looked up
2192 * in the specified table instead of the current table. The purpose is
Ilya Shipitsin47d17182020-06-21 21:42:57 +05002193 * to be able to convert multiple values per key (eg: have gpc0 from
Willy Tarreau7d562212016-11-25 16:10:05 +01002194 * multiple tables). <strm> is allowed to be NULL, in which case only
2195 * the session will be consulted.
2196 */
2197struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002198smp_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 +01002199{
Willy Tarreau7d562212016-11-25 16:10:05 +01002200 struct stkctr *stkptr;
2201 struct stksess *stksess;
2202 unsigned int num = kw[2] - '0';
2203 int arg = 0;
2204
2205 if (num == '_' - '0') {
2206 /* sc_* variant, args[0] = ctr# (mandatory) */
2207 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002208 }
2209 else if (num > 9) { /* src_* variant, args[0] = table */
2210 struct stktable_key *key;
2211 struct connection *conn = objt_conn(sess->origin);
2212 struct sample smp;
2213
2214 if (!conn)
2215 return NULL;
2216
Joseph Herlant5662fa42018-11-15 13:43:28 -08002217 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002218 smp.px = NULL;
2219 smp.sess = sess;
2220 smp.strm = strm;
Willy Tarreau478331d2020-08-28 11:31:31 +02002221 if (!smp_fetch_src || !smp_fetch_src(NULL, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002222 return NULL;
2223
2224 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002225 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002226 if (!key)
2227 return NULL;
2228
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002229 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002230 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2231 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002232 }
2233
2234 /* Here, <num> contains the counter number from 0 to 9 for
2235 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2236 * args[arg] is the first optional argument. We first lookup the
2237 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002238 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002239 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002240 if (num >= MAX_SESS_STKCTR)
2241 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002242
2243 if (strm)
2244 stkptr = &strm->stkctr[num];
2245 if (!strm || !stkctr_entry(stkptr)) {
2246 stkptr = &sess->stkctr[num];
2247 if (!stkctr_entry(stkptr))
2248 return NULL;
2249 }
2250
2251 stksess = stkctr_entry(stkptr);
2252 if (!stksess)
2253 return NULL;
2254
2255 if (unlikely(args[arg].type == ARGT_TAB)) {
2256 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002257 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002258 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2259 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002260 }
2261 return stkptr;
2262}
2263
2264/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2265 * the entry if it doesn't exist yet. This is needed for a few fetch
2266 * functions which need to create an entry, such as src_inc_gpc* and
2267 * src_clr_gpc*.
2268 */
2269struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002270smp_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 +01002271{
Willy Tarreau7d562212016-11-25 16:10:05 +01002272 struct stktable_key *key;
2273 struct connection *conn = objt_conn(sess->origin);
2274 struct sample smp;
2275
2276 if (strncmp(kw, "src_", 4) != 0)
2277 return NULL;
2278
2279 if (!conn)
2280 return NULL;
2281
Joseph Herlant5662fa42018-11-15 13:43:28 -08002282 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002283 smp.px = NULL;
2284 smp.sess = sess;
2285 smp.strm = strm;
Willy Tarreau478331d2020-08-28 11:31:31 +02002286 if (!smp_fetch_src || !smp_fetch_src(NULL, &smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002287 return NULL;
2288
2289 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002290 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002291 if (!key)
2292 return NULL;
2293
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002294 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002295 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2296 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002297}
2298
2299/* set return a boolean indicating if the requested stream counter is
2300 * currently being tracked or not.
2301 * Supports being called as "sc[0-9]_tracked" only.
2302 */
2303static int
2304smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2305{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002306 struct stkctr tmpstkctr;
2307 struct stkctr *stkctr;
2308
Willy Tarreau7d562212016-11-25 16:10:05 +01002309 smp->flags = SMP_F_VOL_TEST;
2310 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002311 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2312 smp->data.u.sint = !!stkctr;
2313
2314 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002315 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002316 stktable_release(stkctr->table, stkctr_entry(stkctr));
2317
Willy Tarreau7d562212016-11-25 16:10:05 +01002318 return 1;
2319}
2320
2321/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2322 * frontend counters or from the src.
2323 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2324 * zero is returned if the key is new.
2325 */
2326static int
2327smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2328{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002329 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002330 struct stkctr *stkctr;
2331
Emeric Brun819fc6f2017-06-13 19:37:32 +02002332 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002333 if (!stkctr)
2334 return 0;
2335
2336 smp->flags = SMP_F_VOL_TEST;
2337 smp->data.type = SMP_T_SINT;
2338 smp->data.u.sint = 0;
2339
Emeric Brun819fc6f2017-06-13 19:37:32 +02002340 if (stkctr_entry(stkctr)) {
2341 void *ptr;
2342
2343 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2344 if (!ptr) {
2345 if (stkctr == &tmpstkctr)
2346 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002347 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002348 }
2349
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002350 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002351
Willy Tarreau7d562212016-11-25 16:10:05 +01002352 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002353
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002354 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002355
2356 if (stkctr == &tmpstkctr)
2357 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002358 }
2359 return 1;
2360}
2361
2362/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2363 * frontend counters or from the src.
2364 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2365 * zero is returned if the key is new.
2366 */
2367static int
2368smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2369{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002370 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002371 struct stkctr *stkctr;
2372
Emeric Brun819fc6f2017-06-13 19:37:32 +02002373 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002374 if (!stkctr)
2375 return 0;
2376
2377 smp->flags = SMP_F_VOL_TEST;
2378 smp->data.type = SMP_T_SINT;
2379 smp->data.u.sint = 0;
2380
2381 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002382 void *ptr;
2383
2384 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2385 if (!ptr) {
2386 if (stkctr == &tmpstkctr)
2387 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002388 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002389 }
2390
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002391 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002392
Willy Tarreau7d562212016-11-25 16:10:05 +01002393 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002394
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002395 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002396
2397 if (stkctr == &tmpstkctr)
2398 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002399 }
2400 return 1;
2401}
2402
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002403/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2404 * frontend counters or from the src.
2405 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2406 * zero is returned if the key is new.
2407 */
2408static int
2409smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2410{
2411 struct stkctr tmpstkctr;
2412 struct stkctr *stkctr;
2413
2414 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2415 if (!stkctr)
2416 return 0;
2417
2418 smp->flags = SMP_F_VOL_TEST;
2419 smp->data.type = SMP_T_SINT;
2420 smp->data.u.sint = 0;
2421
2422 if (stkctr_entry(stkctr) != NULL) {
2423 void *ptr;
2424
2425 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2426 if (!ptr) {
2427 if (stkctr == &tmpstkctr)
2428 stktable_release(stkctr->table, stkctr_entry(stkctr));
2429 return 0; /* parameter not stored */
2430 }
2431
2432 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2433
2434 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2435
2436 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2437
2438 if (stkctr == &tmpstkctr)
2439 stktable_release(stkctr->table, stkctr_entry(stkctr));
2440 }
2441 return 1;
2442}
2443
Willy Tarreau7d562212016-11-25 16:10:05 +01002444/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2445 * tracked frontend counters or from the src.
2446 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2447 * Value zero is returned if the key is new.
2448 */
2449static int
2450smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2451{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002452 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002453 struct stkctr *stkctr;
2454
Emeric Brun819fc6f2017-06-13 19:37:32 +02002455 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002456 if (!stkctr)
2457 return 0;
2458
2459 smp->flags = SMP_F_VOL_TEST;
2460 smp->data.type = SMP_T_SINT;
2461 smp->data.u.sint = 0;
2462 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002463 void *ptr;
2464
2465 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2466 if (!ptr) {
2467 if (stkctr == &tmpstkctr)
2468 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002469 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002470 }
2471
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002472 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002473
Willy Tarreau7d562212016-11-25 16:10:05 +01002474 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2475 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002476
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002477 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002478
2479 if (stkctr == &tmpstkctr)
2480 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002481 }
2482 return 1;
2483}
2484
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002485/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2486 * tracked frontend counters or from the src.
2487 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2488 * Value zero is returned if the key is new.
2489 */
2490static int
2491smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2492{
2493 struct stkctr tmpstkctr;
2494 struct stkctr *stkctr;
2495
2496 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2497 if (!stkctr)
2498 return 0;
2499
2500 smp->flags = SMP_F_VOL_TEST;
2501 smp->data.type = SMP_T_SINT;
2502 smp->data.u.sint = 0;
2503 if (stkctr_entry(stkctr) != NULL) {
2504 void *ptr;
2505
2506 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2507 if (!ptr) {
2508 if (stkctr == &tmpstkctr)
2509 stktable_release(stkctr->table, stkctr_entry(stkctr));
2510 return 0; /* parameter not stored */
2511 }
2512
2513 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2514
2515 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2516 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2517
2518 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2519
2520 if (stkctr == &tmpstkctr)
2521 stktable_release(stkctr->table, stkctr_entry(stkctr));
2522 }
2523 return 1;
2524}
2525
Willy Tarreau7d562212016-11-25 16:10:05 +01002526/* Increment the General Purpose Counter 0 value from the stream's tracked
2527 * frontend counters and return it into temp integer.
2528 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2529 */
2530static int
2531smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2532{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002533 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002534 struct stkctr *stkctr;
2535
Emeric Brun819fc6f2017-06-13 19:37:32 +02002536 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002537 if (!stkctr)
2538 return 0;
2539
2540 smp->flags = SMP_F_VOL_TEST;
2541 smp->data.type = SMP_T_SINT;
2542 smp->data.u.sint = 0;
2543
Emeric Brun819fc6f2017-06-13 19:37:32 +02002544 if (!stkctr_entry(stkctr))
2545 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002546
2547 if (stkctr && stkctr_entry(stkctr)) {
2548 void *ptr1,*ptr2;
2549
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550
Willy Tarreau7d562212016-11-25 16:10:05 +01002551 /* First, update gpc0_rate if it's tracked. Second, update its
2552 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2553 */
2554 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002555 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002556 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002557 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002558
Emeric Brun819fc6f2017-06-13 19:37:32 +02002559 if (ptr1) {
2560 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2561 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2562 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2563 }
2564
2565 if (ptr2)
2566 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2567
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002568 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002569
2570 /* If data was modified, we need to touch to re-schedule sync */
2571 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2572 }
2573 else if (stkctr == &tmpstkctr)
2574 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002575 }
2576 return 1;
2577}
2578
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002579/* Increment the General Purpose Counter 1 value from the stream's tracked
2580 * frontend counters and return it into temp integer.
2581 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2582 */
2583static int
2584smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2585{
2586 struct stkctr tmpstkctr;
2587 struct stkctr *stkctr;
2588
2589 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2590 if (!stkctr)
2591 return 0;
2592
2593 smp->flags = SMP_F_VOL_TEST;
2594 smp->data.type = SMP_T_SINT;
2595 smp->data.u.sint = 0;
2596
2597 if (!stkctr_entry(stkctr))
2598 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2599
2600 if (stkctr && stkctr_entry(stkctr)) {
2601 void *ptr1,*ptr2;
2602
2603
2604 /* First, update gpc1_rate if it's tracked. Second, update its
2605 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2606 */
2607 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2608 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2609 if (ptr1 || ptr2) {
2610 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2611
2612 if (ptr1) {
2613 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2614 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2615 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2616 }
2617
2618 if (ptr2)
2619 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2620
2621 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2622
2623 /* If data was modified, we need to touch to re-schedule sync */
2624 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2625 }
2626 else if (stkctr == &tmpstkctr)
2627 stktable_release(stkctr->table, stkctr_entry(stkctr));
2628 }
2629 return 1;
2630}
2631
Willy Tarreau7d562212016-11-25 16:10:05 +01002632/* Clear the General Purpose Counter 0 value from the stream's tracked
2633 * frontend counters and return its previous value into temp integer.
2634 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2635 */
2636static int
2637smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2638{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002639 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002640 struct stkctr *stkctr;
2641
Emeric Brun819fc6f2017-06-13 19:37:32 +02002642 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002643 if (!stkctr)
2644 return 0;
2645
2646 smp->flags = SMP_F_VOL_TEST;
2647 smp->data.type = SMP_T_SINT;
2648 smp->data.u.sint = 0;
2649
Emeric Brun819fc6f2017-06-13 19:37:32 +02002650 if (!stkctr_entry(stkctr))
2651 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002652
Emeric Brun819fc6f2017-06-13 19:37:32 +02002653 if (stkctr && stkctr_entry(stkctr)) {
2654 void *ptr;
2655
2656 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2657 if (!ptr) {
2658 if (stkctr == &tmpstkctr)
2659 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002660 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002661 }
2662
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002663 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002664
Willy Tarreau7d562212016-11-25 16:10:05 +01002665 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2666 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002667
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002668 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002669
Willy Tarreau7d562212016-11-25 16:10:05 +01002670 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002671 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002672 }
2673 return 1;
2674}
2675
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002676/* Clear the General Purpose Counter 1 value from the stream's tracked
2677 * frontend counters and return its previous value into temp integer.
2678 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2679 */
2680static int
2681smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2682{
2683 struct stkctr tmpstkctr;
2684 struct stkctr *stkctr;
2685
2686 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2687 if (!stkctr)
2688 return 0;
2689
2690 smp->flags = SMP_F_VOL_TEST;
2691 smp->data.type = SMP_T_SINT;
2692 smp->data.u.sint = 0;
2693
2694 if (!stkctr_entry(stkctr))
2695 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2696
2697 if (stkctr && stkctr_entry(stkctr)) {
2698 void *ptr;
2699
2700 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2701 if (!ptr) {
2702 if (stkctr == &tmpstkctr)
2703 stktable_release(stkctr->table, stkctr_entry(stkctr));
2704 return 0; /* parameter not stored */
2705 }
2706
2707 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2708
2709 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2710 stktable_data_cast(ptr, gpc1) = 0;
2711
2712 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2713
2714 /* If data was modified, we need to touch to re-schedule sync */
2715 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2716 }
2717 return 1;
2718}
2719
Willy Tarreau7d562212016-11-25 16:10:05 +01002720/* set <smp> to the cumulated number of connections from the stream's tracked
2721 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2722 * "src_conn_cnt" only.
2723 */
2724static int
2725smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2726{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002727 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002728 struct stkctr *stkctr;
2729
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002731 if (!stkctr)
2732 return 0;
2733
2734 smp->flags = SMP_F_VOL_TEST;
2735 smp->data.type = SMP_T_SINT;
2736 smp->data.u.sint = 0;
2737 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002738 void *ptr;
2739
2740 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2741 if (!ptr) {
2742 if (stkctr == &tmpstkctr)
2743 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002744 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002745 }
2746
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002747 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002748
Willy Tarreau7d562212016-11-25 16:10:05 +01002749 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002750
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002751 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002752
2753 if (stkctr == &tmpstkctr)
2754 stktable_release(stkctr->table, stkctr_entry(stkctr));
2755
2756
Willy Tarreau7d562212016-11-25 16:10:05 +01002757 }
2758 return 1;
2759}
2760
2761/* set <smp> to the connection rate from the stream's tracked frontend
2762 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2763 * only.
2764 */
2765static int
2766smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2767{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002768 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002769 struct stkctr *stkctr;
2770
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002772 if (!stkctr)
2773 return 0;
2774
2775 smp->flags = SMP_F_VOL_TEST;
2776 smp->data.type = SMP_T_SINT;
2777 smp->data.u.sint = 0;
2778 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002779 void *ptr;
2780
2781 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2782 if (!ptr) {
2783 if (stkctr == &tmpstkctr)
2784 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002785 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002786 }
2787
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002788 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002789
Willy Tarreau7d562212016-11-25 16:10:05 +01002790 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2791 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002792
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002793 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002794
2795 if (stkctr == &tmpstkctr)
2796 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002797 }
2798 return 1;
2799}
2800
2801/* set temp integer to the number of connections from the stream's source address
2802 * in the table pointed to by expr, after updating it.
2803 * Accepts exactly 1 argument of type table.
2804 */
2805static int
2806smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2807{
2808 struct connection *conn = objt_conn(smp->sess->origin);
2809 struct stksess *ts;
2810 struct stktable_key *key;
2811 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002812 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002813
2814 if (!conn)
2815 return 0;
2816
Joseph Herlant5662fa42018-11-15 13:43:28 -08002817 /* Fetch source address in a sample. */
Willy Tarreau478331d2020-08-28 11:31:31 +02002818 if (!smp_fetch_src || !smp_fetch_src(NULL, smp, NULL, NULL))
Willy Tarreau7d562212016-11-25 16:10:05 +01002819 return 0;
2820
2821 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002822 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002823 if (!key)
2824 return 0;
2825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002826 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002827
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002828 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002829 /* entry does not exist and could not be created */
2830 return 0;
2831
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002832 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002833 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002834 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002836
2837 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002838
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002839 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002840
Willy Tarreau7d562212016-11-25 16:10:05 +01002841 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002842
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002843 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002844
Willy Tarreau7d562212016-11-25 16:10:05 +01002845 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002846
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002847 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002848
2849 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002850 return 1;
2851}
2852
2853/* set <smp> to the number of concurrent connections from the stream's tracked
2854 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2855 * "src_conn_cur" only.
2856 */
2857static int
2858smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2859{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002860 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002861 struct stkctr *stkctr;
2862
Emeric Brun819fc6f2017-06-13 19:37:32 +02002863 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002864 if (!stkctr)
2865 return 0;
2866
2867 smp->flags = SMP_F_VOL_TEST;
2868 smp->data.type = SMP_T_SINT;
2869 smp->data.u.sint = 0;
2870 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002871 void *ptr;
2872
2873 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2874 if (!ptr) {
2875 if (stkctr == &tmpstkctr)
2876 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002877 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002878 }
2879
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002880 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002881
Willy Tarreau7d562212016-11-25 16:10:05 +01002882 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002883
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002884 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002885
2886 if (stkctr == &tmpstkctr)
2887 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002888 }
2889 return 1;
2890}
2891
2892/* set <smp> to the cumulated number of streams from the stream's tracked
2893 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2894 * "src_sess_cnt" only.
2895 */
2896static int
2897smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2898{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002899 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002900 struct stkctr *stkctr;
2901
Emeric Brun819fc6f2017-06-13 19:37:32 +02002902 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002903 if (!stkctr)
2904 return 0;
2905
2906 smp->flags = SMP_F_VOL_TEST;
2907 smp->data.type = SMP_T_SINT;
2908 smp->data.u.sint = 0;
2909 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002910 void *ptr;
2911
2912 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2913 if (!ptr) {
2914 if (stkctr == &tmpstkctr)
2915 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002916 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002917 }
2918
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002919 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002920
Willy Tarreau7d562212016-11-25 16:10:05 +01002921 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002922
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002923 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924
2925 if (stkctr == &tmpstkctr)
2926 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002927 }
2928 return 1;
2929}
2930
2931/* set <smp> to the stream rate from the stream's tracked frontend counters.
2932 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2933 */
2934static int
2935smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2936{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002937 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002938 struct stkctr *stkctr;
2939
Emeric Brun819fc6f2017-06-13 19:37:32 +02002940 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002941 if (!stkctr)
2942 return 0;
2943
2944 smp->flags = SMP_F_VOL_TEST;
2945 smp->data.type = SMP_T_SINT;
2946 smp->data.u.sint = 0;
2947 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002948 void *ptr;
2949
2950 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2951 if (!ptr) {
2952 if (stkctr == &tmpstkctr)
2953 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002954 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955 }
2956
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002957 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002958
Willy Tarreau7d562212016-11-25 16:10:05 +01002959 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2960 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002961
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002962 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002963
2964 if (stkctr == &tmpstkctr)
2965 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002966 }
2967 return 1;
2968}
2969
2970/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2971 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2972 * "src_http_req_cnt" only.
2973 */
2974static int
2975smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2976{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002977 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002978 struct stkctr *stkctr;
2979
Emeric Brun819fc6f2017-06-13 19:37:32 +02002980 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002981 if (!stkctr)
2982 return 0;
2983
2984 smp->flags = SMP_F_VOL_TEST;
2985 smp->data.type = SMP_T_SINT;
2986 smp->data.u.sint = 0;
2987 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002988 void *ptr;
2989
2990 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2991 if (!ptr) {
2992 if (stkctr == &tmpstkctr)
2993 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002994 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995 }
2996
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002997 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003000
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003001 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003002
3003 if (stkctr == &tmpstkctr)
3004 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003005 }
3006 return 1;
3007}
3008
3009/* set <smp> to the HTTP request rate from the stream's tracked frontend
3010 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3011 * "src_http_req_rate" only.
3012 */
3013static int
3014smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3015{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003016 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003017 struct stkctr *stkctr;
3018
Emeric Brun819fc6f2017-06-13 19:37:32 +02003019 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003020 if (!stkctr)
3021 return 0;
3022
3023 smp->flags = SMP_F_VOL_TEST;
3024 smp->data.type = SMP_T_SINT;
3025 smp->data.u.sint = 0;
3026 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003027 void *ptr;
3028
3029 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3030 if (!ptr) {
3031 if (stkctr == &tmpstkctr)
3032 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003033 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003034 }
3035
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003036 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003037
Willy Tarreau7d562212016-11-25 16:10:05 +01003038 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3039 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003040
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003041 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003042
3043 if (stkctr == &tmpstkctr)
3044 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003045 }
3046 return 1;
3047}
3048
3049/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3050 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3051 * "src_http_err_cnt" only.
3052 */
3053static int
3054smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3055{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003056 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003057 struct stkctr *stkctr;
3058
Emeric Brun819fc6f2017-06-13 19:37:32 +02003059 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003060 if (!stkctr)
3061 return 0;
3062
3063 smp->flags = SMP_F_VOL_TEST;
3064 smp->data.type = SMP_T_SINT;
3065 smp->data.u.sint = 0;
3066 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003067 void *ptr;
3068
3069 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3070 if (!ptr) {
3071 if (stkctr == &tmpstkctr)
3072 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003073 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003074 }
3075
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003076 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003077
Willy Tarreau7d562212016-11-25 16:10:05 +01003078 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003079
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003080 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003081
3082 if (stkctr == &tmpstkctr)
3083 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003084 }
3085 return 1;
3086}
3087
3088/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3089 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3090 * "src_http_err_rate" only.
3091 */
3092static int
3093smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3094{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003095 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003096 struct stkctr *stkctr;
3097
Emeric Brun819fc6f2017-06-13 19:37:32 +02003098 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003099 if (!stkctr)
3100 return 0;
3101
3102 smp->flags = SMP_F_VOL_TEST;
3103 smp->data.type = SMP_T_SINT;
3104 smp->data.u.sint = 0;
3105 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003106 void *ptr;
3107
3108 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3109 if (!ptr) {
3110 if (stkctr == &tmpstkctr)
3111 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003112 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003113 }
3114
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003115 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003116
Willy Tarreau7d562212016-11-25 16:10:05 +01003117 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3118 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003119
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003120 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003121
3122 if (stkctr == &tmpstkctr)
3123 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003124 }
3125 return 1;
3126}
3127
3128/* set <smp> to the number of kbytes received from clients, as found in the
3129 * stream's tracked frontend counters. Supports being called as
3130 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3131 */
3132static int
3133smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3134{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003135 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003136 struct stkctr *stkctr;
3137
Emeric Brun819fc6f2017-06-13 19:37:32 +02003138 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003139 if (!stkctr)
3140 return 0;
3141
3142 smp->flags = SMP_F_VOL_TEST;
3143 smp->data.type = SMP_T_SINT;
3144 smp->data.u.sint = 0;
3145 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146 void *ptr;
3147
3148 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3149 if (!ptr) {
3150 if (stkctr == &tmpstkctr)
3151 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003152 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003153 }
3154
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003155 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003156
Willy Tarreau7d562212016-11-25 16:10:05 +01003157 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003158
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003159 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003160
3161 if (stkctr == &tmpstkctr)
3162 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003163 }
3164 return 1;
3165}
3166
3167/* set <smp> to the data rate received from clients in bytes/s, as found
3168 * in the stream's tracked frontend counters. Supports being called as
3169 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3170 */
3171static int
3172smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3173{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003174 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003175 struct stkctr *stkctr;
3176
Emeric Brun819fc6f2017-06-13 19:37:32 +02003177 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003178 if (!stkctr)
3179 return 0;
3180
3181 smp->flags = SMP_F_VOL_TEST;
3182 smp->data.type = SMP_T_SINT;
3183 smp->data.u.sint = 0;
3184 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003185 void *ptr;
3186
3187 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3188 if (!ptr) {
3189 if (stkctr == &tmpstkctr)
3190 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003191 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003192 }
3193
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003194 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003195
Willy Tarreau7d562212016-11-25 16:10:05 +01003196 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3197 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003198
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003199 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003200
3201 if (stkctr == &tmpstkctr)
3202 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003203 }
3204 return 1;
3205}
3206
3207/* set <smp> to the number of kbytes sent to clients, as found in the
3208 * stream's tracked frontend counters. Supports being called as
3209 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3210 */
3211static int
3212smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3213{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003214 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003215 struct stkctr *stkctr;
3216
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003218 if (!stkctr)
3219 return 0;
3220
3221 smp->flags = SMP_F_VOL_TEST;
3222 smp->data.type = SMP_T_SINT;
3223 smp->data.u.sint = 0;
3224 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225 void *ptr;
3226
3227 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3228 if (!ptr) {
3229 if (stkctr == &tmpstkctr)
3230 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003231 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003232 }
3233
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003234 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003235
Willy Tarreau7d562212016-11-25 16:10:05 +01003236 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003237
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003238 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003239
3240 if (stkctr == &tmpstkctr)
3241 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003242 }
3243 return 1;
3244}
3245
3246/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3247 * stream's tracked frontend counters. Supports being called as
3248 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3249 */
3250static int
3251smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3252{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003253 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003254 struct stkctr *stkctr;
3255
Emeric Brun819fc6f2017-06-13 19:37:32 +02003256 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003257 if (!stkctr)
3258 return 0;
3259
3260 smp->flags = SMP_F_VOL_TEST;
3261 smp->data.type = SMP_T_SINT;
3262 smp->data.u.sint = 0;
3263 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003264 void *ptr;
3265
3266 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3267 if (!ptr) {
3268 if (stkctr == &tmpstkctr)
3269 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003270 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003271 }
3272
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003273 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003274
Willy Tarreau7d562212016-11-25 16:10:05 +01003275 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3276 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003277
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003278 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003279
3280 if (stkctr == &tmpstkctr)
3281 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003282 }
3283 return 1;
3284}
3285
3286/* set <smp> to the number of active trackers on the SC entry in the stream's
3287 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3288 */
3289static int
3290smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3291{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003292 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003293 struct stkctr *stkctr;
3294
Emeric Brun819fc6f2017-06-13 19:37:32 +02003295 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003296 if (!stkctr)
3297 return 0;
3298
3299 smp->flags = SMP_F_VOL_TEST;
3300 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003301 if (stkctr == &tmpstkctr) {
3302 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3303 stktable_release(stkctr->table, stkctr_entry(stkctr));
3304 }
3305 else {
3306 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3307 }
3308
Willy Tarreau7d562212016-11-25 16:10:05 +01003309 return 1;
3310}
3311
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003312
3313/* The functions below are used to manipulate table contents from the CLI.
3314 * There are 3 main actions, "clear", "set" and "show". The code is shared
3315 * between all actions, and the action is encoded in the void *private in
3316 * the appctx as well as in the keyword registration, among one of the
3317 * following values.
3318 */
3319
3320enum {
3321 STK_CLI_ACT_CLR,
3322 STK_CLI_ACT_SET,
3323 STK_CLI_ACT_SHOW,
3324};
3325
3326/* Dump the status of a table to a stream interface's
3327 * read buffer. It returns 0 if the output buffer is full
3328 * and needs to be called again, otherwise non-zero.
3329 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003330static int table_dump_head_to_buffer(struct buffer *msg,
3331 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003332 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003333{
3334 struct stream *s = si_strm(si);
3335
3336 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003337 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003338
3339 /* any other information should be dumped here */
3340
William Lallemand07a62f72017-05-24 00:57:40 +02003341 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003342 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3343
Willy Tarreau06d80a92017-10-19 14:32:15 +02003344 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003345 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003346 return 0;
3347 }
3348
3349 return 1;
3350}
3351
3352/* Dump a table entry to a stream interface's
3353 * read buffer. It returns 0 if the output buffer is full
3354 * and needs to be called again, otherwise non-zero.
3355 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003356static int table_dump_entry_to_buffer(struct buffer *msg,
3357 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003358 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003359{
3360 int dt;
3361
3362 chunk_appendf(msg, "%p:", entry);
3363
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003364 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003365 char addr[INET_ADDRSTRLEN];
3366 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3367 chunk_appendf(msg, " key=%s", addr);
3368 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003369 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003370 char addr[INET6_ADDRSTRLEN];
3371 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3372 chunk_appendf(msg, " key=%s", addr);
3373 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003374 else if (t->type == SMP_T_SINT) {
Willy Tarreau6cde5d82020-02-25 09:41:22 +01003375 chunk_appendf(msg, " key=%u", read_u32(entry->key.key));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003376 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003377 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003378 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003379 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003380 }
3381 else {
3382 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003383 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003384 }
3385
3386 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3387
3388 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3389 void *ptr;
3390
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003391 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003392 continue;
3393 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003394 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003395 else
3396 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3397
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003398 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003399 switch (stktable_data_types[dt].std_type) {
3400 case STD_T_SINT:
3401 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3402 break;
3403 case STD_T_UINT:
3404 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3405 break;
3406 case STD_T_ULL:
3407 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3408 break;
3409 case STD_T_FRQP:
3410 chunk_appendf(msg, "%d",
3411 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003412 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003413 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003414 case STD_T_DICT: {
3415 struct dict_entry *de;
3416 de = stktable_data_cast(ptr, std_t_dict);
3417 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3418 break;
3419 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003420 }
3421 }
3422 chunk_appendf(msg, "\n");
3423
Willy Tarreau06d80a92017-10-19 14:32:15 +02003424 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003425 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003426 return 0;
3427 }
3428
3429 return 1;
3430}
3431
3432
3433/* Processes a single table entry matching a specific key passed in argument.
3434 * returns 0 if wants to be called again, 1 if has ended processing.
3435 */
3436static int table_process_entry_per_key(struct appctx *appctx, char **args)
3437{
3438 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003439 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003440 struct stksess *ts;
3441 uint32_t uint32_key;
3442 unsigned char ip6_key[sizeof(struct in6_addr)];
3443 long long value;
3444 int data_type;
3445 int cur_arg;
3446 void *ptr;
3447 struct freq_ctr_period *frqp;
3448
Willy Tarreau9d008692019-08-09 11:21:01 +02003449 if (!*args[4])
3450 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003451
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003452 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003453 case SMP_T_IPV4:
3454 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003455 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003456 break;
3457 case SMP_T_IPV6:
3458 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003459 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003460 break;
3461 case SMP_T_SINT:
3462 {
3463 char *endptr;
3464 unsigned long val;
3465 errno = 0;
3466 val = strtoul(args[4], &endptr, 10);
3467 if ((errno == ERANGE && val == ULONG_MAX) ||
3468 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003469 val > 0xffffffff)
3470 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003471 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003472 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003473 break;
3474 }
3475 break;
3476 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003477 static_table_key.key = args[4];
3478 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003479 break;
3480 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003481 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003482 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003483 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 +01003484 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003485 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 +01003486 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003487 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 +01003488 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003489 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003490 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003491 }
3492
3493 /* check permissions */
3494 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3495 return 1;
3496
Willy Tarreaua24bc782016-12-14 15:50:35 +01003497 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003498 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003499 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003500 if (!ts)
3501 return 1;
3502 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003503 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3504 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003505 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003506 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003507 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003508 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003509 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003510 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003511 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003512 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003513 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003514 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003515 break;
3516
3517 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003518 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003519 if (!ts)
3520 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003521
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003522 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003523 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003524 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003525 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003526 break;
3527
3528 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003529 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003530 if (!ts) {
3531 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003532 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003533 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003534 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003535 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3536 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003537 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003538 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003539 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003540 return 1;
3541 }
3542
3543 data_type = stktable_get_data_type(args[cur_arg] + 5);
3544 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003545 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003546 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003547 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003548 return 1;
3549 }
3550
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003551 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003552 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003553 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003554 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003555 return 1;
3556 }
3557
3558 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003559 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003560 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003561 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003562 return 1;
3563 }
3564
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003565 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003566
3567 switch (stktable_data_types[data_type].std_type) {
3568 case STD_T_SINT:
3569 stktable_data_cast(ptr, std_t_sint) = value;
3570 break;
3571 case STD_T_UINT:
3572 stktable_data_cast(ptr, std_t_uint) = value;
3573 break;
3574 case STD_T_ULL:
3575 stktable_data_cast(ptr, std_t_ull) = value;
3576 break;
3577 case STD_T_FRQP:
3578 /* We set both the current and previous values. That way
3579 * the reported frequency is stable during all the period
3580 * then slowly fades out. This allows external tools to
3581 * push measures without having to update them too often.
3582 */
3583 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003584 /* First bit is reserved for the freq_ctr_period lock
3585 Note: here we're still protected by the stksess lock
3586 so we don't need to update the update the freq_ctr_period
3587 using its internal lock */
3588 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003589 frqp->prev_ctr = 0;
3590 frqp->curr_ctr = value;
3591 break;
3592 }
3593 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003594 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003595 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003596 break;
3597
3598 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003599 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003600 }
3601 return 1;
3602}
3603
3604/* Prepares the appctx fields with the data-based filters from the command line.
3605 * Returns 0 if the dump can proceed, 1 if has ended processing.
3606 */
3607static int table_prepare_data_request(struct appctx *appctx, char **args)
3608{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003609 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003610 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003611
Willy Tarreau9d008692019-08-09 11:21:01 +02003612 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3613 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003614
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003615 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3616 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3617 break;
3618 /* condition on stored data value */
3619 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3620 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003621 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003622
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003623 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003624 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 +01003625
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003626 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003627 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003628 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 +01003629
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003630 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 +01003631 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3632 }
3633
3634 if (*args[3+3*i]) {
3635 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 +01003636 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003637
3638 /* OK we're done, all the fields are set */
3639 return 0;
3640}
3641
3642/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003643static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003644{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003645 int i;
3646
3647 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3648 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003649 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003650 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003651 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003652
3653 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003654 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003655 if (!appctx->ctx.table.target)
3656 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003657 }
3658 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003659 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003660 goto err_args;
3661 return 0;
3662 }
3663
3664 if (strcmp(args[3], "key") == 0)
3665 return table_process_entry_per_key(appctx, args);
3666 else if (strncmp(args[3], "data.", 5) == 0)
3667 return table_prepare_data_request(appctx, args);
3668 else if (*args[3])
3669 goto err_args;
3670
3671 return 0;
3672
3673err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003674 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003675 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003676 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 +01003677 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003678 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 +01003679 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003680 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003681 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003682 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003683 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003684}
3685
3686/* This function is used to deal with table operations (dump or clear depending
3687 * on the action stored in appctx->private). It returns 0 if the output buffer is
3688 * full and it needs to be called again, otherwise non-zero.
3689 */
3690static int cli_io_handler_table(struct appctx *appctx)
3691{
3692 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003693 struct stream *s = si_strm(si);
3694 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003695 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003696 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003697
3698 /*
3699 * We have 3 possible states in appctx->st2 :
3700 * - STAT_ST_INIT : the first call
3701 * - STAT_ST_INFO : the proxy pointer points to the next table to
3702 * dump, the entry pointer is NULL ;
3703 * - STAT_ST_LIST : the proxy pointer points to the current table
3704 * and the entry pointer points to the next entry to be dumped,
3705 * and the refcount on the next entry is held ;
3706 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3707 * data though.
3708 */
3709
3710 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3711 /* in case of abort, remove any refcount we might have set on an entry */
3712 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003713 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003714 }
3715 return 1;
3716 }
3717
3718 chunk_reset(&trash);
3719
3720 while (appctx->st2 != STAT_ST_FIN) {
3721 switch (appctx->st2) {
3722 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003723 appctx->ctx.table.t = appctx->ctx.table.target;
3724 if (!appctx->ctx.table.t)
3725 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003726
3727 appctx->ctx.table.entry = NULL;
3728 appctx->st2 = STAT_ST_INFO;
3729 break;
3730
3731 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003732 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003733 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003734 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003735 appctx->st2 = STAT_ST_END;
3736 break;
3737 }
3738
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003739 if (appctx->ctx.table.t->size) {
3740 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003741 return 0;
3742
3743 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003744 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003745 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003746 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3747 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003748 if (eb) {
3749 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3750 appctx->ctx.table.entry->ref_cnt++;
3751 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003752 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003753 break;
3754 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003755 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003756 }
3757 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003758 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003759 break;
3760
3761 case STAT_ST_LIST:
3762 skip_entry = 0;
3763
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003764 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003765
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003766 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003767 /* we're filtering on some data contents */
3768 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003769 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003770 signed char op;
3771 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003772
Emeric Brun819fc6f2017-06-13 19:37:32 +02003773
Willy Tarreau2b64a352020-01-22 17:09:47 +01003774 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003775 if (appctx->ctx.table.data_type[i] == -1)
3776 break;
3777 dt = appctx->ctx.table.data_type[i];
3778 ptr = stktable_data_ptr(appctx->ctx.table.t,
3779 appctx->ctx.table.entry,
3780 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003781
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003782 data = 0;
3783 switch (stktable_data_types[dt].std_type) {
3784 case STD_T_SINT:
3785 data = stktable_data_cast(ptr, std_t_sint);
3786 break;
3787 case STD_T_UINT:
3788 data = stktable_data_cast(ptr, std_t_uint);
3789 break;
3790 case STD_T_ULL:
3791 data = stktable_data_cast(ptr, std_t_ull);
3792 break;
3793 case STD_T_FRQP:
3794 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3795 appctx->ctx.table.t->data_arg[dt].u);
3796 break;
3797 }
3798
3799 op = appctx->ctx.table.data_op[i];
3800 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003801
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003802 /* skip the entry if the data does not match the test and the value */
3803 if ((data < value &&
3804 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3805 (data == value &&
3806 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3807 (data > value &&
3808 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3809 skip_entry = 1;
3810 break;
3811 }
3812 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003813 }
3814
3815 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003816 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003817 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003818 return 0;
3819 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003820
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003821 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003822
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003823 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003824 appctx->ctx.table.entry->ref_cnt--;
3825
3826 eb = ebmb_next(&appctx->ctx.table.entry->key);
3827 if (eb) {
3828 struct stksess *old = appctx->ctx.table.entry;
3829 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3830 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003831 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003832 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003833 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003834 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003835 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003836 break;
3837 }
3838
3839
3840 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003841 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003842 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003843 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003844
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003845 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003846
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003847 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003848 appctx->st2 = STAT_ST_INFO;
3849 break;
3850
3851 case STAT_ST_END:
3852 appctx->st2 = STAT_ST_FIN;
3853 break;
3854 }
3855 }
3856 return 1;
3857}
3858
3859static void cli_release_show_table(struct appctx *appctx)
3860{
3861 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003862 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003863 }
3864}
3865
Willy Tarreau478331d2020-08-28 11:31:31 +02003866static void stkt_late_init(void)
3867{
3868 struct sample_fetch *f;
3869
3870 f = find_sample_fetch("src", strlen("src"));
3871 if (f)
3872 smp_fetch_src = f->process;
3873}
3874
3875INITCALL0(STG_INIT, stkt_late_init);
3876
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003877/* register cli keywords */
3878static struct cli_kw_list cli_kws = {{ },{
3879 { { "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 },
3880 { { "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 },
3881 { { "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 },
3882 {{},}
3883}};
3884
Willy Tarreau0108d902018-11-25 19:14:37 +01003885INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003886
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003887static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003888 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003889 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003890 { "sc-set-gpt0", parse_set_gpt0, 1 },
3891 { /* END */ }
3892}};
3893
Willy Tarreau0108d902018-11-25 19:14:37 +01003894INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3895
Willy Tarreau620408f2016-10-21 16:37:51 +02003896static struct action_kw_list tcp_sess_kws = { { }, {
3897 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003898 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003899 { "sc-set-gpt0", parse_set_gpt0, 1 },
3900 { /* END */ }
3901}};
3902
Willy Tarreau0108d902018-11-25 19:14:37 +01003903INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3904
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003905static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003906 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003907 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003908 { "sc-set-gpt0", parse_set_gpt0, 1 },
3909 { /* END */ }
3910}};
3911
Willy Tarreau0108d902018-11-25 19:14:37 +01003912INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3913
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003914static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003915 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003916 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003917 { "sc-set-gpt0", parse_set_gpt0, 1 },
3918 { /* END */ }
3919}};
3920
Willy Tarreau0108d902018-11-25 19:14:37 +01003921INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3922
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003923static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003924 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003925 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003926 { "sc-set-gpt0", parse_set_gpt0, 1 },
3927 { /* END */ }
3928}};
3929
Willy Tarreau0108d902018-11-25 19:14:37 +01003930INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3931
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003932static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003933 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003934 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003935 { "sc-set-gpt0", parse_set_gpt0, 1 },
3936 { /* END */ }
3937}};
3938
Willy Tarreau0108d902018-11-25 19:14:37 +01003939INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3940
Willy Tarreau7d562212016-11-25 16:10:05 +01003941///* Note: must not be declared <const> as its list will be overwritten.
3942// * Please take care of keeping this list alphabetically sorted.
3943// */
3944//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3945// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3946// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3947// { /* END */ },
3948//}};
3949/* Note: must not be declared <const> as its list will be overwritten.
3950 * Please take care of keeping this list alphabetically sorted.
3951 */
3952static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3953 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3954 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3955 { "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 +01003956 { "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 +01003957 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3958 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3959 { "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 +01003960 { "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 +01003961 { "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 +01003962 { "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 +01003963 { "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 +01003964 { "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 +01003965 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3966 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3967 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3968 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3969 { "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 +01003970 { "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 +01003971 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3972 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3973 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3974 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3975 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3976 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3977 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3978 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3979 { "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 +01003980 { "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 +01003981 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3982 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "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 +01003984 { "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 +01003985 { "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 +01003986 { "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 +01003987 { "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 +01003988 { "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 +01003989 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3990 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3991 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3992 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3993 { "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 +01003994 { "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 +01003995 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3996 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3997 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3998 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3999 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4000 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4001 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4002 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4003 { "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 +01004004 { "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 +01004005 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4007 { "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 +01004008 { "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 +01004009 { "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 +01004010 { "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 +01004011 { "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 +01004012 { "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 +01004013 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4014 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4015 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4016 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4017 { "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 +01004018 { "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 +01004019 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4020 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4021 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4022 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4023 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4024 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4025 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4026 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4027 { "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 +01004028 { "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 +01004029 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4030 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4031 { "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 +01004032 { "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 +01004033 { "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 +01004034 { "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 +01004035 { "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 +01004036 { "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 +01004037 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4038 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4039 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4040 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4041 { "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 +01004042 { "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 +01004043 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4044 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4045 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4046 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4047 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4048 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4049 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4050 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4051 { "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 +01004052 { "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 +01004053 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4054 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4055 { "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 +01004056 { "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 +01004057 { "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 +01004058 { "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 +01004059 { "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 +01004060 { "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 +01004061 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4062 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4063 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4064 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4065 { "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 +01004066 { "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 +01004067 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4068 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4069 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4070 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4071 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4072 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4073 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4074 { /* END */ },
4075}};
4076
Willy Tarreau0108d902018-11-25 19:14:37 +01004077INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004078
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004079/* Note: must not be declared <const> as its list will be overwritten */
4080static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004081 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4082 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4083 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4084 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4085 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4086 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4087 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4088 { "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 +01004089 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004090 { "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 +01004091 { "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 +02004092 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4093 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4094 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4095 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4096 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4097 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4098 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4099 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4100 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4101 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004102 { /* END */ },
4103}};
4104
Willy Tarreau0108d902018-11-25 19:14:37 +01004105INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);