blob: 1e7d4f3a865d50806bef1d5bf5f4fef54a372979 [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
17#include <common/config.h>
Frédéric Lécailled456aa42019-03-08 14:47:00 +010018#include <common/cfgparse.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010019#include <common/initcall.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010020#include <common/memory.h>
21#include <common/mini-clist.h>
22#include <common/standard.h>
23#include <common/time.h>
24
25#include <ebmbtree.h>
26#include <ebsttree.h>
27
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010028#include <types/cli.h>
Willy Tarreau39713102016-11-25 15:49:32 +010029#include <types/global.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010030#include <types/stats.h>
31
Willy Tarreaud9f316a2014-07-10 14:03:38 +020032#include <proto/arg.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010033#include <proto/cli.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020034#include <proto/http_rules.h>
Andjelko Iharosc3680ec2017-07-20 16:49:14 +020035#include <proto/log.h>
Christopher Fauletfc9cfe42019-07-16 14:54:53 +020036#include <proto/http_ana.h>
Willy Tarreau7d562212016-11-25 16:10:05 +010037#include <proto/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010038#include <proto/proxy.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020039#include <proto/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020040#include <proto/stream.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010041#include <proto/stream_interface.h>
Willy Tarreau68129b92010-06-06 16:06:52 +020042#include <proto/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010043#include <proto/task.h>
Emeric Brun32da3c42010-09-23 18:39:19 +020044#include <proto/peers.h>
Willy Tarreau39713102016-11-25 15:49:32 +010045#include <proto/tcp_rules.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010046
Willy Tarreau12785782012-04-27 21:37:17 +020047/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020048static THREAD_LOCAL struct stktable_key static_table_key;
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>
168 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100169 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200170int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100171{
172 struct stksess *ts;
173 struct eb32_node *eb;
174 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200175 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100176
177 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
178
179 while (batched < to_batch) {
180
181 if (unlikely(!eb)) {
182 /* we might have reached the end of the tree, typically because
183 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200184 * half. Let's loop back to the beginning of the tree now if we
185 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200187 if (looped)
188 break;
189 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100190 eb = eb32_first(&t->exps);
191 if (likely(!eb))
192 break;
193 }
194
195 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200196 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100197 eb = eb32_next(eb);
198
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200199 /* don't delete an entry which is currently referenced */
200 if (ts->ref_cnt)
201 continue;
202
Willy Tarreau86257dc2010-06-06 12:57:10 +0200203 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100204
Willy Tarreau86257dc2010-06-06 12:57:10 +0200205 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100206 if (!tick_isset(ts->expire))
207 continue;
208
Willy Tarreau86257dc2010-06-06 12:57:10 +0200209 ts->exp.key = ts->expire;
210 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100211
Willy Tarreau86257dc2010-06-06 12:57:10 +0200212 if (!eb || eb->key > ts->exp.key)
213 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100214
215 continue;
216 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217
Willy Tarreauaea940e2010-06-06 11:56:36 +0200218 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200219 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200220 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200221 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100222 batched++;
223 }
224
225 return batched;
226}
227
228/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200229 * Trash oldest <to_batch> sticky sessions from table <t>
230 * Returns number of trashed sticky sessions.
231 * This function locks the table
232 */
233int stktable_trash_oldest(struct stktable *t, int to_batch)
234{
235 int ret;
236
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100237 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200238 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100239 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200240
241 return ret;
242}
243/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200244 * Allocate and initialise a new sticky session.
245 * The new sticky session is returned or NULL in case of lack of memory.
246 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200247 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
248 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100249 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200250struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100251{
252 struct stksess *ts;
253
254 if (unlikely(t->current == t->size)) {
255 if ( t->nopurge )
256 return NULL;
257
Emeric Brun819fc6f2017-06-13 19:37:32 +0200258 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100259 return NULL;
260 }
261
Willy Tarreaubafbe012017-11-24 17:34:44 +0100262 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100263 if (ts) {
264 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100265 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200266 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200267 if (key)
268 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100269 }
270
271 return ts;
272}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200273/*
274 * Allocate and initialise a new sticky session.
275 * The new sticky session is returned or NULL in case of lack of memory.
276 * Sticky sessions should only be allocated this way, and must be freed using
277 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
278 * is not NULL, it is assigned to the new session.
279 * This function locks the table
280 */
281struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
282{
283 struct stksess *ts;
284
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100285 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200286 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100287 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200288
289 return ts;
290}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100291
292/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200293 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200294 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100295 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200296struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100297{
298 struct ebmb_node *eb;
299
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200300 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200301 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 +0100302 else
303 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
304
305 if (unlikely(!eb)) {
306 /* no session found */
307 return NULL;
308 }
309
Willy Tarreau86257dc2010-06-06 12:57:10 +0200310 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100311}
312
Emeric Brun819fc6f2017-06-13 19:37:32 +0200313/*
314 * Looks in table <t> for a sticky session matching key <key>.
315 * Returns pointer on requested sticky session or NULL if none was found.
316 * The refcount of the found entry is increased and this function
317 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200318 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200319struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200320{
321 struct stksess *ts;
322
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100323 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200324 ts = __stktable_lookup_key(t, key);
325 if (ts)
326 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100327 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200328
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200329 return ts;
330}
331
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200332/*
333 * Looks in table <t> for a sticky session with same key as <ts>.
334 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100335 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200336struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100337{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100338 struct ebmb_node *eb;
339
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200340 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200341 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100342 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200343 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100344
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200345 if (unlikely(!eb))
346 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100347
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200348 return ebmb_entry(eb, struct stksess, key);
349}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100350
Emeric Brun819fc6f2017-06-13 19:37:32 +0200351/*
352 * Looks in table <t> for a sticky session with same key as <ts>.
353 * Returns pointer on requested sticky session or NULL if none was found.
354 * The refcount of the found entry is increased and this function
355 * is protected using the table lock
356 */
357struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
358{
359 struct stksess *lts;
360
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100361 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200362 lts = __stktable_lookup(t, ts);
363 if (lts)
364 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100365 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200366
367 return lts;
368}
369
Willy Tarreaucb183642010-06-06 17:58:34 +0200370/* Update the expiration timer for <ts> but do not touch its expiration node.
371 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372 * The node will be also inserted into the update tree if needed, at a position
373 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200374 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200375void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200376{
Emeric Brun85e77c72010-09-23 18:16:52 +0200377 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200378 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200379 if (t->expire) {
380 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
381 task_queue(t->exp_task);
382 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200383
Emeric Brun819fc6f2017-06-13 19:37:32 +0200384 /* If sync is enabled */
385 if (t->sync_task) {
386 if (local) {
387 /* If this entry is not in the tree
388 or not scheduled for at least one peer */
389 if (!ts->upd.node.leaf_p
390 || (int)(t->commitupdate - ts->upd.key) >= 0
391 || (int)(ts->upd.key - t->localupdate) >= 0) {
392 ts->upd.key = ++t->update;
393 t->localupdate = t->update;
394 eb32_delete(&ts->upd);
395 eb = eb32_insert(&t->updates, &ts->upd);
396 if (eb != &ts->upd) {
397 eb32_delete(eb);
398 eb32_insert(&t->updates, &ts->upd);
399 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200400 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200401 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200402 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200403 else {
404 /* If this entry is not in the tree */
405 if (!ts->upd.node.leaf_p) {
406 ts->upd.key= (++t->update)+(2147483648U);
407 eb = eb32_insert(&t->updates, &ts->upd);
408 if (eb != &ts->upd) {
409 eb32_delete(eb);
410 eb32_insert(&t->updates, &ts->upd);
411 }
412 }
413 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200414 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200415}
416
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200417/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200418 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200419 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200420 * The node will be also inserted into the update tree if needed, at a position
421 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200422 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200423void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
424{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100425 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200426 __stktable_touch_with_exp(t, ts, 0, ts->expire);
427 if (decrefcnt)
428 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100429 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200430}
431
432/* Update the expiration timer for <ts> but do not touch its expiration node.
433 * The table's expiration timer is updated using the date of expiration coming from
434 * <t> stick-table configuration.
435 * The node will be also inserted into the update tree if needed, at a position
436 * considering the update was made locally
437 */
438void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200439{
440 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
441
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100442 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200443 __stktable_touch_with_exp(t, ts, 1, expire);
444 if (decrefcnt)
445 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100446 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200447}
Willy Tarreau43e90352018-06-27 06:25:57 +0200448/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
449static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450{
Willy Tarreau43e90352018-06-27 06:25:57 +0200451 if (!ts)
452 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100453 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200454 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100455 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200456}
457
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200458/* Insert new sticky session <ts> in the table. It is assumed that it does not
459 * yet exist (the caller must check this). The table's timeout is updated if it
460 * is set. <ts> is returned.
461 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200462void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200463{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100464
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200465 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200466 ts->exp.key = ts->expire;
467 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200468 if (t->expire) {
469 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
470 task_queue(t->exp_task);
471 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200472}
473
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200474/* Returns a valid or initialized stksess for the specified stktable_key in the
475 * specified table, or NULL if the key was NULL, or if no entry was found nor
476 * could be created. The entry's expiration is updated.
477 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200478struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200479{
480 struct stksess *ts;
481
482 if (!key)
483 return NULL;
484
Emeric Brun819fc6f2017-06-13 19:37:32 +0200485 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200486 if (ts == NULL) {
487 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200488 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200489 if (!ts)
490 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200491 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200492 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200493 return ts;
494}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200495/* Returns a valid or initialized stksess for the specified stktable_key in the
496 * specified table, or NULL if the key was NULL, or if no entry was found nor
497 * could be created. The entry's expiration is updated.
498 * This function locks the table, and the refcount of the entry is increased.
499 */
500struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
501{
502 struct stksess *ts;
503
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100504 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200505 ts = __stktable_get_entry(table, key);
506 if (ts)
507 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100508 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200509
510 return ts;
511}
512
513/* Lookup for an entry with the same key and store the submitted
514 * stksess if not found.
515 */
516struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
517{
518 struct stksess *ts;
519
520 ts = __stktable_lookup(table, nts);
521 if (ts == NULL) {
522 ts = nts;
523 __stktable_store(table, ts);
524 }
525 return ts;
526}
527
528/* Lookup for an entry with the same key and store the submitted
529 * stksess if not found.
530 * This function locks the table, and the refcount of the entry is increased.
531 */
532struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
533{
534 struct stksess *ts;
535
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100536 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200537 ts = __stktable_set_entry(table, nts);
538 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100539 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200540
Emeric Brun819fc6f2017-06-13 19:37:32 +0200541 return ts;
542}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100543/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200544 * Trash expired sticky sessions from table <t>. The next expiration date is
545 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100546 */
547static int stktable_trash_expired(struct stktable *t)
548{
549 struct stksess *ts;
550 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200551 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100552
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100553 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100554 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
555
556 while (1) {
557 if (unlikely(!eb)) {
558 /* we might have reached the end of the tree, typically because
559 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200560 * half. Let's loop back to the beginning of the tree now if we
561 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100562 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200563 if (looped)
564 break;
565 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100566 eb = eb32_first(&t->exps);
567 if (likely(!eb))
568 break;
569 }
570
571 if (likely(tick_is_lt(now_ms, eb->key))) {
572 /* timer not expired yet, revisit it later */
573 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100574 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100575 }
576
577 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200578 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 eb = eb32_next(eb);
580
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200581 /* don't delete an entry which is currently referenced */
582 if (ts->ref_cnt)
583 continue;
584
Willy Tarreau86257dc2010-06-06 12:57:10 +0200585 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100586
587 if (!tick_is_expired(ts->expire, now_ms)) {
588 if (!tick_isset(ts->expire))
589 continue;
590
Willy Tarreau86257dc2010-06-06 12:57:10 +0200591 ts->exp.key = ts->expire;
592 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100593
Willy Tarreau86257dc2010-06-06 12:57:10 +0200594 if (!eb || eb->key > ts->exp.key)
595 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100596 continue;
597 }
598
599 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200600 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200601 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200602 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100603 }
604
605 /* We have found no task to expire in any tree */
606 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100607out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100608 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 return t->exp_next;
610}
611
612/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200613 * Task processing function to trash expired sticky sessions. A pointer to the
614 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100615 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200616static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100617{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200618 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100619
620 task->expire = stktable_trash_expired(t);
621 return task;
622}
623
Willy Tarreauaea940e2010-06-06 11:56:36 +0200624/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100625int stktable_init(struct stktable *t)
626{
627 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200628 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100629 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100630 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100631 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100633 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 +0100634
635 t->exp_next = TICK_ETERNITY;
636 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200637 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200638 if (!t->exp_task)
639 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100640 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100641 t->exp_task->context = (void *)t;
642 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200643 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200644 peers_register_table(t->peers.p, t);
645 }
646
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647 return t->pool != NULL;
648 }
649 return 1;
650}
651
652/*
653 * Configuration keywords of known table types
654 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200655struct stktable_type stktable_types[SMP_TYPES] = {
656 [SMP_T_SINT] = { "integer", 0, 4 },
657 [SMP_T_IPV4] = { "ip", 0, 4 },
658 [SMP_T_IPV6] = { "ipv6", 0, 16 },
659 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
660 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
661};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100662
663/*
664 * Parse table type configuration.
665 * Returns 0 on successful parsing, else 1.
666 * <myidx> is set at next configuration <args> index.
667 */
668int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
669{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200670 for (*type = 0; *type < SMP_TYPES; (*type)++) {
671 if (!stktable_types[*type].kw)
672 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100673 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
674 continue;
675
676 *key_size = stktable_types[*type].default_size;
677 (*myidx)++;
678
Willy Tarreauaea940e2010-06-06 11:56:36 +0200679 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100680 if (strcmp("len", args[*myidx]) == 0) {
681 (*myidx)++;
682 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200683 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100684 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200685 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200686 /* null terminated string needs +1 for '\0'. */
687 (*key_size)++;
688 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100689 (*myidx)++;
690 }
691 }
692 return 0;
693 }
694 return 1;
695}
696
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100697/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100698 * Parse a line with <linenum> as number in <file> configuration file to configure
699 * the stick-table with <t> as address and <id> as ID.
700 * <peers> provides the "peers" section pointer only if this function is called
701 * from a "peers" section.
702 * <nid> is the stick-table name which is sent over the network. It must be equal
703 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
704 * "peers" section name followed by a '/' character if parsed from a "peers" section.
705 * This is the responsability of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100706 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
707 */
708int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100709 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100710{
711 int err_code = 0;
712 int idx = 1;
713 unsigned int val;
714
715 if (!id || !*id) {
716 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
717 err_code |= ERR_ALERT | ERR_ABORT;
718 goto out;
719 }
720
721 /* Store the "peers" section if this function is called from a "peers" section. */
722 if (peers) {
723 t->peers.p = peers;
724 idx++;
725 }
726
727 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100728 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100729 t->type = (unsigned int)-1;
730 t->conf.file = file;
731 t->conf.line = linenum;
732
733 while (*args[idx]) {
734 const char *err;
735
736 if (strcmp(args[idx], "size") == 0) {
737 idx++;
738 if (!*(args[idx])) {
739 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
740 file, linenum, args[0], args[idx-1]);
741 err_code |= ERR_ALERT | ERR_FATAL;
742 goto out;
743 }
744 if ((err = parse_size_err(args[idx], &t->size))) {
745 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
746 file, linenum, args[0], *err, args[idx-1]);
747 err_code |= ERR_ALERT | ERR_FATAL;
748 goto out;
749 }
750 idx++;
751 }
752 /* This argument does not exit in "peers" section. */
753 else if (!peers && strcmp(args[idx], "peers") == 0) {
754 idx++;
755 if (!*(args[idx])) {
756 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
757 file, linenum, args[0], args[idx-1]);
758 err_code |= ERR_ALERT | ERR_FATAL;
759 goto out;
760 }
761 t->peers.name = strdup(args[idx++]);
762 }
763 else if (strcmp(args[idx], "expire") == 0) {
764 idx++;
765 if (!*(args[idx])) {
766 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
767 file, linenum, args[0], args[idx-1]);
768 err_code |= ERR_ALERT | ERR_FATAL;
769 goto out;
770 }
771 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200772 if (err == PARSE_TIME_OVER) {
773 ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
774 file, linenum, args[0], args[idx], args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100775 err_code |= ERR_ALERT | ERR_FATAL;
776 goto out;
777 }
Willy Tarreau9faebe32019-06-07 19:00:37 +0200778 else if (err == PARSE_TIME_UNDER) {
779 ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
780 file, linenum, args[0], args[idx], args[idx-1]);
781 err_code |= ERR_ALERT | ERR_FATAL;
782 goto out;
783 }
784 else if (err) {
785 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
786 file, linenum, args[0], *err, args[idx-1]);
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100787 err_code |= ERR_ALERT | ERR_FATAL;
788 goto out;
789 }
790 t->expire = val;
791 idx++;
792 }
793 else if (strcmp(args[idx], "nopurge") == 0) {
794 t->nopurge = 1;
795 idx++;
796 }
797 else if (strcmp(args[idx], "type") == 0) {
798 idx++;
799 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
800 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
801 file, linenum, args[0], args[idx]);
802 err_code |= ERR_ALERT | ERR_FATAL;
803 goto out;
804 }
805 /* idx already points to next arg */
806 }
807 else if (strcmp(args[idx], "store") == 0) {
808 int type, err;
809 char *cw, *nw, *sa;
810
811 idx++;
812 nw = args[idx];
813 while (*nw) {
814 /* the "store" keyword supports a comma-separated list */
815 cw = nw;
816 sa = NULL; /* store arg */
817 while (*nw && *nw != ',') {
818 if (*nw == '(') {
819 *nw = 0;
820 sa = ++nw;
821 while (*nw != ')') {
822 if (!*nw) {
823 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
824 file, linenum, args[0], cw);
825 err_code |= ERR_ALERT | ERR_FATAL;
826 goto out;
827 }
828 nw++;
829 }
830 *nw = '\0';
831 }
832 nw++;
833 }
834 if (*nw)
835 *nw++ = '\0';
836 type = stktable_get_data_type(cw);
837 if (type < 0) {
838 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
839 file, linenum, args[0], cw);
840 err_code |= ERR_ALERT | ERR_FATAL;
841 goto out;
842 }
843
844 err = stktable_alloc_data_type(t, type, sa);
845 switch (err) {
846 case PE_NONE: break;
847 case PE_EXIST:
848 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
849 file, linenum, args[0], cw);
850 err_code |= ERR_WARN;
851 break;
852
853 case PE_ARG_MISSING:
854 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
855 file, linenum, args[0], cw);
856 err_code |= ERR_ALERT | ERR_FATAL;
857 goto out;
858
859 case PE_ARG_NOT_USED:
860 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
861 file, linenum, args[0], cw);
862 err_code |= ERR_ALERT | ERR_FATAL;
863 goto out;
864
865 default:
866 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
867 file, linenum, args[0], cw);
868 err_code |= ERR_ALERT | ERR_FATAL;
869 goto out;
870 }
871 }
872 idx++;
873 }
874 else {
875 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
876 file, linenum, args[0], args[idx]);
877 err_code |= ERR_ALERT | ERR_FATAL;
878 goto out;
879 }
880 }
881
882 if (!t->size) {
883 ha_alert("parsing [%s:%d] : %s: missing size.\n",
884 file, linenum, args[0]);
885 err_code |= ERR_ALERT | ERR_FATAL;
886 goto out;
887 }
888
889 if (t->type == (unsigned int)-1) {
890 ha_alert("parsing [%s:%d] : %s: missing type.\n",
891 file, linenum, args[0]);
892 err_code |= ERR_ALERT | ERR_FATAL;
893 goto out;
894 }
895
896 out:
897 return err_code;
898}
899
Willy Tarreau8fed9032014-07-03 17:02:46 +0200900/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200901 * Note that the sample *is* modified and that the returned key may point
902 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200903 * Returns NULL if the sample could not be converted (eg: no matching type),
904 * otherwise a pointer to the static stktable_key filled with what is needed
905 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200906 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200907struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200908{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200909 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200910 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200911 return NULL;
912
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200913 /* Fill static_table_key. */
914 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200915
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200916 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200917 static_table_key.key = &smp->data.u.ipv4;
918 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200919 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200920
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200921 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200922 static_table_key.key = &smp->data.u.ipv6;
923 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200924 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200925
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200926 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200927 /* The stick table require a 32bit unsigned int, "sint" is a
928 * signed 64 it, so we can convert it inplace.
929 */
Willy Tarreau28c63c12019-10-23 06:21:05 +0200930 smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200931 static_table_key.key = &smp->data.u.sint;
932 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200933 break;
934
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200935 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200936 if (!smp_make_safe(smp))
937 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200938 static_table_key.key = smp->data.u.str.area;
939 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200940 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200941
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200942 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200943 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200944 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200945 if (!smp_make_rw(smp))
946 return NULL;
947
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200948 if (smp->data.u.str.size < t->key_size)
949 if (!smp_dup(smp))
950 return NULL;
951 if (smp->data.u.str.size < t->key_size)
952 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200953 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
954 t->key_size - smp->data.u.str.data);
955 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200956 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200957 static_table_key.key = smp->data.u.str.area;
958 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200959 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200960
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200961 default: /* impossible case. */
962 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200963 }
964
Christopher Fauletca20d022017-08-29 15:30:31 +0200965 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200966}
967
968/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200969 * Process a fetch + format conversion as defined by the sample expression <expr>
970 * on request or response considering the <opt> parameter. Returns either NULL if
971 * no key could be extracted, or a pointer to the converted result stored in
972 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
973 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200974 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
975 * without SMP_OPT_FINAL). The output will be usable like this :
976 *
977 * return MAY_CHANGE FINAL Meaning for the sample
978 * NULL 0 * Not present and will never be (eg: header)
979 * NULL 1 0 Not present or unstable, could change (eg: req_len)
980 * NULL 1 1 Not present, will not change anymore
981 * smp 0 * Present and will not change (eg: header)
982 * smp 1 0 not possible
983 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200984 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200985struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200986 unsigned int opt, struct sample_expr *expr, struct sample *smp)
987{
988 if (smp)
989 memset(smp, 0, sizeof(*smp));
990
Willy Tarreau192252e2015-04-04 01:47:55 +0200991 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200992 if (!smp)
993 return NULL;
994
995 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
996 return NULL; /* we can only use stable samples */
997
998 return smp_to_stkey(smp, t);
999}
1000
1001/*
Willy Tarreau12785782012-04-27 21:37:17 +02001002 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001003 * type <table_type>, otherwise zero. Used in configuration check.
1004 */
Willy Tarreau12785782012-04-27 21:37:17 +02001005int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001006{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001007 int out_type;
1008
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001009 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001010 return 0;
1011
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001012 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001013
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001014 /* Convert sample. */
1015 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001016 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001017
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001018 return 1;
1019}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001020
Willy Tarreauedee1d62014-07-15 16:44:27 +02001021/* Extra data types processing : after the last one, some room may remain
1022 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1023 * at run time.
1024 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001025struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001026 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001027 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001028 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001029 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001030 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1031 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1032 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1033 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1034 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1035 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1036 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1037 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1038 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1039 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1040 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1041 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1042 [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 +01001043 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1044 [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 +02001045 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001046};
1047
Willy Tarreauedee1d62014-07-15 16:44:27 +02001048/* Registers stick-table extra data type with index <idx>, name <name>, type
1049 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1050 * index is automatically allocated. The allocated index is returned, or -1 if
1051 * no free index was found or <name> was already registered. The <name> is used
1052 * directly as a pointer, so if it's not stable, the caller must allocate it.
1053 */
1054int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1055{
1056 if (idx < 0) {
1057 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1058 if (!stktable_data_types[idx].name)
1059 break;
1060
1061 if (strcmp(stktable_data_types[idx].name, name) == 0)
1062 return -1;
1063 }
1064 }
1065
1066 if (idx >= STKTABLE_DATA_TYPES)
1067 return -1;
1068
1069 if (stktable_data_types[idx].name != NULL)
1070 return -1;
1071
1072 stktable_data_types[idx].name = name;
1073 stktable_data_types[idx].std_type = std_type;
1074 stktable_data_types[idx].arg_type = arg_type;
1075 return idx;
1076}
1077
Willy Tarreau08d5f982010-06-06 13:34:54 +02001078/*
1079 * Returns the data type number for the stktable_data_type whose name is <name>,
1080 * or <0 if not found.
1081 */
1082int stktable_get_data_type(char *name)
1083{
1084 int type;
1085
1086 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001087 if (!stktable_data_types[type].name)
1088 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001089 if (strcmp(name, stktable_data_types[type].name) == 0)
1090 return type;
1091 }
1092 return -1;
1093}
1094
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001095/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1096 * it up into this table. Returns true if found, false otherwise. The input
1097 * type is STR so that input samples are converted to string (since all types
1098 * can be converted to strings), then the function casts the string again into
1099 * the table's type. This is a double conversion, but in the future we might
1100 * support automatic input types to perform the cast on the fly.
1101 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001102static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001103{
1104 struct stktable *t;
1105 struct stktable_key *key;
1106 struct stksess *ts;
1107
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001108 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001109
1110 key = smp_to_stkey(smp, t);
1111 if (!key)
1112 return 0;
1113
1114 ts = stktable_lookup_key(t, key);
1115
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001116 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001117 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001118 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001119 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001120 return 1;
1121}
1122
1123/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1124 * it up into this table. Returns the data rate received from clients in bytes/s
1125 * if the key is present in the table, otherwise zero, so that comparisons can
1126 * be easily performed. If the inspected parameter is not stored in the table,
1127 * <not found> is returned.
1128 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001129static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001130{
1131 struct stktable *t;
1132 struct stktable_key *key;
1133 struct stksess *ts;
1134 void *ptr;
1135
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001136 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001137
1138 key = smp_to_stkey(smp, t);
1139 if (!key)
1140 return 0;
1141
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001142 ts = stktable_lookup_key(t, key);
1143
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001144 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001145 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001146 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001147
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001148 if (!ts) /* key not present */
1149 return 1;
1150
1151 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001152 if (ptr)
1153 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1154 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001155
Daniel Corbett3e60b112018-05-27 09:47:12 -04001156 stktable_release(t, ts);
1157 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001158}
1159
1160/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1161 * it up into this table. Returns the cumulated number of connections for the key
1162 * if the key is present in the table, otherwise zero, so that comparisons can
1163 * be easily performed. If the inspected parameter is not stored in the table,
1164 * <not found> is returned.
1165 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001166static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001167{
1168 struct stktable *t;
1169 struct stktable_key *key;
1170 struct stksess *ts;
1171 void *ptr;
1172
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001173 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001174
1175 key = smp_to_stkey(smp, t);
1176 if (!key)
1177 return 0;
1178
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001179 ts = stktable_lookup_key(t, key);
1180
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001181 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001182 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001183 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001184
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001185 if (!ts) /* key not present */
1186 return 1;
1187
1188 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001189 if (ptr)
1190 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001191
Daniel Corbett3e60b112018-05-27 09:47:12 -04001192 stktable_release(t, ts);
1193 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001194}
1195
1196/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1197 * it up into this table. Returns the number of concurrent connections for the
1198 * key if the key is present in the table, otherwise zero, so that comparisons
1199 * can be easily performed. If the inspected parameter is not stored in the
1200 * table, <not found> is returned.
1201 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001202static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001203{
1204 struct stktable *t;
1205 struct stktable_key *key;
1206 struct stksess *ts;
1207 void *ptr;
1208
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001209 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001210
1211 key = smp_to_stkey(smp, t);
1212 if (!key)
1213 return 0;
1214
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001215 ts = stktable_lookup_key(t, key);
1216
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001217 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001218 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001219 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001220
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001221 if (!ts) /* key not present */
1222 return 1;
1223
1224 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001225 if (ptr)
1226 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001227
Daniel Corbett3e60b112018-05-27 09:47:12 -04001228 stktable_release(t, ts);
1229 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001230}
1231
1232/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1233 * it up into this table. Returns the rate of incoming connections from the key
1234 * if the key is present in the table, otherwise zero, so that comparisons can
1235 * be easily performed. If the inspected parameter is not stored in the table,
1236 * <not found> is returned.
1237 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001238static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001239{
1240 struct stktable *t;
1241 struct stktable_key *key;
1242 struct stksess *ts;
1243 void *ptr;
1244
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001245 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001246
1247 key = smp_to_stkey(smp, t);
1248 if (!key)
1249 return 0;
1250
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001251 ts = stktable_lookup_key(t, key);
1252
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001253 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001254 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001255 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001256
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001257 if (!ts) /* key not present */
1258 return 1;
1259
1260 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001261 if (ptr)
1262 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1263 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001264
Daniel Corbett3e60b112018-05-27 09:47:12 -04001265 stktable_release(t, ts);
1266 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001267}
1268
1269/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1270 * it up into this table. Returns the data rate sent to clients in bytes/s
1271 * if the key is present in the table, otherwise zero, so that comparisons can
1272 * be easily performed. If the inspected parameter is not stored in the table,
1273 * <not found> is returned.
1274 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001275static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001276{
1277 struct stktable *t;
1278 struct stktable_key *key;
1279 struct stksess *ts;
1280 void *ptr;
1281
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001282 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001283
1284 key = smp_to_stkey(smp, t);
1285 if (!key)
1286 return 0;
1287
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001288 ts = stktable_lookup_key(t, key);
1289
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001290 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001291 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001292 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001293
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001294 if (!ts) /* key not present */
1295 return 1;
1296
1297 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001298 if (ptr)
1299 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1300 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301
Daniel Corbett3e60b112018-05-27 09:47:12 -04001302 stktable_release(t, ts);
1303 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001304}
1305
1306/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001307 * it up into this table. Returns the value of the GPT0 tag for the key
1308 * if the key is present in the table, otherwise false, so that comparisons can
1309 * be easily performed. If the inspected parameter is not stored in the table,
1310 * <not found> is returned.
1311 */
1312static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1313{
1314 struct stktable *t;
1315 struct stktable_key *key;
1316 struct stksess *ts;
1317 void *ptr;
1318
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001319 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001320
1321 key = smp_to_stkey(smp, t);
1322 if (!key)
1323 return 0;
1324
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001325 ts = stktable_lookup_key(t, key);
1326
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001327 smp->flags = SMP_F_VOL_TEST;
1328 smp->data.type = SMP_T_SINT;
1329 smp->data.u.sint = 0;
1330
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001331 if (!ts) /* key not present */
1332 return 1;
1333
1334 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001335 if (ptr)
1336 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001337
Daniel Corbett3e60b112018-05-27 09:47:12 -04001338 stktable_release(t, ts);
1339 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001340}
1341
1342/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343 * it up into this table. Returns the value of the GPC0 counter for the key
1344 * if the key is present in the table, otherwise zero, so that comparisons can
1345 * be easily performed. If the inspected parameter is not stored in the table,
1346 * <not found> is returned.
1347 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001348static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001349{
1350 struct stktable *t;
1351 struct stktable_key *key;
1352 struct stksess *ts;
1353 void *ptr;
1354
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001355 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356
1357 key = smp_to_stkey(smp, t);
1358 if (!key)
1359 return 0;
1360
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001361 ts = stktable_lookup_key(t, key);
1362
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001364 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001365 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001367 if (!ts) /* key not present */
1368 return 1;
1369
1370 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001371 if (ptr)
1372 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001373
Daniel Corbett3e60b112018-05-27 09:47:12 -04001374 stktable_release(t, ts);
1375 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001376}
1377
1378/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1379 * it up into this table. Returns the event rate of the GPC0 counter for the key
1380 * if the key is present in the table, otherwise zero, so that comparisons can
1381 * be easily performed. If the inspected parameter is not stored in the table,
1382 * <not found> is returned.
1383 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001384static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001385{
1386 struct stktable *t;
1387 struct stktable_key *key;
1388 struct stksess *ts;
1389 void *ptr;
1390
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001391 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001392
1393 key = smp_to_stkey(smp, t);
1394 if (!key)
1395 return 0;
1396
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001397 ts = stktable_lookup_key(t, key);
1398
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001399 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001400 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001401 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403 if (!ts) /* key not present */
1404 return 1;
1405
1406 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001407 if (ptr)
1408 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1409 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001410
Daniel Corbett3e60b112018-05-27 09:47:12 -04001411 stktable_release(t, ts);
1412 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001413}
1414
1415/* 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 +01001416 * it up into this table. Returns the value of the GPC1 counter for the key
1417 * if the key is present in the table, otherwise zero, so that comparisons can
1418 * be easily performed. If the inspected parameter is not stored in the table,
1419 * <not found> is returned.
1420 */
1421static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1422{
1423 struct stktable *t;
1424 struct stktable_key *key;
1425 struct stksess *ts;
1426 void *ptr;
1427
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001428 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001429
1430 key = smp_to_stkey(smp, t);
1431 if (!key)
1432 return 0;
1433
1434 ts = stktable_lookup_key(t, key);
1435
1436 smp->flags = SMP_F_VOL_TEST;
1437 smp->data.type = SMP_T_SINT;
1438 smp->data.u.sint = 0;
1439
1440 if (!ts) /* key not present */
1441 return 1;
1442
1443 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001444 if (ptr)
1445 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001446
Daniel Corbett3e60b112018-05-27 09:47:12 -04001447 stktable_release(t, ts);
1448 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001449}
1450
1451/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1452 * it up into this table. Returns the event rate of the GPC1 counter for the key
1453 * if the key is present in the table, otherwise zero, so that comparisons can
1454 * be easily performed. If the inspected parameter is not stored in the table,
1455 * <not found> is returned.
1456 */
1457static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1458{
1459 struct stktable *t;
1460 struct stktable_key *key;
1461 struct stksess *ts;
1462 void *ptr;
1463
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001464 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001465
1466 key = smp_to_stkey(smp, t);
1467 if (!key)
1468 return 0;
1469
1470 ts = stktable_lookup_key(t, key);
1471
1472 smp->flags = SMP_F_VOL_TEST;
1473 smp->data.type = SMP_T_SINT;
1474 smp->data.u.sint = 0;
1475
1476 if (!ts) /* key not present */
1477 return 1;
1478
1479 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001480 if (ptr)
1481 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1482 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001483
Daniel Corbett3e60b112018-05-27 09:47:12 -04001484 stktable_release(t, ts);
1485 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001486}
1487
1488/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001489 * it up into this table. Returns the cumulated number of HTTP request errors
1490 * for the key if the key is present in the table, otherwise zero, so that
1491 * comparisons can be easily performed. If the inspected parameter is not stored
1492 * in the table, <not found> is returned.
1493 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001494static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001495{
1496 struct stktable *t;
1497 struct stktable_key *key;
1498 struct stksess *ts;
1499 void *ptr;
1500
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001501 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001502
1503 key = smp_to_stkey(smp, t);
1504 if (!key)
1505 return 0;
1506
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001507 ts = stktable_lookup_key(t, key);
1508
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001509 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001510 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001511 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001512
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001513 if (!ts) /* key not present */
1514 return 1;
1515
1516 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001517 if (ptr)
1518 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001519
Daniel Corbett3e60b112018-05-27 09:47:12 -04001520 stktable_release(t, ts);
1521 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001522}
1523
1524/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1525 * it up into this table. Returns the HTTP request error rate the key
1526 * if the key is present in the table, otherwise zero, so that comparisons can
1527 * be easily performed. If the inspected parameter is not stored in the table,
1528 * <not found> is returned.
1529 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001530static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001531{
1532 struct stktable *t;
1533 struct stktable_key *key;
1534 struct stksess *ts;
1535 void *ptr;
1536
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001537 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001538
1539 key = smp_to_stkey(smp, t);
1540 if (!key)
1541 return 0;
1542
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001543 ts = stktable_lookup_key(t, key);
1544
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001545 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001546 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001547 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001548
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001549 if (!ts) /* key not present */
1550 return 1;
1551
1552 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001553 if (ptr)
1554 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1555 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001556
Daniel Corbett3e60b112018-05-27 09:47:12 -04001557 stktable_release(t, ts);
1558 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001559}
1560
1561/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1562 * it up into this table. Returns the cumulated number of HTTP request for the
1563 * key if the key is present in the table, otherwise zero, so that comparisons
1564 * can be easily performed. If the inspected parameter is not stored in the
1565 * table, <not found> is returned.
1566 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001567static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001568{
1569 struct stktable *t;
1570 struct stktable_key *key;
1571 struct stksess *ts;
1572 void *ptr;
1573
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001574 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001575
1576 key = smp_to_stkey(smp, t);
1577 if (!key)
1578 return 0;
1579
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001580 ts = stktable_lookup_key(t, key);
1581
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001582 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001583 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001584 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001585
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001586 if (!ts) /* key not present */
1587 return 1;
1588
1589 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001590 if (ptr)
1591 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001592
Daniel Corbett3e60b112018-05-27 09:47:12 -04001593 stktable_release(t, ts);
1594 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001595}
1596
1597/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1598 * it up into this table. Returns the HTTP request rate the key if the key is
1599 * present in the table, otherwise zero, so that comparisons can be easily
1600 * performed. If the inspected parameter is not stored in the table, <not found>
1601 * is returned.
1602 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001603static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001604{
1605 struct stktable *t;
1606 struct stktable_key *key;
1607 struct stksess *ts;
1608 void *ptr;
1609
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001610 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001611
1612 key = smp_to_stkey(smp, t);
1613 if (!key)
1614 return 0;
1615
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001616 ts = stktable_lookup_key(t, key);
1617
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001618 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001619 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001620 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001621
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001622 if (!ts) /* key not present */
1623 return 1;
1624
1625 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001626 if (ptr)
1627 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1628 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001629
Daniel Corbett3e60b112018-05-27 09:47:12 -04001630 stktable_release(t, ts);
1631 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001632}
1633
1634/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1635 * it up into this table. Returns the volume of datareceived from clients in kbytes
1636 * if the key is present in the table, otherwise zero, so that comparisons can
1637 * be easily performed. If the inspected parameter is not stored in the table,
1638 * <not found> is returned.
1639 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001640static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001641{
1642 struct stktable *t;
1643 struct stktable_key *key;
1644 struct stksess *ts;
1645 void *ptr;
1646
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001647 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001648
1649 key = smp_to_stkey(smp, t);
1650 if (!key)
1651 return 0;
1652
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001653 ts = stktable_lookup_key(t, key);
1654
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001655 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001656 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001657 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001658
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001659 if (!ts) /* key not present */
1660 return 1;
1661
1662 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001663 if (ptr)
1664 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001665
Daniel Corbett3e60b112018-05-27 09:47:12 -04001666 stktable_release(t, ts);
1667 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001668}
1669
1670/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1671 * it up into this table. Returns the volume of data sent to clients in kbytes
1672 * if the key is present in the table, otherwise zero, so that comparisons can
1673 * be easily performed. If the inspected parameter is not stored in the table,
1674 * <not found> is returned.
1675 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001676static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001677{
1678 struct stktable *t;
1679 struct stktable_key *key;
1680 struct stksess *ts;
1681 void *ptr;
1682
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001683 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001684
1685 key = smp_to_stkey(smp, t);
1686 if (!key)
1687 return 0;
1688
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001689 ts = stktable_lookup_key(t, key);
1690
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001691 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001692 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001693 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001694
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001695 if (!ts) /* key not present */
1696 return 1;
1697
1698 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001699 if (ptr)
1700 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001701
Daniel Corbett3e60b112018-05-27 09:47:12 -04001702 stktable_release(t, ts);
1703 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001704}
1705
1706/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1707 * it up into this table. Returns the server ID associated with the key if the
1708 * key is present in the table, otherwise zero, so that comparisons can be
1709 * easily performed. If the inspected parameter is not stored in the table,
1710 * <not found> is returned.
1711 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001712static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001713{
1714 struct stktable *t;
1715 struct stktable_key *key;
1716 struct stksess *ts;
1717 void *ptr;
1718
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001719 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001720
1721 key = smp_to_stkey(smp, t);
1722 if (!key)
1723 return 0;
1724
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001725 ts = stktable_lookup_key(t, key);
1726
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001728 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001729 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001730
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001731 if (!ts) /* key not present */
1732 return 1;
1733
1734 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001735 if (ptr)
1736 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001737
Daniel Corbett3e60b112018-05-27 09:47:12 -04001738 stktable_release(t, ts);
1739 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001740}
1741
1742/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1743 * it up into this table. Returns the cumulated number of sessions for the
1744 * key if the key is present in the table, otherwise zero, so that comparisons
1745 * can be easily performed. If the inspected parameter is not stored in the
1746 * table, <not found> is returned.
1747 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001748static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001749{
1750 struct stktable *t;
1751 struct stktable_key *key;
1752 struct stksess *ts;
1753 void *ptr;
1754
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001755 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001756
1757 key = smp_to_stkey(smp, t);
1758 if (!key)
1759 return 0;
1760
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001761 ts = stktable_lookup_key(t, key);
1762
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001763 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001764 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001765 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001766
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001767 if (!ts) /* key not present */
1768 return 1;
1769
1770 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001771 if (ptr)
1772 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001773
Daniel Corbett3e60b112018-05-27 09:47:12 -04001774 stktable_release(t, ts);
1775 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001776}
1777
1778/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1779 * it up into this table. Returns the session rate the key if the key is
1780 * present in the table, otherwise zero, so that comparisons can be easily
1781 * performed. If the inspected parameter is not stored in the table, <not found>
1782 * is returned.
1783 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001784static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001785{
1786 struct stktable *t;
1787 struct stktable_key *key;
1788 struct stksess *ts;
1789 void *ptr;
1790
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001791 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001792
1793 key = smp_to_stkey(smp, t);
1794 if (!key)
1795 return 0;
1796
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001797 ts = stktable_lookup_key(t, key);
1798
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001799 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001800 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001801 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001802
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001803 if (!ts) /* key not present */
1804 return 1;
1805
1806 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001807 if (ptr)
1808 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1809 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001810
Daniel Corbett3e60b112018-05-27 09:47:12 -04001811 stktable_release(t, ts);
1812 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001813}
1814
1815/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1816 * it up into this table. Returns the amount of concurrent connections tracking
1817 * the same key if the key is present in the table, otherwise zero, so that
1818 * comparisons can be easily performed. If the inspected parameter is not
1819 * stored in the table, <not found> is returned.
1820 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001821static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001822{
1823 struct stktable *t;
1824 struct stktable_key *key;
1825 struct stksess *ts;
1826
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001827 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001828
1829 key = smp_to_stkey(smp, t);
1830 if (!key)
1831 return 0;
1832
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001833 ts = stktable_lookup_key(t, key);
1834
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001835 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001836 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001837 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001838
Tim Duesterhus65189c12018-06-26 15:57:29 +02001839 if (!ts)
1840 return 1;
1841
1842 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001843
Daniel Corbett3e60b112018-05-27 09:47:12 -04001844 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001845 return 1;
1846}
1847
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001848/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001849static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001850 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001851{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001852 struct stksess *ts;
1853 struct stkctr *stkctr;
1854
1855 /* Extract the stksess, return OK if no stksess available. */
1856 if (s)
1857 stkctr = &s->stkctr[rule->arg.gpc.sc];
1858 else
1859 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001860
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001861 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001862 if (ts) {
1863 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001864
Willy Tarreau79c1e912016-01-25 14:54:45 +01001865 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1866 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001867 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1868 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001869 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001870
1871 if (ptr1)
1872 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001873 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001874
Emeric Brun819fc6f2017-06-13 19:37:32 +02001875 if (ptr2)
1876 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001877
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001878 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001879
1880 /* If data was modified, we need to touch to re-schedule sync */
1881 stktable_touch_local(stkctr->table, ts, 0);
1882 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001883 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001884 return ACT_RET_CONT;
1885}
1886
1887/* This function is a common parser for using variables. It understands
1888 * the formats:
1889 *
1890 * sc-inc-gpc0(<stick-table ID>)
1891 *
1892 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1893 * it returns 1 and the variable <expr> is filled with the pointer to the
1894 * expression to execute.
1895 */
1896static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1897 struct act_rule *rule, char **err)
1898{
1899 const char *cmd_name = args[*arg-1];
1900 char *error;
1901
1902 cmd_name += strlen("sc-inc-gpc0");
1903 if (*cmd_name == '\0') {
1904 /* default stick table id. */
1905 rule->arg.gpc.sc = 0;
1906 } else {
1907 /* parse the stick table id. */
1908 if (*cmd_name != '(') {
1909 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1910 return ACT_RET_PRS_ERR;
1911 }
1912 cmd_name++; /* jump the '(' */
1913 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1914 if (*error != ')') {
1915 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1916 return ACT_RET_PRS_ERR;
1917 }
1918
Christopher Faulet28436e22019-12-18 10:25:46 +01001919 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001920 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01001921 MAX_SESS_STKCTR-1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001922 return ACT_RET_PRS_ERR;
1923 }
1924 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001925 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001926 rule->action_ptr = action_inc_gpc0;
1927 return ACT_RET_PRS_OK;
1928}
1929
1930/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001931static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1932 struct session *sess, struct stream *s, int flags)
1933{
1934 struct stksess *ts;
1935 struct stkctr *stkctr;
1936
1937 /* Extract the stksess, return OK if no stksess available. */
1938 if (s)
1939 stkctr = &s->stkctr[rule->arg.gpc.sc];
1940 else
1941 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1942
1943 ts = stkctr_entry(stkctr);
1944 if (ts) {
1945 void *ptr1, *ptr2;
1946
1947 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1948 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1949 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1950 if (ptr1 || ptr2) {
1951 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1952
1953 if (ptr1)
1954 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1955 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1956
1957 if (ptr2)
1958 stktable_data_cast(ptr2, gpc1)++;
1959
1960 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1961
1962 /* If data was modified, we need to touch to re-schedule sync */
1963 stktable_touch_local(stkctr->table, ts, 0);
1964 }
1965 }
1966 return ACT_RET_CONT;
1967}
1968
1969/* This function is a common parser for using variables. It understands
1970 * the formats:
1971 *
1972 * sc-inc-gpc1(<stick-table ID>)
1973 *
1974 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1975 * it returns 1 and the variable <expr> is filled with the pointer to the
1976 * expression to execute.
1977 */
1978static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1979 struct act_rule *rule, char **err)
1980{
1981 const char *cmd_name = args[*arg-1];
1982 char *error;
1983
1984 cmd_name += strlen("sc-inc-gpc1");
1985 if (*cmd_name == '\0') {
1986 /* default stick table id. */
1987 rule->arg.gpc.sc = 0;
1988 } else {
1989 /* parse the stick table id. */
1990 if (*cmd_name != '(') {
1991 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1992 return ACT_RET_PRS_ERR;
1993 }
1994 cmd_name++; /* jump the '(' */
1995 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1996 if (*error != ')') {
1997 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1998 return ACT_RET_PRS_ERR;
1999 }
2000
Christopher Faulet28436e22019-12-18 10:25:46 +01002001 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002002 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002003 MAX_SESS_STKCTR-1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002004 return ACT_RET_PRS_ERR;
2005 }
2006 }
2007 rule->action = ACT_CUSTOM;
2008 rule->action_ptr = action_inc_gpc1;
2009 return ACT_RET_PRS_OK;
2010}
2011
2012/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002013static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002014 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002015{
2016 void *ptr;
2017 struct stksess *ts;
2018 struct stkctr *stkctr;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002019 unsigned int value = 0;
2020 struct sample *smp;
2021 int smp_opt_dir;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002022
2023 /* Extract the stksess, return OK if no stksess available. */
2024 if (s)
2025 stkctr = &s->stkctr[rule->arg.gpt.sc];
2026 else
2027 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002028
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002029 ts = stkctr_entry(stkctr);
2030 if (!ts)
2031 return ACT_RET_CONT;
2032
2033 /* Store the sample in the required sc, and ignore errors. */
2034 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002035 if (ptr) {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002036 if (!rule->arg.gpt.expr)
2037 value = (unsigned int)(rule->arg.gpt.value);
2038 else {
2039 switch (rule->from) {
2040 case ACT_F_TCP_REQ_SES: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2041 case ACT_F_TCP_REQ_CNT: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2042 case ACT_F_TCP_RES_CNT: smp_opt_dir = SMP_OPT_DIR_RES; break;
2043 case ACT_F_HTTP_REQ: smp_opt_dir = SMP_OPT_DIR_REQ; break;
2044 case ACT_F_HTTP_RES: smp_opt_dir = SMP_OPT_DIR_RES; break;
2045 default:
2046 send_log(px, LOG_ERR, "stick table: internal error while setting gpt0.");
2047 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2048 ha_alert("stick table: internal error while executing setting gpt0.\n");
2049 return ACT_RET_CONT;
2050 }
2051
2052 /* Fetch and cast the expression. */
2053 smp = sample_fetch_as_type(px, sess, s, smp_opt_dir|SMP_OPT_FINAL, rule->arg.gpt.expr, SMP_T_SINT);
2054 if (!smp) {
2055 send_log(px, LOG_WARNING, "stick table: invalid expression or data type while setting gpt0.");
2056 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
2057 ha_alert("stick table: invalid expression or data type while setting gpt0.\n");
2058 return ACT_RET_CONT;
2059 }
2060 value = (unsigned int)(smp->data.u.sint);
2061 }
2062
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002063 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002064
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002065 stktable_data_cast(ptr, gpt0) = value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002066
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002067 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002068
2069 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002070 }
2071
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002072 return ACT_RET_CONT;
2073}
2074
2075/* This function is a common parser for using variables. It understands
2076 * the format:
2077 *
2078 * set-gpt0(<stick-table ID>) <expression>
2079 *
2080 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2081 * it returns 1 and the variable <expr> is filled with the pointer to the
2082 * expression to execute.
2083 */
2084static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2085 struct act_rule *rule, char **err)
2086
2087
2088{
2089 const char *cmd_name = args[*arg-1];
2090 char *error;
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002091 int smp_val;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002092
2093 cmd_name += strlen("sc-set-gpt0");
2094 if (*cmd_name == '\0') {
2095 /* default stick table id. */
2096 rule->arg.gpt.sc = 0;
2097 } else {
2098 /* parse the stick table id. */
2099 if (*cmd_name != '(') {
2100 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2101 return ACT_RET_PRS_ERR;
2102 }
2103 cmd_name++; /* jump the '(' */
2104 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2105 if (*error != ')') {
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
Christopher Faulet28436e22019-12-18 10:25:46 +01002110 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002111 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
Christopher Faulet28436e22019-12-18 10:25:46 +01002112 args[*arg-1], MAX_SESS_STKCTR-1);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002113 return ACT_RET_PRS_ERR;
2114 }
2115 }
2116
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002117 rule->arg.gpt.expr = NULL;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002118 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2119 if (*error != '\0') {
Cédric Dufour0d7712d2019-11-06 18:38:53 +01002120 rule->arg.gpt.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
2121 px->conf.args.line, err, &px->conf.args);
2122 if (!rule->arg.gpt.expr)
2123 return ACT_RET_PRS_ERR;
2124
2125 switch (rule->from) {
2126 case ACT_F_TCP_REQ_SES: smp_val = SMP_VAL_FE_SES_ACC; break;
2127 case ACT_F_TCP_REQ_CNT: smp_val = SMP_VAL_FE_REQ_CNT; break;
2128 case ACT_F_TCP_RES_CNT: smp_val = SMP_VAL_BE_RES_CNT; break;
2129 case ACT_F_HTTP_REQ: smp_val = SMP_VAL_FE_HRQ_HDR; break;
2130 case ACT_F_HTTP_RES: smp_val = SMP_VAL_BE_HRS_HDR; break;
2131 default:
2132 memprintf(err, "internal error, unexpected rule->from=%d, please report this bug!", rule->from);
2133 return ACT_RET_PRS_ERR;
2134 }
2135 if (!(rule->arg.gpt.expr->fetch->val & smp_val)) {
2136 memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[*arg-1],
2137 sample_src_names(rule->arg.gpt.expr->fetch->use));
2138 free(rule->arg.gpt.expr);
2139 return ACT_RET_PRS_ERR;
2140 }
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002141 }
2142 (*arg)++;
2143
Thierry FOURNIER42148732015-09-02 17:17:33 +02002144 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002145 rule->action_ptr = action_set_gpt0;
2146
2147 return ACT_RET_PRS_OK;
2148}
2149
Willy Tarreau7d562212016-11-25 16:10:05 +01002150/* set temp integer to the number of used entries in the table pointed to by expr.
2151 * Accepts exactly 1 argument of type table.
2152 */
2153static int
2154smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2155{
2156 smp->flags = SMP_F_VOL_TEST;
2157 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002158 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002159 return 1;
2160}
2161
2162/* set temp integer to the number of free entries in the table pointed to by expr.
2163 * Accepts exactly 1 argument of type table.
2164 */
2165static int
2166smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2167{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002168 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002169
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002170 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002171 smp->flags = SMP_F_VOL_TEST;
2172 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002173 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002174 return 1;
2175}
2176
2177/* Returns a pointer to a stkctr depending on the fetch keyword name.
2178 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2179 * sc[0-9]_* will return a pointer to the respective field in the
2180 * stream <l4>. sc_* requires an UINT argument specifying the stick
2181 * counter number. src_* will fill a locally allocated structure with
2182 * the table and entry corresponding to what is specified with src_*.
2183 * NULL may be returned if the designated stkctr is not tracked. For
2184 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2185 * passed. When present, the currently tracked key is then looked up
2186 * in the specified table instead of the current table. The purpose is
2187 * to be able to convery multiple values per key (eg: have gpc0 from
2188 * multiple tables). <strm> is allowed to be NULL, in which case only
2189 * the session will be consulted.
2190 */
2191struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002192smp_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 +01002193{
Willy Tarreau7d562212016-11-25 16:10:05 +01002194 struct stkctr *stkptr;
2195 struct stksess *stksess;
2196 unsigned int num = kw[2] - '0';
2197 int arg = 0;
2198
2199 if (num == '_' - '0') {
2200 /* sc_* variant, args[0] = ctr# (mandatory) */
2201 num = args[arg++].data.sint;
Willy Tarreau7d562212016-11-25 16:10:05 +01002202 }
2203 else if (num > 9) { /* src_* variant, args[0] = table */
2204 struct stktable_key *key;
2205 struct connection *conn = objt_conn(sess->origin);
2206 struct sample smp;
2207
2208 if (!conn)
2209 return NULL;
2210
Joseph Herlant5662fa42018-11-15 13:43:28 -08002211 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002212 smp.px = NULL;
2213 smp.sess = sess;
2214 smp.strm = strm;
2215 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2216 return NULL;
2217
2218 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002219 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002220 if (!key)
2221 return NULL;
2222
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002223 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002224 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2225 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002226 }
2227
2228 /* Here, <num> contains the counter number from 0 to 9 for
2229 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2230 * args[arg] is the first optional argument. We first lookup the
2231 * ctr form the stream, then from the session if it was not there.
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002232 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
Willy Tarreau7d562212016-11-25 16:10:05 +01002233 */
Christopher Fauleta9fa88a2019-10-21 10:53:34 +02002234 if (num >= MAX_SESS_STKCTR)
2235 return NULL;
Willy Tarreau7d562212016-11-25 16:10:05 +01002236
2237 if (strm)
2238 stkptr = &strm->stkctr[num];
2239 if (!strm || !stkctr_entry(stkptr)) {
2240 stkptr = &sess->stkctr[num];
2241 if (!stkctr_entry(stkptr))
2242 return NULL;
2243 }
2244
2245 stksess = stkctr_entry(stkptr);
2246 if (!stksess)
2247 return NULL;
2248
2249 if (unlikely(args[arg].type == ARGT_TAB)) {
2250 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002251 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002252 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2253 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002254 }
2255 return stkptr;
2256}
2257
2258/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2259 * the entry if it doesn't exist yet. This is needed for a few fetch
2260 * functions which need to create an entry, such as src_inc_gpc* and
2261 * src_clr_gpc*.
2262 */
2263struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002264smp_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 +01002265{
Willy Tarreau7d562212016-11-25 16:10:05 +01002266 struct stktable_key *key;
2267 struct connection *conn = objt_conn(sess->origin);
2268 struct sample smp;
2269
2270 if (strncmp(kw, "src_", 4) != 0)
2271 return NULL;
2272
2273 if (!conn)
2274 return NULL;
2275
Joseph Herlant5662fa42018-11-15 13:43:28 -08002276 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002277 smp.px = NULL;
2278 smp.sess = sess;
2279 smp.strm = strm;
2280 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2281 return NULL;
2282
2283 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002284 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002285 if (!key)
2286 return NULL;
2287
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002288 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002289 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2290 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002291}
2292
2293/* set return a boolean indicating if the requested stream counter is
2294 * currently being tracked or not.
2295 * Supports being called as "sc[0-9]_tracked" only.
2296 */
2297static int
2298smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2299{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002300 struct stkctr tmpstkctr;
2301 struct stkctr *stkctr;
2302
Willy Tarreau7d562212016-11-25 16:10:05 +01002303 smp->flags = SMP_F_VOL_TEST;
2304 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002305 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2306 smp->data.u.sint = !!stkctr;
2307
2308 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002309 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002310 stktable_release(stkctr->table, stkctr_entry(stkctr));
2311
Willy Tarreau7d562212016-11-25 16:10:05 +01002312 return 1;
2313}
2314
2315/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2316 * frontend counters or from the src.
2317 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2318 * zero is returned if the key is new.
2319 */
2320static int
2321smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2322{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002323 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002324 struct stkctr *stkctr;
2325
Emeric Brun819fc6f2017-06-13 19:37:32 +02002326 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002327 if (!stkctr)
2328 return 0;
2329
2330 smp->flags = SMP_F_VOL_TEST;
2331 smp->data.type = SMP_T_SINT;
2332 smp->data.u.sint = 0;
2333
Emeric Brun819fc6f2017-06-13 19:37:32 +02002334 if (stkctr_entry(stkctr)) {
2335 void *ptr;
2336
2337 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2338 if (!ptr) {
2339 if (stkctr == &tmpstkctr)
2340 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002341 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002342 }
2343
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002344 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002345
Willy Tarreau7d562212016-11-25 16:10:05 +01002346 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002347
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002348 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002349
2350 if (stkctr == &tmpstkctr)
2351 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002352 }
2353 return 1;
2354}
2355
2356/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2357 * frontend counters or from the src.
2358 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2359 * zero is returned if the key is new.
2360 */
2361static int
2362smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2363{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002364 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002365 struct stkctr *stkctr;
2366
Emeric Brun819fc6f2017-06-13 19:37:32 +02002367 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002368 if (!stkctr)
2369 return 0;
2370
2371 smp->flags = SMP_F_VOL_TEST;
2372 smp->data.type = SMP_T_SINT;
2373 smp->data.u.sint = 0;
2374
2375 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002376 void *ptr;
2377
2378 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2379 if (!ptr) {
2380 if (stkctr == &tmpstkctr)
2381 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002382 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002383 }
2384
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002385 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002386
Willy Tarreau7d562212016-11-25 16:10:05 +01002387 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002388
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002389 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002390
2391 if (stkctr == &tmpstkctr)
2392 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002393 }
2394 return 1;
2395}
2396
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002397/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2398 * frontend counters or from the src.
2399 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2400 * zero is returned if the key is new.
2401 */
2402static int
2403smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2404{
2405 struct stkctr tmpstkctr;
2406 struct stkctr *stkctr;
2407
2408 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2409 if (!stkctr)
2410 return 0;
2411
2412 smp->flags = SMP_F_VOL_TEST;
2413 smp->data.type = SMP_T_SINT;
2414 smp->data.u.sint = 0;
2415
2416 if (stkctr_entry(stkctr) != NULL) {
2417 void *ptr;
2418
2419 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2420 if (!ptr) {
2421 if (stkctr == &tmpstkctr)
2422 stktable_release(stkctr->table, stkctr_entry(stkctr));
2423 return 0; /* parameter not stored */
2424 }
2425
2426 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2427
2428 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2429
2430 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2431
2432 if (stkctr == &tmpstkctr)
2433 stktable_release(stkctr->table, stkctr_entry(stkctr));
2434 }
2435 return 1;
2436}
2437
Willy Tarreau7d562212016-11-25 16:10:05 +01002438/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2439 * tracked frontend counters or from the src.
2440 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2441 * Value zero is returned if the key is new.
2442 */
2443static int
2444smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2445{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002446 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002447 struct stkctr *stkctr;
2448
Emeric Brun819fc6f2017-06-13 19:37:32 +02002449 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002450 if (!stkctr)
2451 return 0;
2452
2453 smp->flags = SMP_F_VOL_TEST;
2454 smp->data.type = SMP_T_SINT;
2455 smp->data.u.sint = 0;
2456 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002457 void *ptr;
2458
2459 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2460 if (!ptr) {
2461 if (stkctr == &tmpstkctr)
2462 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002463 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002464 }
2465
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002466 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002467
Willy Tarreau7d562212016-11-25 16:10:05 +01002468 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2469 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002470
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002471 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002472
2473 if (stkctr == &tmpstkctr)
2474 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002475 }
2476 return 1;
2477}
2478
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002479/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2480 * tracked frontend counters or from the src.
2481 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2482 * Value zero is returned if the key is new.
2483 */
2484static int
2485smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2486{
2487 struct stkctr tmpstkctr;
2488 struct stkctr *stkctr;
2489
2490 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2491 if (!stkctr)
2492 return 0;
2493
2494 smp->flags = SMP_F_VOL_TEST;
2495 smp->data.type = SMP_T_SINT;
2496 smp->data.u.sint = 0;
2497 if (stkctr_entry(stkctr) != NULL) {
2498 void *ptr;
2499
2500 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2501 if (!ptr) {
2502 if (stkctr == &tmpstkctr)
2503 stktable_release(stkctr->table, stkctr_entry(stkctr));
2504 return 0; /* parameter not stored */
2505 }
2506
2507 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2508
2509 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2510 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2511
2512 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2513
2514 if (stkctr == &tmpstkctr)
2515 stktable_release(stkctr->table, stkctr_entry(stkctr));
2516 }
2517 return 1;
2518}
2519
Willy Tarreau7d562212016-11-25 16:10:05 +01002520/* Increment the General Purpose Counter 0 value from the stream's tracked
2521 * frontend counters and return it into temp integer.
2522 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2523 */
2524static int
2525smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2526{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002527 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002528 struct stkctr *stkctr;
2529
Emeric Brun819fc6f2017-06-13 19:37:32 +02002530 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002531 if (!stkctr)
2532 return 0;
2533
2534 smp->flags = SMP_F_VOL_TEST;
2535 smp->data.type = SMP_T_SINT;
2536 smp->data.u.sint = 0;
2537
Emeric Brun819fc6f2017-06-13 19:37:32 +02002538 if (!stkctr_entry(stkctr))
2539 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002540
2541 if (stkctr && stkctr_entry(stkctr)) {
2542 void *ptr1,*ptr2;
2543
Emeric Brun819fc6f2017-06-13 19:37:32 +02002544
Willy Tarreau7d562212016-11-25 16:10:05 +01002545 /* First, update gpc0_rate if it's tracked. Second, update its
2546 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2547 */
2548 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002549 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002551 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002552
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553 if (ptr1) {
2554 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2555 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2556 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2557 }
2558
2559 if (ptr2)
2560 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2561
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002562 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002563
2564 /* If data was modified, we need to touch to re-schedule sync */
2565 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2566 }
2567 else if (stkctr == &tmpstkctr)
2568 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002569 }
2570 return 1;
2571}
2572
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002573/* Increment the General Purpose Counter 1 value from the stream's tracked
2574 * frontend counters and return it into temp integer.
2575 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2576 */
2577static int
2578smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2579{
2580 struct stkctr tmpstkctr;
2581 struct stkctr *stkctr;
2582
2583 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2584 if (!stkctr)
2585 return 0;
2586
2587 smp->flags = SMP_F_VOL_TEST;
2588 smp->data.type = SMP_T_SINT;
2589 smp->data.u.sint = 0;
2590
2591 if (!stkctr_entry(stkctr))
2592 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2593
2594 if (stkctr && stkctr_entry(stkctr)) {
2595 void *ptr1,*ptr2;
2596
2597
2598 /* First, update gpc1_rate if it's tracked. Second, update its
2599 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2600 */
2601 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2602 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2603 if (ptr1 || ptr2) {
2604 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2605
2606 if (ptr1) {
2607 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2608 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2609 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2610 }
2611
2612 if (ptr2)
2613 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2614
2615 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2616
2617 /* If data was modified, we need to touch to re-schedule sync */
2618 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2619 }
2620 else if (stkctr == &tmpstkctr)
2621 stktable_release(stkctr->table, stkctr_entry(stkctr));
2622 }
2623 return 1;
2624}
2625
Willy Tarreau7d562212016-11-25 16:10:05 +01002626/* Clear the General Purpose Counter 0 value from the stream's tracked
2627 * frontend counters and return its previous value into temp integer.
2628 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2629 */
2630static int
2631smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2632{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002633 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002634 struct stkctr *stkctr;
2635
Emeric Brun819fc6f2017-06-13 19:37:32 +02002636 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002637 if (!stkctr)
2638 return 0;
2639
2640 smp->flags = SMP_F_VOL_TEST;
2641 smp->data.type = SMP_T_SINT;
2642 smp->data.u.sint = 0;
2643
Emeric Brun819fc6f2017-06-13 19:37:32 +02002644 if (!stkctr_entry(stkctr))
2645 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002646
Emeric Brun819fc6f2017-06-13 19:37:32 +02002647 if (stkctr && stkctr_entry(stkctr)) {
2648 void *ptr;
2649
2650 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2651 if (!ptr) {
2652 if (stkctr == &tmpstkctr)
2653 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002654 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002655 }
2656
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002657 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002658
Willy Tarreau7d562212016-11-25 16:10:05 +01002659 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2660 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002661
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002662 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002663
Willy Tarreau7d562212016-11-25 16:10:05 +01002664 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002665 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002666 }
2667 return 1;
2668}
2669
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002670/* Clear the General Purpose Counter 1 value from the stream's tracked
2671 * frontend counters and return its previous value into temp integer.
2672 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2673 */
2674static int
2675smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2676{
2677 struct stkctr tmpstkctr;
2678 struct stkctr *stkctr;
2679
2680 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2681 if (!stkctr)
2682 return 0;
2683
2684 smp->flags = SMP_F_VOL_TEST;
2685 smp->data.type = SMP_T_SINT;
2686 smp->data.u.sint = 0;
2687
2688 if (!stkctr_entry(stkctr))
2689 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2690
2691 if (stkctr && stkctr_entry(stkctr)) {
2692 void *ptr;
2693
2694 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2695 if (!ptr) {
2696 if (stkctr == &tmpstkctr)
2697 stktable_release(stkctr->table, stkctr_entry(stkctr));
2698 return 0; /* parameter not stored */
2699 }
2700
2701 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2702
2703 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2704 stktable_data_cast(ptr, gpc1) = 0;
2705
2706 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2707
2708 /* If data was modified, we need to touch to re-schedule sync */
2709 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2710 }
2711 return 1;
2712}
2713
Willy Tarreau7d562212016-11-25 16:10:05 +01002714/* set <smp> to the cumulated number of connections from the stream's tracked
2715 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2716 * "src_conn_cnt" only.
2717 */
2718static int
2719smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2720{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002721 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002722 struct stkctr *stkctr;
2723
Emeric Brun819fc6f2017-06-13 19:37:32 +02002724 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002725 if (!stkctr)
2726 return 0;
2727
2728 smp->flags = SMP_F_VOL_TEST;
2729 smp->data.type = SMP_T_SINT;
2730 smp->data.u.sint = 0;
2731 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002732 void *ptr;
2733
2734 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2735 if (!ptr) {
2736 if (stkctr == &tmpstkctr)
2737 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002738 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002739 }
2740
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002741 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002742
Willy Tarreau7d562212016-11-25 16:10:05 +01002743 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002744
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002745 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746
2747 if (stkctr == &tmpstkctr)
2748 stktable_release(stkctr->table, stkctr_entry(stkctr));
2749
2750
Willy Tarreau7d562212016-11-25 16:10:05 +01002751 }
2752 return 1;
2753}
2754
2755/* set <smp> to the connection rate from the stream's tracked frontend
2756 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2757 * only.
2758 */
2759static int
2760smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2761{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002762 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002763 struct stkctr *stkctr;
2764
Emeric Brun819fc6f2017-06-13 19:37:32 +02002765 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002766 if (!stkctr)
2767 return 0;
2768
2769 smp->flags = SMP_F_VOL_TEST;
2770 smp->data.type = SMP_T_SINT;
2771 smp->data.u.sint = 0;
2772 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002773 void *ptr;
2774
2775 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2776 if (!ptr) {
2777 if (stkctr == &tmpstkctr)
2778 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002779 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780 }
2781
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002782 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002783
Willy Tarreau7d562212016-11-25 16:10:05 +01002784 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2785 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002786
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002787 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002788
2789 if (stkctr == &tmpstkctr)
2790 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002791 }
2792 return 1;
2793}
2794
2795/* set temp integer to the number of connections from the stream's source address
2796 * in the table pointed to by expr, after updating it.
2797 * Accepts exactly 1 argument of type table.
2798 */
2799static int
2800smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2801{
2802 struct connection *conn = objt_conn(smp->sess->origin);
2803 struct stksess *ts;
2804 struct stktable_key *key;
2805 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002806 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002807
2808 if (!conn)
2809 return 0;
2810
Joseph Herlant5662fa42018-11-15 13:43:28 -08002811 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002812 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2813 return 0;
2814
2815 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002816 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002817 if (!key)
2818 return 0;
2819
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002820 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002821
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002822 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002823 /* entry does not exist and could not be created */
2824 return 0;
2825
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002826 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002828 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002829 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002830
2831 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002832
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002833 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002834
Willy Tarreau7d562212016-11-25 16:10:05 +01002835 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002836
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002837 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002838
Willy Tarreau7d562212016-11-25 16:10:05 +01002839 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002840
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002841 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002842
2843 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002844 return 1;
2845}
2846
2847/* set <smp> to the number of concurrent connections from the stream's tracked
2848 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2849 * "src_conn_cur" only.
2850 */
2851static int
2852smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2853{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002854 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002855 struct stkctr *stkctr;
2856
Emeric Brun819fc6f2017-06-13 19:37:32 +02002857 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002858 if (!stkctr)
2859 return 0;
2860
2861 smp->flags = SMP_F_VOL_TEST;
2862 smp->data.type = SMP_T_SINT;
2863 smp->data.u.sint = 0;
2864 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002865 void *ptr;
2866
2867 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2868 if (!ptr) {
2869 if (stkctr == &tmpstkctr)
2870 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002871 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002872 }
2873
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002874 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002875
Willy Tarreau7d562212016-11-25 16:10:05 +01002876 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002878 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002879
2880 if (stkctr == &tmpstkctr)
2881 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002882 }
2883 return 1;
2884}
2885
2886/* set <smp> to the cumulated number of streams from the stream's tracked
2887 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2888 * "src_sess_cnt" only.
2889 */
2890static int
2891smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2892{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 struct stkctr *stkctr;
2895
Emeric Brun819fc6f2017-06-13 19:37:32 +02002896 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002897 if (!stkctr)
2898 return 0;
2899
2900 smp->flags = SMP_F_VOL_TEST;
2901 smp->data.type = SMP_T_SINT;
2902 smp->data.u.sint = 0;
2903 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002904 void *ptr;
2905
2906 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2907 if (!ptr) {
2908 if (stkctr == &tmpstkctr)
2909 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002910 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002911 }
2912
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002913 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002914
Willy Tarreau7d562212016-11-25 16:10:05 +01002915 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002917 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002918
2919 if (stkctr == &tmpstkctr)
2920 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002921 }
2922 return 1;
2923}
2924
2925/* set <smp> to the stream rate from the stream's tracked frontend counters.
2926 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2927 */
2928static int
2929smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2930{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002932 struct stkctr *stkctr;
2933
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002935 if (!stkctr)
2936 return 0;
2937
2938 smp->flags = SMP_F_VOL_TEST;
2939 smp->data.type = SMP_T_SINT;
2940 smp->data.u.sint = 0;
2941 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002942 void *ptr;
2943
2944 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2945 if (!ptr) {
2946 if (stkctr == &tmpstkctr)
2947 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002948 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002949 }
2950
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002951 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952
Willy Tarreau7d562212016-11-25 16:10:05 +01002953 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2954 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002956 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002957
2958 if (stkctr == &tmpstkctr)
2959 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002960 }
2961 return 1;
2962}
2963
2964/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2965 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2966 * "src_http_req_cnt" only.
2967 */
2968static int
2969smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2970{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002971 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002972 struct stkctr *stkctr;
2973
Emeric Brun819fc6f2017-06-13 19:37:32 +02002974 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002975 if (!stkctr)
2976 return 0;
2977
2978 smp->flags = SMP_F_VOL_TEST;
2979 smp->data.type = SMP_T_SINT;
2980 smp->data.u.sint = 0;
2981 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002982 void *ptr;
2983
2984 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2985 if (!ptr) {
2986 if (stkctr == &tmpstkctr)
2987 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002988 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002989 }
2990
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002991 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992
Willy Tarreau7d562212016-11-25 16:10:05 +01002993 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002994
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002995 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996
2997 if (stkctr == &tmpstkctr)
2998 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 }
3000 return 1;
3001}
3002
3003/* set <smp> to the HTTP request rate from the stream's tracked frontend
3004 * counters. Supports being called as "sc[0-9]_http_req_rate" or
3005 * "src_http_req_rate" only.
3006 */
3007static int
3008smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3009{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003011 struct stkctr *stkctr;
3012
Emeric Brun819fc6f2017-06-13 19:37:32 +02003013 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003014 if (!stkctr)
3015 return 0;
3016
3017 smp->flags = SMP_F_VOL_TEST;
3018 smp->data.type = SMP_T_SINT;
3019 smp->data.u.sint = 0;
3020 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003021 void *ptr;
3022
3023 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
3024 if (!ptr) {
3025 if (stkctr == &tmpstkctr)
3026 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003027 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003028 }
3029
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003030 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003031
Willy Tarreau7d562212016-11-25 16:10:05 +01003032 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3033 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003034
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003035 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003036
3037 if (stkctr == &tmpstkctr)
3038 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003039 }
3040 return 1;
3041}
3042
3043/* set <smp> to the cumulated number of HTTP requests errors from the stream's
3044 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
3045 * "src_http_err_cnt" only.
3046 */
3047static int
3048smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
3049{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003050 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003051 struct stkctr *stkctr;
3052
Emeric Brun819fc6f2017-06-13 19:37:32 +02003053 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003054 if (!stkctr)
3055 return 0;
3056
3057 smp->flags = SMP_F_VOL_TEST;
3058 smp->data.type = SMP_T_SINT;
3059 smp->data.u.sint = 0;
3060 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003061 void *ptr;
3062
3063 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3064 if (!ptr) {
3065 if (stkctr == &tmpstkctr)
3066 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003067 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003068 }
3069
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003070 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003071
Willy Tarreau7d562212016-11-25 16:10:05 +01003072 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003073
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003074 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003075
3076 if (stkctr == &tmpstkctr)
3077 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003078 }
3079 return 1;
3080}
3081
3082/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3083 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3084 * "src_http_err_rate" only.
3085 */
3086static int
3087smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3088{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003089 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003090 struct stkctr *stkctr;
3091
Emeric Brun819fc6f2017-06-13 19:37:32 +02003092 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003093 if (!stkctr)
3094 return 0;
3095
3096 smp->flags = SMP_F_VOL_TEST;
3097 smp->data.type = SMP_T_SINT;
3098 smp->data.u.sint = 0;
3099 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003100 void *ptr;
3101
3102 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3103 if (!ptr) {
3104 if (stkctr == &tmpstkctr)
3105 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003106 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003107 }
3108
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003109 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003110
Willy Tarreau7d562212016-11-25 16:10:05 +01003111 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3112 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003113
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003114 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003115
3116 if (stkctr == &tmpstkctr)
3117 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003118 }
3119 return 1;
3120}
3121
3122/* set <smp> to the number of kbytes received from clients, as found in the
3123 * stream's tracked frontend counters. Supports being called as
3124 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3125 */
3126static int
3127smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3128{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003130 struct stkctr *stkctr;
3131
Emeric Brun819fc6f2017-06-13 19:37:32 +02003132 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003133 if (!stkctr)
3134 return 0;
3135
3136 smp->flags = SMP_F_VOL_TEST;
3137 smp->data.type = SMP_T_SINT;
3138 smp->data.u.sint = 0;
3139 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003140 void *ptr;
3141
3142 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3143 if (!ptr) {
3144 if (stkctr == &tmpstkctr)
3145 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003146 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003147 }
3148
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003149 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003150
Willy Tarreau7d562212016-11-25 16:10:05 +01003151 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003152
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003153 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154
3155 if (stkctr == &tmpstkctr)
3156 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003157 }
3158 return 1;
3159}
3160
3161/* set <smp> to the data rate received from clients in bytes/s, as found
3162 * in the stream's tracked frontend counters. Supports being called as
3163 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3164 */
3165static int
3166smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3167{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003168 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003169 struct stkctr *stkctr;
3170
Emeric Brun819fc6f2017-06-13 19:37:32 +02003171 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003172 if (!stkctr)
3173 return 0;
3174
3175 smp->flags = SMP_F_VOL_TEST;
3176 smp->data.type = SMP_T_SINT;
3177 smp->data.u.sint = 0;
3178 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003179 void *ptr;
3180
3181 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3182 if (!ptr) {
3183 if (stkctr == &tmpstkctr)
3184 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003185 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003186 }
3187
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003188 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003189
Willy Tarreau7d562212016-11-25 16:10:05 +01003190 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3191 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003192
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003193 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003194
3195 if (stkctr == &tmpstkctr)
3196 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003197 }
3198 return 1;
3199}
3200
3201/* set <smp> to the number of kbytes sent to clients, as found in the
3202 * stream's tracked frontend counters. Supports being called as
3203 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3204 */
3205static int
3206smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3207{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003208 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003209 struct stkctr *stkctr;
3210
Emeric Brun819fc6f2017-06-13 19:37:32 +02003211 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003212 if (!stkctr)
3213 return 0;
3214
3215 smp->flags = SMP_F_VOL_TEST;
3216 smp->data.type = SMP_T_SINT;
3217 smp->data.u.sint = 0;
3218 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219 void *ptr;
3220
3221 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3222 if (!ptr) {
3223 if (stkctr == &tmpstkctr)
3224 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003225 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003226 }
3227
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003228 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003229
Willy Tarreau7d562212016-11-25 16:10:05 +01003230 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003231
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003232 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003233
3234 if (stkctr == &tmpstkctr)
3235 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003236 }
3237 return 1;
3238}
3239
3240/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3241 * stream's tracked frontend counters. Supports being called as
3242 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3243 */
3244static int
3245smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3246{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003247 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003248 struct stkctr *stkctr;
3249
Emeric Brun819fc6f2017-06-13 19:37:32 +02003250 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003251 if (!stkctr)
3252 return 0;
3253
3254 smp->flags = SMP_F_VOL_TEST;
3255 smp->data.type = SMP_T_SINT;
3256 smp->data.u.sint = 0;
3257 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003258 void *ptr;
3259
3260 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3261 if (!ptr) {
3262 if (stkctr == &tmpstkctr)
3263 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003264 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003265 }
3266
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003267 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003268
Willy Tarreau7d562212016-11-25 16:10:05 +01003269 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3270 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003271
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003272 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003273
3274 if (stkctr == &tmpstkctr)
3275 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003276 }
3277 return 1;
3278}
3279
3280/* set <smp> to the number of active trackers on the SC entry in the stream's
3281 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3282 */
3283static int
3284smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3285{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003286 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003287 struct stkctr *stkctr;
3288
Emeric Brun819fc6f2017-06-13 19:37:32 +02003289 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003290 if (!stkctr)
3291 return 0;
3292
3293 smp->flags = SMP_F_VOL_TEST;
3294 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003295 if (stkctr == &tmpstkctr) {
3296 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3297 stktable_release(stkctr->table, stkctr_entry(stkctr));
3298 }
3299 else {
3300 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3301 }
3302
Willy Tarreau7d562212016-11-25 16:10:05 +01003303 return 1;
3304}
3305
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003306
3307/* The functions below are used to manipulate table contents from the CLI.
3308 * There are 3 main actions, "clear", "set" and "show". The code is shared
3309 * between all actions, and the action is encoded in the void *private in
3310 * the appctx as well as in the keyword registration, among one of the
3311 * following values.
3312 */
3313
3314enum {
3315 STK_CLI_ACT_CLR,
3316 STK_CLI_ACT_SET,
3317 STK_CLI_ACT_SHOW,
3318};
3319
3320/* Dump the status of a table to a stream interface's
3321 * read buffer. It returns 0 if the output buffer is full
3322 * and needs to be called again, otherwise non-zero.
3323 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003324static int table_dump_head_to_buffer(struct buffer *msg,
3325 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003326 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003327{
3328 struct stream *s = si_strm(si);
3329
3330 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003331 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003332
3333 /* any other information should be dumped here */
3334
William Lallemand07a62f72017-05-24 00:57:40 +02003335 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003336 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3337
Willy Tarreau06d80a92017-10-19 14:32:15 +02003338 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003339 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003340 return 0;
3341 }
3342
3343 return 1;
3344}
3345
3346/* Dump a table entry to a stream interface's
3347 * read buffer. It returns 0 if the output buffer is full
3348 * and needs to be called again, otherwise non-zero.
3349 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003350static int table_dump_entry_to_buffer(struct buffer *msg,
3351 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003352 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003353{
3354 int dt;
3355
3356 chunk_appendf(msg, "%p:", entry);
3357
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003358 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003359 char addr[INET_ADDRSTRLEN];
3360 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3361 chunk_appendf(msg, " key=%s", addr);
3362 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003363 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003364 char addr[INET6_ADDRSTRLEN];
3365 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3366 chunk_appendf(msg, " key=%s", addr);
3367 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003368 else if (t->type == SMP_T_SINT) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003369 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3370 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003371 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003372 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003373 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003374 }
3375 else {
3376 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003377 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003378 }
3379
3380 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3381
3382 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3383 void *ptr;
3384
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003385 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003386 continue;
3387 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003388 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003389 else
3390 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3391
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003392 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003393 switch (stktable_data_types[dt].std_type) {
3394 case STD_T_SINT:
3395 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3396 break;
3397 case STD_T_UINT:
3398 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3399 break;
3400 case STD_T_ULL:
3401 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3402 break;
3403 case STD_T_FRQP:
3404 chunk_appendf(msg, "%d",
3405 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003406 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003407 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003408 case STD_T_DICT: {
3409 struct dict_entry *de;
3410 de = stktable_data_cast(ptr, std_t_dict);
3411 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3412 break;
3413 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003414 }
3415 }
3416 chunk_appendf(msg, "\n");
3417
Willy Tarreau06d80a92017-10-19 14:32:15 +02003418 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003419 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003420 return 0;
3421 }
3422
3423 return 1;
3424}
3425
3426
3427/* Processes a single table entry matching a specific key passed in argument.
3428 * returns 0 if wants to be called again, 1 if has ended processing.
3429 */
3430static int table_process_entry_per_key(struct appctx *appctx, char **args)
3431{
3432 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003433 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003434 struct stksess *ts;
3435 uint32_t uint32_key;
3436 unsigned char ip6_key[sizeof(struct in6_addr)];
3437 long long value;
3438 int data_type;
3439 int cur_arg;
3440 void *ptr;
3441 struct freq_ctr_period *frqp;
3442
Willy Tarreau9d008692019-08-09 11:21:01 +02003443 if (!*args[4])
3444 return cli_err(appctx, "Key value expected\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003445
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003446 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003447 case SMP_T_IPV4:
3448 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003449 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003450 break;
3451 case SMP_T_IPV6:
3452 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003453 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003454 break;
3455 case SMP_T_SINT:
3456 {
3457 char *endptr;
3458 unsigned long val;
3459 errno = 0;
3460 val = strtoul(args[4], &endptr, 10);
3461 if ((errno == ERANGE && val == ULONG_MAX) ||
3462 (errno != 0 && val == 0) || endptr == args[4] ||
Willy Tarreau9d008692019-08-09 11:21:01 +02003463 val > 0xffffffff)
3464 return cli_err(appctx, "Invalid key\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003465 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003466 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003467 break;
3468 }
3469 break;
3470 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003471 static_table_key.key = args[4];
3472 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003473 break;
3474 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003475 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003476 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003477 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 +01003478 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003479 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 +01003480 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003481 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 +01003482 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003483 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003484 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003485 }
3486
3487 /* check permissions */
3488 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3489 return 1;
3490
Willy Tarreaua24bc782016-12-14 15:50:35 +01003491 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003492 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003493 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003494 if (!ts)
3495 return 1;
3496 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003497 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3498 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003499 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003500 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003501 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003502 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003503 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003504 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_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003508 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003509 break;
3510
3511 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003512 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003513 if (!ts)
3514 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003515
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003516 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003517 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003518 return cli_err(appctx, "Entry currently in use, cannot remove\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003519 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003520 break;
3521
3522 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003523 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003524 if (!ts) {
3525 /* don't delete an entry which is currently referenced */
Willy Tarreau9d008692019-08-09 11:21:01 +02003526 return cli_err(appctx, "Unable to allocate a new entry\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003527 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003528 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003529 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3530 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003531 cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003532 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003533 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003534 return 1;
3535 }
3536
3537 data_type = stktable_get_data_type(args[cur_arg] + 5);
3538 if (data_type < 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003539 cli_err(appctx, "Unknown data type\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003540 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003541 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003542 return 1;
3543 }
3544
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003545 if (!t->data_ofs[data_type]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003546 cli_err(appctx, "Data type not stored in this table\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003547 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003548 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003549 return 1;
3550 }
3551
3552 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02003553 cli_err(appctx, "Require a valid integer value to store\n");
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003554 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003555 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003556 return 1;
3557 }
3558
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003559 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003560
3561 switch (stktable_data_types[data_type].std_type) {
3562 case STD_T_SINT:
3563 stktable_data_cast(ptr, std_t_sint) = value;
3564 break;
3565 case STD_T_UINT:
3566 stktable_data_cast(ptr, std_t_uint) = value;
3567 break;
3568 case STD_T_ULL:
3569 stktable_data_cast(ptr, std_t_ull) = value;
3570 break;
3571 case STD_T_FRQP:
3572 /* We set both the current and previous values. That way
3573 * the reported frequency is stable during all the period
3574 * then slowly fades out. This allows external tools to
3575 * push measures without having to update them too often.
3576 */
3577 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003578 /* First bit is reserved for the freq_ctr_period lock
3579 Note: here we're still protected by the stksess lock
3580 so we don't need to update the update the freq_ctr_period
3581 using its internal lock */
3582 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003583 frqp->prev_ctr = 0;
3584 frqp->curr_ctr = value;
3585 break;
3586 }
3587 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003588 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003589 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003590 break;
3591
3592 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003593 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003594 }
3595 return 1;
3596}
3597
3598/* Prepares the appctx fields with the data-based filters from the command line.
3599 * Returns 0 if the dump can proceed, 1 if has ended processing.
3600 */
3601static int table_prepare_data_request(struct appctx *appctx, char **args)
3602{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003603 int i;
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003604 char *err = NULL;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003605
Willy Tarreau9d008692019-08-09 11:21:01 +02003606 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
3607 return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003608
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003609 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
3610 if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
3611 break;
3612 /* condition on stored data value */
3613 appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
3614 if (appctx->ctx.table.data_type[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003615 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003616
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003617 if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003618 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 +01003619
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003620 appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
Willy Tarreau2b64a352020-01-22 17:09:47 +01003621 if (appctx->ctx.table.data_op[i] < 0)
Adis Nezirovicd0142e72020-01-22 16:50:27 +01003622 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 +01003623
Adis Nezirovic56dd3542020-01-22 16:16:48 +01003624 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 +01003625 return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
3626 }
3627
3628 if (*args[3+3*i]) {
3629 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 +01003630 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003631
3632 /* OK we're done, all the fields are set */
3633 return 0;
3634}
3635
3636/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003637static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003638{
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003639 int i;
3640
3641 for (i = 0; i < STKTABLE_FILTER_LEN; i++)
3642 appctx->ctx.table.data_type[i] = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003643 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003644 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003645 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003646
3647 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003648 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreau9d008692019-08-09 11:21:01 +02003649 if (!appctx->ctx.table.target)
3650 return cli_err(appctx, "No such table\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003651 }
3652 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003653 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003654 goto err_args;
3655 return 0;
3656 }
3657
3658 if (strcmp(args[3], "key") == 0)
3659 return table_process_entry_per_key(appctx, args);
3660 else if (strncmp(args[3], "data.", 5) == 0)
3661 return table_prepare_data_request(appctx, args);
3662 else if (*args[3])
3663 goto err_args;
3664
3665 return 0;
3666
3667err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003668 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003669 case STK_CLI_ACT_SHOW:
Willy Tarreau9d008692019-08-09 11:21:01 +02003670 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 +01003671 case STK_CLI_ACT_CLR:
Willy Tarreau9d008692019-08-09 11:21:01 +02003672 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 +01003673 case STK_CLI_ACT_SET:
Willy Tarreau9d008692019-08-09 11:21:01 +02003674 return cli_err(appctx, "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003675 default:
Willy Tarreau9d008692019-08-09 11:21:01 +02003676 return cli_err(appctx, "Unknown action\n");
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003677 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003678}
3679
3680/* This function is used to deal with table operations (dump or clear depending
3681 * on the action stored in appctx->private). It returns 0 if the output buffer is
3682 * full and it needs to be called again, otherwise non-zero.
3683 */
3684static int cli_io_handler_table(struct appctx *appctx)
3685{
3686 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003687 struct stream *s = si_strm(si);
3688 struct ebmb_node *eb;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003689 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003690 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003691
3692 /*
3693 * We have 3 possible states in appctx->st2 :
3694 * - STAT_ST_INIT : the first call
3695 * - STAT_ST_INFO : the proxy pointer points to the next table to
3696 * dump, the entry pointer is NULL ;
3697 * - STAT_ST_LIST : the proxy pointer points to the current table
3698 * and the entry pointer points to the next entry to be dumped,
3699 * and the refcount on the next entry is held ;
3700 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3701 * data though.
3702 */
3703
3704 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3705 /* in case of abort, remove any refcount we might have set on an entry */
3706 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003707 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003708 }
3709 return 1;
3710 }
3711
3712 chunk_reset(&trash);
3713
3714 while (appctx->st2 != STAT_ST_FIN) {
3715 switch (appctx->st2) {
3716 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003717 appctx->ctx.table.t = appctx->ctx.table.target;
3718 if (!appctx->ctx.table.t)
3719 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003720
3721 appctx->ctx.table.entry = NULL;
3722 appctx->st2 = STAT_ST_INFO;
3723 break;
3724
3725 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003726 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003727 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003728 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003729 appctx->st2 = STAT_ST_END;
3730 break;
3731 }
3732
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003733 if (appctx->ctx.table.t->size) {
3734 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003735 return 0;
3736
3737 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003738 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003739 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003740 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3741 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003742 if (eb) {
3743 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3744 appctx->ctx.table.entry->ref_cnt++;
3745 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003746 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003747 break;
3748 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003749 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003750 }
3751 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003752 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003753 break;
3754
3755 case STAT_ST_LIST:
3756 skip_entry = 0;
3757
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003758 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003759
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003760 if (appctx->ctx.table.data_type[0] >= 0) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003761 /* we're filtering on some data contents */
3762 void *ptr;
Willy Tarreau2b64a352020-01-22 17:09:47 +01003763 int dt, i;
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003764 signed char op;
3765 long long data, value;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003766
Emeric Brun819fc6f2017-06-13 19:37:32 +02003767
Willy Tarreau2b64a352020-01-22 17:09:47 +01003768 for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003769 if (appctx->ctx.table.data_type[i] == -1)
3770 break;
3771 dt = appctx->ctx.table.data_type[i];
3772 ptr = stktable_data_ptr(appctx->ctx.table.t,
3773 appctx->ctx.table.entry,
3774 dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003775
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003776 data = 0;
3777 switch (stktable_data_types[dt].std_type) {
3778 case STD_T_SINT:
3779 data = stktable_data_cast(ptr, std_t_sint);
3780 break;
3781 case STD_T_UINT:
3782 data = stktable_data_cast(ptr, std_t_uint);
3783 break;
3784 case STD_T_ULL:
3785 data = stktable_data_cast(ptr, std_t_ull);
3786 break;
3787 case STD_T_FRQP:
3788 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3789 appctx->ctx.table.t->data_arg[dt].u);
3790 break;
3791 }
3792
3793 op = appctx->ctx.table.data_op[i];
3794 value = appctx->ctx.table.value[i];
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003795
Adis Nezirovic1a693fc2020-01-16 15:19:29 +01003796 /* skip the entry if the data does not match the test and the value */
3797 if ((data < value &&
3798 (op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
3799 (data == value &&
3800 (op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
3801 (data > value &&
3802 (op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
3803 skip_entry = 1;
3804 break;
3805 }
3806 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003807 }
3808
3809 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003810 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003811 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003812 return 0;
3813 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003814
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003815 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003816
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003817 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003818 appctx->ctx.table.entry->ref_cnt--;
3819
3820 eb = ebmb_next(&appctx->ctx.table.entry->key);
3821 if (eb) {
3822 struct stksess *old = appctx->ctx.table.entry;
3823 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3824 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003825 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003826 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003827 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003828 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003829 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003830 break;
3831 }
3832
3833
3834 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003835 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003836 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003837 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003838
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003839 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003840
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003841 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003842 appctx->st2 = STAT_ST_INFO;
3843 break;
3844
3845 case STAT_ST_END:
3846 appctx->st2 = STAT_ST_FIN;
3847 break;
3848 }
3849 }
3850 return 1;
3851}
3852
3853static void cli_release_show_table(struct appctx *appctx)
3854{
3855 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003856 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003857 }
3858}
3859
3860/* register cli keywords */
3861static struct cli_kw_list cli_kws = {{ },{
3862 { { "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 },
3863 { { "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 },
3864 { { "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 },
3865 {{},}
3866}};
3867
Willy Tarreau0108d902018-11-25 19:14:37 +01003868INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003869
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003870static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003871 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003872 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003873 { "sc-set-gpt0", parse_set_gpt0, 1 },
3874 { /* END */ }
3875}};
3876
Willy Tarreau0108d902018-11-25 19:14:37 +01003877INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3878
Willy Tarreau620408f2016-10-21 16:37:51 +02003879static struct action_kw_list tcp_sess_kws = { { }, {
3880 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003881 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003882 { "sc-set-gpt0", parse_set_gpt0, 1 },
3883 { /* END */ }
3884}};
3885
Willy Tarreau0108d902018-11-25 19:14:37 +01003886INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3887
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003888static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003889 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003890 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003891 { "sc-set-gpt0", parse_set_gpt0, 1 },
3892 { /* END */ }
3893}};
3894
Willy Tarreau0108d902018-11-25 19:14:37 +01003895INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3896
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003897static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003898 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003899 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003900 { "sc-set-gpt0", parse_set_gpt0, 1 },
3901 { /* END */ }
3902}};
3903
Willy Tarreau0108d902018-11-25 19:14:37 +01003904INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3905
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003906static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003907 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003908 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003909 { "sc-set-gpt0", parse_set_gpt0, 1 },
3910 { /* END */ }
3911}};
3912
Willy Tarreau0108d902018-11-25 19:14:37 +01003913INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3914
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003915static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003916 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003917 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003918 { "sc-set-gpt0", parse_set_gpt0, 1 },
3919 { /* END */ }
3920}};
3921
Willy Tarreau0108d902018-11-25 19:14:37 +01003922INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3923
Willy Tarreau7d562212016-11-25 16:10:05 +01003924///* Note: must not be declared <const> as its list will be overwritten.
3925// * Please take care of keeping this list alphabetically sorted.
3926// */
3927//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3928// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3929// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3930// { /* END */ },
3931//}};
3932/* Note: must not be declared <const> as its list will be overwritten.
3933 * Please take care of keeping this list alphabetically sorted.
3934 */
3935static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3936 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3937 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3938 { "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 +01003939 { "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 +01003940 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3941 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3942 { "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 +01003943 { "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 +01003944 { "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 +01003945 { "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 +01003946 { "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 +01003947 { "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 +01003948 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3949 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3950 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3951 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3952 { "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 +01003953 { "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 +01003954 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3955 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3956 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3957 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3958 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3959 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3960 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3961 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3962 { "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 +01003963 { "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 +01003964 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3965 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3966 { "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 +01003967 { "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 +01003968 { "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 +01003969 { "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 +01003970 { "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 +01003971 { "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 +01003972 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3973 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3974 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3975 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3976 { "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 +01003977 { "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 +01003978 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3979 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3980 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3981 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3982 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3983 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3984 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3985 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3986 { "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 +01003987 { "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 +01003988 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3989 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3990 { "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 +01003991 { "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 +01003992 { "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 +01003993 { "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 +01003994 { "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 +01003995 { "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 +01003996 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3997 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3998 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3999 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4000 { "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 +01004001 { "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 +01004002 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4003 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4004 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4005 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4007 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4008 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4009 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4010 { "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 +01004011 { "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 +01004012 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4013 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4014 { "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 +01004015 { "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 +01004016 { "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 +01004017 { "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 +01004018 { "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 +01004019 { "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 +01004020 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4021 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4022 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4023 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4024 { "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 +01004025 { "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 +01004026 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4027 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4028 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4029 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4030 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4031 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4032 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4033 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4034 { "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 +01004035 { "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 +01004036 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4037 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4038 { "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 +01004039 { "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 +01004040 { "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 +01004041 { "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 +01004042 { "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 +01004043 { "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 +01004044 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4045 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4046 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4047 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4048 { "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 +01004049 { "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 +01004050 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4051 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4052 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4053 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4054 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4055 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4056 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4057 { /* END */ },
4058}};
4059
Willy Tarreau0108d902018-11-25 19:14:37 +01004060INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004061
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004062/* Note: must not be declared <const> as its list will be overwritten */
4063static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004064 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4065 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4066 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4067 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4068 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4069 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4070 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4071 { "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 +01004072 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004073 { "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 +01004074 { "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 +02004075 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4076 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4077 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4078 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4079 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4080 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4081 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4082 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4083 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4084 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004085 { /* END */ },
4086}};
4087
Willy Tarreau0108d902018-11-25 19:14:37 +01004088INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);