blob: 87a26e6a9f3590b05afb2e4161665db7f978a361 [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>
Thierry FOURNIER236657b2015-08-19 08:25:14 +020036#include <proto/proto_http.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/*
698 * Parse a line with <linenum> as number in <file> configuration file to configure the
699 * stick-table with <t> as address and <id> as ID.
700 * <peers> provides the "peers" section pointer only if this function is called from a "peers" section.
701 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
702 */
703int parse_stick_table(const char *file, int linenum, char **args,
704 struct stktable *t, char *id, struct peers *peers)
705{
706 int err_code = 0;
707 int idx = 1;
708 unsigned int val;
709
710 if (!id || !*id) {
711 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
712 err_code |= ERR_ALERT | ERR_ABORT;
713 goto out;
714 }
715
716 /* Store the "peers" section if this function is called from a "peers" section. */
717 if (peers) {
718 t->peers.p = peers;
719 idx++;
720 }
721
722 t->id = id;
723 t->type = (unsigned int)-1;
724 t->conf.file = file;
725 t->conf.line = linenum;
726
727 while (*args[idx]) {
728 const char *err;
729
730 if (strcmp(args[idx], "size") == 0) {
731 idx++;
732 if (!*(args[idx])) {
733 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
734 file, linenum, args[0], args[idx-1]);
735 err_code |= ERR_ALERT | ERR_FATAL;
736 goto out;
737 }
738 if ((err = parse_size_err(args[idx], &t->size))) {
739 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
740 file, linenum, args[0], *err, args[idx-1]);
741 err_code |= ERR_ALERT | ERR_FATAL;
742 goto out;
743 }
744 idx++;
745 }
746 /* This argument does not exit in "peers" section. */
747 else if (!peers && strcmp(args[idx], "peers") == 0) {
748 idx++;
749 if (!*(args[idx])) {
750 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
751 file, linenum, args[0], args[idx-1]);
752 err_code |= ERR_ALERT | ERR_FATAL;
753 goto out;
754 }
755 t->peers.name = strdup(args[idx++]);
756 }
757 else if (strcmp(args[idx], "expire") == 0) {
758 idx++;
759 if (!*(args[idx])) {
760 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
761 file, linenum, args[0], args[idx-1]);
762 err_code |= ERR_ALERT | ERR_FATAL;
763 goto out;
764 }
765 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
766 if (err) {
767 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
768 file, linenum, args[0], *err, args[idx-1]);
769 err_code |= ERR_ALERT | ERR_FATAL;
770 goto out;
771 }
772 if (val > INT_MAX) {
773 ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n",
774 file, linenum, val);
775 err_code |= ERR_ALERT | ERR_FATAL;
776 goto out;
777 }
778 t->expire = val;
779 idx++;
780 }
781 else if (strcmp(args[idx], "nopurge") == 0) {
782 t->nopurge = 1;
783 idx++;
784 }
785 else if (strcmp(args[idx], "type") == 0) {
786 idx++;
787 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
788 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
789 file, linenum, args[0], args[idx]);
790 err_code |= ERR_ALERT | ERR_FATAL;
791 goto out;
792 }
793 /* idx already points to next arg */
794 }
795 else if (strcmp(args[idx], "store") == 0) {
796 int type, err;
797 char *cw, *nw, *sa;
798
799 idx++;
800 nw = args[idx];
801 while (*nw) {
802 /* the "store" keyword supports a comma-separated list */
803 cw = nw;
804 sa = NULL; /* store arg */
805 while (*nw && *nw != ',') {
806 if (*nw == '(') {
807 *nw = 0;
808 sa = ++nw;
809 while (*nw != ')') {
810 if (!*nw) {
811 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
812 file, linenum, args[0], cw);
813 err_code |= ERR_ALERT | ERR_FATAL;
814 goto out;
815 }
816 nw++;
817 }
818 *nw = '\0';
819 }
820 nw++;
821 }
822 if (*nw)
823 *nw++ = '\0';
824 type = stktable_get_data_type(cw);
825 if (type < 0) {
826 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
827 file, linenum, args[0], cw);
828 err_code |= ERR_ALERT | ERR_FATAL;
829 goto out;
830 }
831
832 err = stktable_alloc_data_type(t, type, sa);
833 switch (err) {
834 case PE_NONE: break;
835 case PE_EXIST:
836 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
837 file, linenum, args[0], cw);
838 err_code |= ERR_WARN;
839 break;
840
841 case PE_ARG_MISSING:
842 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
843 file, linenum, args[0], cw);
844 err_code |= ERR_ALERT | ERR_FATAL;
845 goto out;
846
847 case PE_ARG_NOT_USED:
848 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
849 file, linenum, args[0], cw);
850 err_code |= ERR_ALERT | ERR_FATAL;
851 goto out;
852
853 default:
854 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
855 file, linenum, args[0], cw);
856 err_code |= ERR_ALERT | ERR_FATAL;
857 goto out;
858 }
859 }
860 idx++;
861 }
862 else {
863 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
864 file, linenum, args[0], args[idx]);
865 err_code |= ERR_ALERT | ERR_FATAL;
866 goto out;
867 }
868 }
869
870 if (!t->size) {
871 ha_alert("parsing [%s:%d] : %s: missing size.\n",
872 file, linenum, args[0]);
873 err_code |= ERR_ALERT | ERR_FATAL;
874 goto out;
875 }
876
877 if (t->type == (unsigned int)-1) {
878 ha_alert("parsing [%s:%d] : %s: missing type.\n",
879 file, linenum, args[0]);
880 err_code |= ERR_ALERT | ERR_FATAL;
881 goto out;
882 }
883
884 out:
885 return err_code;
886}
887
Willy Tarreau8fed9032014-07-03 17:02:46 +0200888/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200889 * Note that the sample *is* modified and that the returned key may point
890 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200891 * Returns NULL if the sample could not be converted (eg: no matching type),
892 * otherwise a pointer to the static stktable_key filled with what is needed
893 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200894 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200895struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200896{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200897 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200898 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200899 return NULL;
900
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200901 /* Fill static_table_key. */
902 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200903
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200904 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200905 static_table_key.key = &smp->data.u.ipv4;
906 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200907 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200908
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200909 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200910 static_table_key.key = &smp->data.u.ipv6;
911 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200912 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200913
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200914 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200915 /* The stick table require a 32bit unsigned int, "sint" is a
916 * signed 64 it, so we can convert it inplace.
917 */
918 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200919 static_table_key.key = &smp->data.u.sint;
920 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200921 break;
922
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200923 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200924 if (!smp_make_safe(smp))
925 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200926 static_table_key.key = smp->data.u.str.area;
927 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200928 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200929
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200930 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200931 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200932 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200933 if (!smp_make_rw(smp))
934 return NULL;
935
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200936 if (smp->data.u.str.size < t->key_size)
937 if (!smp_dup(smp))
938 return NULL;
939 if (smp->data.u.str.size < t->key_size)
940 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200941 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
942 t->key_size - smp->data.u.str.data);
943 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200944 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200945 static_table_key.key = smp->data.u.str.area;
946 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200947 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200948
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200949 default: /* impossible case. */
950 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200951 }
952
Christopher Fauletca20d022017-08-29 15:30:31 +0200953 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200954}
955
956/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200957 * Process a fetch + format conversion as defined by the sample expression <expr>
958 * on request or response considering the <opt> parameter. Returns either NULL if
959 * no key could be extracted, or a pointer to the converted result stored in
960 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
961 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200962 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
963 * without SMP_OPT_FINAL). The output will be usable like this :
964 *
965 * return MAY_CHANGE FINAL Meaning for the sample
966 * NULL 0 * Not present and will never be (eg: header)
967 * NULL 1 0 Not present or unstable, could change (eg: req_len)
968 * NULL 1 1 Not present, will not change anymore
969 * smp 0 * Present and will not change (eg: header)
970 * smp 1 0 not possible
971 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200972 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200973struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200974 unsigned int opt, struct sample_expr *expr, struct sample *smp)
975{
976 if (smp)
977 memset(smp, 0, sizeof(*smp));
978
Willy Tarreau192252e2015-04-04 01:47:55 +0200979 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200980 if (!smp)
981 return NULL;
982
983 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
984 return NULL; /* we can only use stable samples */
985
986 return smp_to_stkey(smp, t);
987}
988
989/*
Willy Tarreau12785782012-04-27 21:37:17 +0200990 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200991 * type <table_type>, otherwise zero. Used in configuration check.
992 */
Willy Tarreau12785782012-04-27 21:37:17 +0200993int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200994{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100995 int out_type;
996
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200997 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200998 return 0;
999
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001000 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001001
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001002 /* Convert sample. */
1003 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001004 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001005
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001006 return 1;
1007}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001008
Willy Tarreauedee1d62014-07-15 16:44:27 +02001009/* Extra data types processing : after the last one, some room may remain
1010 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1011 * at run time.
1012 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001013struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001014 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001015 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001016 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001017 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001018 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1019 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1020 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1021 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1022 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1023 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1024 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1025 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1026 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1027 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1028 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1029 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1030 [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 +01001031 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1032 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001033};
1034
Willy Tarreauedee1d62014-07-15 16:44:27 +02001035/* Registers stick-table extra data type with index <idx>, name <name>, type
1036 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1037 * index is automatically allocated. The allocated index is returned, or -1 if
1038 * no free index was found or <name> was already registered. The <name> is used
1039 * directly as a pointer, so if it's not stable, the caller must allocate it.
1040 */
1041int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1042{
1043 if (idx < 0) {
1044 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1045 if (!stktable_data_types[idx].name)
1046 break;
1047
1048 if (strcmp(stktable_data_types[idx].name, name) == 0)
1049 return -1;
1050 }
1051 }
1052
1053 if (idx >= STKTABLE_DATA_TYPES)
1054 return -1;
1055
1056 if (stktable_data_types[idx].name != NULL)
1057 return -1;
1058
1059 stktable_data_types[idx].name = name;
1060 stktable_data_types[idx].std_type = std_type;
1061 stktable_data_types[idx].arg_type = arg_type;
1062 return idx;
1063}
1064
Willy Tarreau08d5f982010-06-06 13:34:54 +02001065/*
1066 * Returns the data type number for the stktable_data_type whose name is <name>,
1067 * or <0 if not found.
1068 */
1069int stktable_get_data_type(char *name)
1070{
1071 int type;
1072
1073 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001074 if (!stktable_data_types[type].name)
1075 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001076 if (strcmp(name, stktable_data_types[type].name) == 0)
1077 return type;
1078 }
1079 return -1;
1080}
1081
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001082/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1083 * it up into this table. Returns true if found, false otherwise. The input
1084 * type is STR so that input samples are converted to string (since all types
1085 * can be converted to strings), then the function casts the string again into
1086 * the table's type. This is a double conversion, but in the future we might
1087 * support automatic input types to perform the cast on the fly.
1088 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001089static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001090{
1091 struct stktable *t;
1092 struct stktable_key *key;
1093 struct stksess *ts;
1094
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001095 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001096
1097 key = smp_to_stkey(smp, t);
1098 if (!key)
1099 return 0;
1100
1101 ts = stktable_lookup_key(t, key);
1102
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001103 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001104 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001105 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001106 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001107 return 1;
1108}
1109
1110/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1111 * it up into this table. Returns the data rate received from clients in bytes/s
1112 * if the key is present in the table, otherwise zero, so that comparisons can
1113 * be easily performed. If the inspected parameter is not stored in the table,
1114 * <not found> is returned.
1115 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001116static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001117{
1118 struct stktable *t;
1119 struct stktable_key *key;
1120 struct stksess *ts;
1121 void *ptr;
1122
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001123 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001124
1125 key = smp_to_stkey(smp, t);
1126 if (!key)
1127 return 0;
1128
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001129 ts = stktable_lookup_key(t, key);
1130
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001131 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001132 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001133 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001134
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001135 if (!ts) /* key not present */
1136 return 1;
1137
1138 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001139 if (ptr)
1140 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1141 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001142
Daniel Corbett3e60b112018-05-27 09:47:12 -04001143 stktable_release(t, ts);
1144 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001145}
1146
1147/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1148 * it up into this table. Returns the cumulated number of connections for the key
1149 * if the key is present in the table, otherwise zero, so that comparisons can
1150 * be easily performed. If the inspected parameter is not stored in the table,
1151 * <not found> is returned.
1152 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001153static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001154{
1155 struct stktable *t;
1156 struct stktable_key *key;
1157 struct stksess *ts;
1158 void *ptr;
1159
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001160 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001161
1162 key = smp_to_stkey(smp, t);
1163 if (!key)
1164 return 0;
1165
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001166 ts = stktable_lookup_key(t, key);
1167
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001168 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001169 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001170 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001171
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001172 if (!ts) /* key not present */
1173 return 1;
1174
1175 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001176 if (ptr)
1177 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001178
Daniel Corbett3e60b112018-05-27 09:47:12 -04001179 stktable_release(t, ts);
1180 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001181}
1182
1183/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1184 * it up into this table. Returns the number of concurrent connections for the
1185 * key if the key is present in the table, otherwise zero, so that comparisons
1186 * can be easily performed. If the inspected parameter is not stored in the
1187 * table, <not found> is returned.
1188 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001189static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001190{
1191 struct stktable *t;
1192 struct stktable_key *key;
1193 struct stksess *ts;
1194 void *ptr;
1195
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001196 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001197
1198 key = smp_to_stkey(smp, t);
1199 if (!key)
1200 return 0;
1201
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001202 ts = stktable_lookup_key(t, key);
1203
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001204 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001205 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001206 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001207
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001208 if (!ts) /* key not present */
1209 return 1;
1210
1211 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001212 if (ptr)
1213 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001214
Daniel Corbett3e60b112018-05-27 09:47:12 -04001215 stktable_release(t, ts);
1216 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001217}
1218
1219/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1220 * it up into this table. Returns the rate of incoming connections from the key
1221 * if the key is present in the table, otherwise zero, so that comparisons can
1222 * be easily performed. If the inspected parameter is not stored in the table,
1223 * <not found> is returned.
1224 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001225static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001226{
1227 struct stktable *t;
1228 struct stktable_key *key;
1229 struct stksess *ts;
1230 void *ptr;
1231
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001232 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001233
1234 key = smp_to_stkey(smp, t);
1235 if (!key)
1236 return 0;
1237
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001238 ts = stktable_lookup_key(t, key);
1239
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001240 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001241 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001242 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001243
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001244 if (!ts) /* key not present */
1245 return 1;
1246
1247 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001248 if (ptr)
1249 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1250 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251
Daniel Corbett3e60b112018-05-27 09:47:12 -04001252 stktable_release(t, ts);
1253 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254}
1255
1256/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1257 * it up into this table. Returns the data rate sent to clients in bytes/s
1258 * if the key is present in the table, otherwise zero, so that comparisons can
1259 * be easily performed. If the inspected parameter is not stored in the table,
1260 * <not found> is returned.
1261 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001262static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001263{
1264 struct stktable *t;
1265 struct stktable_key *key;
1266 struct stksess *ts;
1267 void *ptr;
1268
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001269 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001270
1271 key = smp_to_stkey(smp, t);
1272 if (!key)
1273 return 0;
1274
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001275 ts = stktable_lookup_key(t, key);
1276
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001277 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001278 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001279 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001280
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281 if (!ts) /* key not present */
1282 return 1;
1283
1284 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001285 if (ptr)
1286 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1287 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001288
Daniel Corbett3e60b112018-05-27 09:47:12 -04001289 stktable_release(t, ts);
1290 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001291}
1292
1293/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001294 * it up into this table. Returns the value of the GPT0 tag for the key
1295 * if the key is present in the table, otherwise false, so that comparisons can
1296 * be easily performed. If the inspected parameter is not stored in the table,
1297 * <not found> is returned.
1298 */
1299static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1300{
1301 struct stktable *t;
1302 struct stktable_key *key;
1303 struct stksess *ts;
1304 void *ptr;
1305
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001306 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001307
1308 key = smp_to_stkey(smp, t);
1309 if (!key)
1310 return 0;
1311
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001312 ts = stktable_lookup_key(t, key);
1313
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001314 smp->flags = SMP_F_VOL_TEST;
1315 smp->data.type = SMP_T_SINT;
1316 smp->data.u.sint = 0;
1317
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001318 if (!ts) /* key not present */
1319 return 1;
1320
1321 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001322 if (ptr)
1323 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001324
Daniel Corbett3e60b112018-05-27 09:47:12 -04001325 stktable_release(t, ts);
1326 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001327}
1328
1329/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001330 * it up into this table. Returns the value of the GPC0 counter for the key
1331 * if the key is present in the table, otherwise zero, so that comparisons can
1332 * be easily performed. If the inspected parameter is not stored in the table,
1333 * <not found> is returned.
1334 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001335static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001336{
1337 struct stktable *t;
1338 struct stktable_key *key;
1339 struct stksess *ts;
1340 void *ptr;
1341
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001342 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343
1344 key = smp_to_stkey(smp, t);
1345 if (!key)
1346 return 0;
1347
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001348 ts = stktable_lookup_key(t, key);
1349
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001351 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001352 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001353
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354 if (!ts) /* key not present */
1355 return 1;
1356
1357 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001358 if (ptr)
1359 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360
Daniel Corbett3e60b112018-05-27 09:47:12 -04001361 stktable_release(t, ts);
1362 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363}
1364
1365/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1366 * it up into this table. Returns the event rate of the GPC0 counter for the key
1367 * if the key is present in the table, otherwise zero, so that comparisons can
1368 * be easily performed. If the inspected parameter is not stored in the table,
1369 * <not found> is returned.
1370 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001371static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001372{
1373 struct stktable *t;
1374 struct stktable_key *key;
1375 struct stksess *ts;
1376 void *ptr;
1377
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001378 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379
1380 key = smp_to_stkey(smp, t);
1381 if (!key)
1382 return 0;
1383
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001384 ts = stktable_lookup_key(t, key);
1385
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001387 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001388 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001389
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001390 if (!ts) /* key not present */
1391 return 1;
1392
1393 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001394 if (ptr)
1395 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1396 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001397
Daniel Corbett3e60b112018-05-27 09:47:12 -04001398 stktable_release(t, ts);
1399 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400}
1401
1402/* 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 +01001403 * it up into this table. Returns the value of the GPC1 counter for the key
1404 * if the key is present in the table, otherwise zero, so that comparisons can
1405 * be easily performed. If the inspected parameter is not stored in the table,
1406 * <not found> is returned.
1407 */
1408static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1409{
1410 struct stktable *t;
1411 struct stktable_key *key;
1412 struct stksess *ts;
1413 void *ptr;
1414
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001415 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001416
1417 key = smp_to_stkey(smp, t);
1418 if (!key)
1419 return 0;
1420
1421 ts = stktable_lookup_key(t, key);
1422
1423 smp->flags = SMP_F_VOL_TEST;
1424 smp->data.type = SMP_T_SINT;
1425 smp->data.u.sint = 0;
1426
1427 if (!ts) /* key not present */
1428 return 1;
1429
1430 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001431 if (ptr)
1432 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001433
Daniel Corbett3e60b112018-05-27 09:47:12 -04001434 stktable_release(t, ts);
1435 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001436}
1437
1438/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1439 * it up into this table. Returns the event rate of the GPC1 counter for the key
1440 * if the key is present in the table, otherwise zero, so that comparisons can
1441 * be easily performed. If the inspected parameter is not stored in the table,
1442 * <not found> is returned.
1443 */
1444static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1445{
1446 struct stktable *t;
1447 struct stktable_key *key;
1448 struct stksess *ts;
1449 void *ptr;
1450
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001451 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001452
1453 key = smp_to_stkey(smp, t);
1454 if (!key)
1455 return 0;
1456
1457 ts = stktable_lookup_key(t, key);
1458
1459 smp->flags = SMP_F_VOL_TEST;
1460 smp->data.type = SMP_T_SINT;
1461 smp->data.u.sint = 0;
1462
1463 if (!ts) /* key not present */
1464 return 1;
1465
1466 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001467 if (ptr)
1468 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1469 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001470
Daniel Corbett3e60b112018-05-27 09:47:12 -04001471 stktable_release(t, ts);
1472 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001473}
1474
1475/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001476 * it up into this table. Returns the cumulated number of HTTP request errors
1477 * for the key if the key is present in the table, otherwise zero, so that
1478 * comparisons can be easily performed. If the inspected parameter is not stored
1479 * in the table, <not found> is returned.
1480 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001481static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001482{
1483 struct stktable *t;
1484 struct stktable_key *key;
1485 struct stksess *ts;
1486 void *ptr;
1487
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001488 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001489
1490 key = smp_to_stkey(smp, t);
1491 if (!key)
1492 return 0;
1493
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001494 ts = stktable_lookup_key(t, key);
1495
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001497 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001498 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001499
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001500 if (!ts) /* key not present */
1501 return 1;
1502
1503 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001504 if (ptr)
1505 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001506
Daniel Corbett3e60b112018-05-27 09:47:12 -04001507 stktable_release(t, ts);
1508 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001509}
1510
1511/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1512 * it up into this table. Returns the HTTP request error rate the key
1513 * if the key is present in the table, otherwise zero, so that comparisons can
1514 * be easily performed. If the inspected parameter is not stored in the table,
1515 * <not found> is returned.
1516 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001517static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001518{
1519 struct stktable *t;
1520 struct stktable_key *key;
1521 struct stksess *ts;
1522 void *ptr;
1523
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001524 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001525
1526 key = smp_to_stkey(smp, t);
1527 if (!key)
1528 return 0;
1529
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001530 ts = stktable_lookup_key(t, key);
1531
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001533 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001534 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001535
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001536 if (!ts) /* key not present */
1537 return 1;
1538
1539 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001540 if (ptr)
1541 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1542 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001543
Daniel Corbett3e60b112018-05-27 09:47:12 -04001544 stktable_release(t, ts);
1545 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001546}
1547
1548/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1549 * it up into this table. Returns the cumulated number of HTTP request for the
1550 * key if the key is present in the table, otherwise zero, so that comparisons
1551 * can be easily performed. If the inspected parameter is not stored in the
1552 * table, <not found> is returned.
1553 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001554static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001555{
1556 struct stktable *t;
1557 struct stktable_key *key;
1558 struct stksess *ts;
1559 void *ptr;
1560
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001561 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001562
1563 key = smp_to_stkey(smp, t);
1564 if (!key)
1565 return 0;
1566
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001567 ts = stktable_lookup_key(t, key);
1568
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001569 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001570 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001571 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001572
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001573 if (!ts) /* key not present */
1574 return 1;
1575
1576 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001577 if (ptr)
1578 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001579
Daniel Corbett3e60b112018-05-27 09:47:12 -04001580 stktable_release(t, ts);
1581 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001582}
1583
1584/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1585 * it up into this table. Returns the HTTP request rate the key if the key is
1586 * present in the table, otherwise zero, so that comparisons can be easily
1587 * performed. If the inspected parameter is not stored in the table, <not found>
1588 * is returned.
1589 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001590static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001591{
1592 struct stktable *t;
1593 struct stktable_key *key;
1594 struct stksess *ts;
1595 void *ptr;
1596
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001597 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001598
1599 key = smp_to_stkey(smp, t);
1600 if (!key)
1601 return 0;
1602
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001603 ts = stktable_lookup_key(t, key);
1604
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001605 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001606 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001607 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001608
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001609 if (!ts) /* key not present */
1610 return 1;
1611
1612 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001613 if (ptr)
1614 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1615 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001616
Daniel Corbett3e60b112018-05-27 09:47:12 -04001617 stktable_release(t, ts);
1618 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001619}
1620
1621/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1622 * it up into this table. Returns the volume of datareceived from clients in kbytes
1623 * if the key is present in the table, otherwise zero, so that comparisons can
1624 * be easily performed. If the inspected parameter is not stored in the table,
1625 * <not found> is returned.
1626 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001627static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001628{
1629 struct stktable *t;
1630 struct stktable_key *key;
1631 struct stksess *ts;
1632 void *ptr;
1633
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001634 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001635
1636 key = smp_to_stkey(smp, t);
1637 if (!key)
1638 return 0;
1639
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001640 ts = stktable_lookup_key(t, key);
1641
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001642 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001643 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001644 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001645
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001646 if (!ts) /* key not present */
1647 return 1;
1648
1649 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001650 if (ptr)
1651 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001652
Daniel Corbett3e60b112018-05-27 09:47:12 -04001653 stktable_release(t, ts);
1654 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001655}
1656
1657/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1658 * it up into this table. Returns the volume of data sent to clients in kbytes
1659 * if the key is present in the table, otherwise zero, so that comparisons can
1660 * be easily performed. If the inspected parameter is not stored in the table,
1661 * <not found> is returned.
1662 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001663static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001664{
1665 struct stktable *t;
1666 struct stktable_key *key;
1667 struct stksess *ts;
1668 void *ptr;
1669
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001670 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001671
1672 key = smp_to_stkey(smp, t);
1673 if (!key)
1674 return 0;
1675
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001676 ts = stktable_lookup_key(t, key);
1677
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001678 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001679 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001680 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001681
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001682 if (!ts) /* key not present */
1683 return 1;
1684
1685 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001686 if (ptr)
1687 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001688
Daniel Corbett3e60b112018-05-27 09:47:12 -04001689 stktable_release(t, ts);
1690 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001691}
1692
1693/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1694 * it up into this table. Returns the server ID associated with the key if the
1695 * key is present in the table, otherwise zero, so that comparisons can be
1696 * easily performed. If the inspected parameter is not stored in the table,
1697 * <not found> is returned.
1698 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001699static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001700{
1701 struct stktable *t;
1702 struct stktable_key *key;
1703 struct stksess *ts;
1704 void *ptr;
1705
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001706 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001707
1708 key = smp_to_stkey(smp, t);
1709 if (!key)
1710 return 0;
1711
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001712 ts = stktable_lookup_key(t, key);
1713
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001714 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001715 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001716 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001717
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001718 if (!ts) /* key not present */
1719 return 1;
1720
1721 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001722 if (ptr)
1723 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001724
Daniel Corbett3e60b112018-05-27 09:47:12 -04001725 stktable_release(t, ts);
1726 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001727}
1728
1729/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1730 * it up into this table. Returns the cumulated number of sessions for the
1731 * key if the key is present in the table, otherwise zero, so that comparisons
1732 * can be easily performed. If the inspected parameter is not stored in the
1733 * table, <not found> is returned.
1734 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001735static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001736{
1737 struct stktable *t;
1738 struct stktable_key *key;
1739 struct stksess *ts;
1740 void *ptr;
1741
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001742 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001743
1744 key = smp_to_stkey(smp, t);
1745 if (!key)
1746 return 0;
1747
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001748 ts = stktable_lookup_key(t, key);
1749
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001750 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001751 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001752 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001753
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001754 if (!ts) /* key not present */
1755 return 1;
1756
1757 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001758 if (ptr)
1759 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001760
Daniel Corbett3e60b112018-05-27 09:47:12 -04001761 stktable_release(t, ts);
1762 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001763}
1764
1765/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1766 * it up into this table. Returns the session rate the key if the key is
1767 * present in the table, otherwise zero, so that comparisons can be easily
1768 * performed. If the inspected parameter is not stored in the table, <not found>
1769 * is returned.
1770 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001771static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001772{
1773 struct stktable *t;
1774 struct stktable_key *key;
1775 struct stksess *ts;
1776 void *ptr;
1777
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001778 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001779
1780 key = smp_to_stkey(smp, t);
1781 if (!key)
1782 return 0;
1783
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001784 ts = stktable_lookup_key(t, key);
1785
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001786 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001787 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001788 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001789
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001790 if (!ts) /* key not present */
1791 return 1;
1792
1793 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001794 if (ptr)
1795 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1796 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001797
Daniel Corbett3e60b112018-05-27 09:47:12 -04001798 stktable_release(t, ts);
1799 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001800}
1801
1802/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1803 * it up into this table. Returns the amount of concurrent connections tracking
1804 * the same key if the key is present in the table, otherwise zero, so that
1805 * comparisons can be easily performed. If the inspected parameter is not
1806 * stored in the table, <not found> is returned.
1807 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001808static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001809{
1810 struct stktable *t;
1811 struct stktable_key *key;
1812 struct stksess *ts;
1813
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001814 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001815
1816 key = smp_to_stkey(smp, t);
1817 if (!key)
1818 return 0;
1819
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001820 ts = stktable_lookup_key(t, key);
1821
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001822 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001823 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001824 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001825
Tim Duesterhus65189c12018-06-26 15:57:29 +02001826 if (!ts)
1827 return 1;
1828
1829 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001830
Daniel Corbett3e60b112018-05-27 09:47:12 -04001831 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001832 return 1;
1833}
1834
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001835/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001836static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001837 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001838{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001839 struct stksess *ts;
1840 struct stkctr *stkctr;
1841
1842 /* Extract the stksess, return OK if no stksess available. */
1843 if (s)
1844 stkctr = &s->stkctr[rule->arg.gpc.sc];
1845 else
1846 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001847
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001848 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001849 if (ts) {
1850 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001851
Willy Tarreau79c1e912016-01-25 14:54:45 +01001852 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1853 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001854 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1855 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001856 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001857
1858 if (ptr1)
1859 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001860 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001861
Emeric Brun819fc6f2017-06-13 19:37:32 +02001862 if (ptr2)
1863 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001864
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001865 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001866
1867 /* If data was modified, we need to touch to re-schedule sync */
1868 stktable_touch_local(stkctr->table, ts, 0);
1869 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001870 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001871 return ACT_RET_CONT;
1872}
1873
1874/* This function is a common parser for using variables. It understands
1875 * the formats:
1876 *
1877 * sc-inc-gpc0(<stick-table ID>)
1878 *
1879 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1880 * it returns 1 and the variable <expr> is filled with the pointer to the
1881 * expression to execute.
1882 */
1883static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1884 struct act_rule *rule, char **err)
1885{
1886 const char *cmd_name = args[*arg-1];
1887 char *error;
1888
1889 cmd_name += strlen("sc-inc-gpc0");
1890 if (*cmd_name == '\0') {
1891 /* default stick table id. */
1892 rule->arg.gpc.sc = 0;
1893 } else {
1894 /* parse the stick table id. */
1895 if (*cmd_name != '(') {
1896 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1897 return ACT_RET_PRS_ERR;
1898 }
1899 cmd_name++; /* jump the '(' */
1900 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1901 if (*error != ')') {
1902 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1903 return ACT_RET_PRS_ERR;
1904 }
1905
1906 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1907 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1908 ACT_ACTION_TRK_SCMAX-1);
1909 return ACT_RET_PRS_ERR;
1910 }
1911 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001912 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001913 rule->action_ptr = action_inc_gpc0;
1914 return ACT_RET_PRS_OK;
1915}
1916
1917/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001918static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1919 struct session *sess, struct stream *s, int flags)
1920{
1921 struct stksess *ts;
1922 struct stkctr *stkctr;
1923
1924 /* Extract the stksess, return OK if no stksess available. */
1925 if (s)
1926 stkctr = &s->stkctr[rule->arg.gpc.sc];
1927 else
1928 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1929
1930 ts = stkctr_entry(stkctr);
1931 if (ts) {
1932 void *ptr1, *ptr2;
1933
1934 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1935 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1936 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1937 if (ptr1 || ptr2) {
1938 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1939
1940 if (ptr1)
1941 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1942 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1943
1944 if (ptr2)
1945 stktable_data_cast(ptr2, gpc1)++;
1946
1947 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1948
1949 /* If data was modified, we need to touch to re-schedule sync */
1950 stktable_touch_local(stkctr->table, ts, 0);
1951 }
1952 }
1953 return ACT_RET_CONT;
1954}
1955
1956/* This function is a common parser for using variables. It understands
1957 * the formats:
1958 *
1959 * sc-inc-gpc1(<stick-table ID>)
1960 *
1961 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1962 * it returns 1 and the variable <expr> is filled with the pointer to the
1963 * expression to execute.
1964 */
1965static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1966 struct act_rule *rule, char **err)
1967{
1968 const char *cmd_name = args[*arg-1];
1969 char *error;
1970
1971 cmd_name += strlen("sc-inc-gpc1");
1972 if (*cmd_name == '\0') {
1973 /* default stick table id. */
1974 rule->arg.gpc.sc = 0;
1975 } else {
1976 /* parse the stick table id. */
1977 if (*cmd_name != '(') {
1978 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1979 return ACT_RET_PRS_ERR;
1980 }
1981 cmd_name++; /* jump the '(' */
1982 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1983 if (*error != ')') {
1984 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1985 return ACT_RET_PRS_ERR;
1986 }
1987
1988 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1989 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1990 ACT_ACTION_TRK_SCMAX-1);
1991 return ACT_RET_PRS_ERR;
1992 }
1993 }
1994 rule->action = ACT_CUSTOM;
1995 rule->action_ptr = action_inc_gpc1;
1996 return ACT_RET_PRS_OK;
1997}
1998
1999/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002000static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002001 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002002{
2003 void *ptr;
2004 struct stksess *ts;
2005 struct stkctr *stkctr;
2006
2007 /* Extract the stksess, return OK if no stksess available. */
2008 if (s)
2009 stkctr = &s->stkctr[rule->arg.gpt.sc];
2010 else
2011 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002012
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002013 ts = stkctr_entry(stkctr);
2014 if (!ts)
2015 return ACT_RET_CONT;
2016
2017 /* Store the sample in the required sc, and ignore errors. */
2018 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002019 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002020 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002021
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002022 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002023
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002024 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002025
2026 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002027 }
2028
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002029 return ACT_RET_CONT;
2030}
2031
2032/* This function is a common parser for using variables. It understands
2033 * the format:
2034 *
2035 * set-gpt0(<stick-table ID>) <expression>
2036 *
2037 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2038 * it returns 1 and the variable <expr> is filled with the pointer to the
2039 * expression to execute.
2040 */
2041static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2042 struct act_rule *rule, char **err)
2043
2044
2045{
2046 const char *cmd_name = args[*arg-1];
2047 char *error;
2048
2049 cmd_name += strlen("sc-set-gpt0");
2050 if (*cmd_name == '\0') {
2051 /* default stick table id. */
2052 rule->arg.gpt.sc = 0;
2053 } else {
2054 /* parse the stick table id. */
2055 if (*cmd_name != '(') {
2056 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2057 return ACT_RET_PRS_ERR;
2058 }
2059 cmd_name++; /* jump the '(' */
2060 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2061 if (*error != ')') {
2062 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2063 return ACT_RET_PRS_ERR;
2064 }
2065
2066 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
2067 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2068 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
2069 return ACT_RET_PRS_ERR;
2070 }
2071 }
2072
2073 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2074 if (*error != '\0') {
2075 memprintf(err, "invalid integer value '%s'", args[*arg]);
2076 return ACT_RET_PRS_ERR;
2077 }
2078 (*arg)++;
2079
Thierry FOURNIER42148732015-09-02 17:17:33 +02002080 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002081 rule->action_ptr = action_set_gpt0;
2082
2083 return ACT_RET_PRS_OK;
2084}
2085
Willy Tarreau7d562212016-11-25 16:10:05 +01002086/* set temp integer to the number of used entries in the table pointed to by expr.
2087 * Accepts exactly 1 argument of type table.
2088 */
2089static int
2090smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2091{
2092 smp->flags = SMP_F_VOL_TEST;
2093 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002094 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002095 return 1;
2096}
2097
2098/* set temp integer to the number of free entries in the table pointed to by expr.
2099 * Accepts exactly 1 argument of type table.
2100 */
2101static int
2102smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2103{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002104 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002105
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002106 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002107 smp->flags = SMP_F_VOL_TEST;
2108 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002109 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002110 return 1;
2111}
2112
2113/* Returns a pointer to a stkctr depending on the fetch keyword name.
2114 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2115 * sc[0-9]_* will return a pointer to the respective field in the
2116 * stream <l4>. sc_* requires an UINT argument specifying the stick
2117 * counter number. src_* will fill a locally allocated structure with
2118 * the table and entry corresponding to what is specified with src_*.
2119 * NULL may be returned if the designated stkctr is not tracked. For
2120 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2121 * passed. When present, the currently tracked key is then looked up
2122 * in the specified table instead of the current table. The purpose is
2123 * to be able to convery multiple values per key (eg: have gpc0 from
2124 * multiple tables). <strm> is allowed to be NULL, in which case only
2125 * the session will be consulted.
2126 */
2127struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002128smp_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 +01002129{
Willy Tarreau7d562212016-11-25 16:10:05 +01002130 struct stkctr *stkptr;
2131 struct stksess *stksess;
2132 unsigned int num = kw[2] - '0';
2133 int arg = 0;
2134
2135 if (num == '_' - '0') {
2136 /* sc_* variant, args[0] = ctr# (mandatory) */
2137 num = args[arg++].data.sint;
2138 if (num >= MAX_SESS_STKCTR)
2139 return NULL;
2140 }
2141 else if (num > 9) { /* src_* variant, args[0] = table */
2142 struct stktable_key *key;
2143 struct connection *conn = objt_conn(sess->origin);
2144 struct sample smp;
2145
2146 if (!conn)
2147 return NULL;
2148
Joseph Herlant5662fa42018-11-15 13:43:28 -08002149 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002150 smp.px = NULL;
2151 smp.sess = sess;
2152 smp.strm = strm;
2153 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2154 return NULL;
2155
2156 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002157 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002158 if (!key)
2159 return NULL;
2160
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002161 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002162 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2163 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002164 }
2165
2166 /* Here, <num> contains the counter number from 0 to 9 for
2167 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2168 * args[arg] is the first optional argument. We first lookup the
2169 * ctr form the stream, then from the session if it was not there.
2170 */
2171
2172 if (strm)
2173 stkptr = &strm->stkctr[num];
2174 if (!strm || !stkctr_entry(stkptr)) {
2175 stkptr = &sess->stkctr[num];
2176 if (!stkctr_entry(stkptr))
2177 return NULL;
2178 }
2179
2180 stksess = stkctr_entry(stkptr);
2181 if (!stksess)
2182 return NULL;
2183
2184 if (unlikely(args[arg].type == ARGT_TAB)) {
2185 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002186 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002187 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2188 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002189 }
2190 return stkptr;
2191}
2192
2193/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2194 * the entry if it doesn't exist yet. This is needed for a few fetch
2195 * functions which need to create an entry, such as src_inc_gpc* and
2196 * src_clr_gpc*.
2197 */
2198struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002199smp_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 +01002200{
Willy Tarreau7d562212016-11-25 16:10:05 +01002201 struct stktable_key *key;
2202 struct connection *conn = objt_conn(sess->origin);
2203 struct sample smp;
2204
2205 if (strncmp(kw, "src_", 4) != 0)
2206 return NULL;
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_get_entry(stkctr->table, key));
2225 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002226}
2227
2228/* set return a boolean indicating if the requested stream counter is
2229 * currently being tracked or not.
2230 * Supports being called as "sc[0-9]_tracked" only.
2231 */
2232static int
2233smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2234{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002235 struct stkctr tmpstkctr;
2236 struct stkctr *stkctr;
2237
Willy Tarreau7d562212016-11-25 16:10:05 +01002238 smp->flags = SMP_F_VOL_TEST;
2239 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002240 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2241 smp->data.u.sint = !!stkctr;
2242
2243 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002244 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002245 stktable_release(stkctr->table, stkctr_entry(stkctr));
2246
Willy Tarreau7d562212016-11-25 16:10:05 +01002247 return 1;
2248}
2249
2250/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2251 * frontend counters or from the src.
2252 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2253 * zero is returned if the key is new.
2254 */
2255static int
2256smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2257{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002258 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002259 struct stkctr *stkctr;
2260
Emeric Brun819fc6f2017-06-13 19:37:32 +02002261 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002262 if (!stkctr)
2263 return 0;
2264
2265 smp->flags = SMP_F_VOL_TEST;
2266 smp->data.type = SMP_T_SINT;
2267 smp->data.u.sint = 0;
2268
Emeric Brun819fc6f2017-06-13 19:37:32 +02002269 if (stkctr_entry(stkctr)) {
2270 void *ptr;
2271
2272 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2273 if (!ptr) {
2274 if (stkctr == &tmpstkctr)
2275 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002276 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002277 }
2278
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002279 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002280
Willy Tarreau7d562212016-11-25 16:10:05 +01002281 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002282
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002283 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002284
2285 if (stkctr == &tmpstkctr)
2286 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002287 }
2288 return 1;
2289}
2290
2291/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2292 * frontend counters or from the src.
2293 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2294 * zero is returned if the key is new.
2295 */
2296static int
2297smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2298{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002299 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002300 struct stkctr *stkctr;
2301
Emeric Brun819fc6f2017-06-13 19:37:32 +02002302 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002303 if (!stkctr)
2304 return 0;
2305
2306 smp->flags = SMP_F_VOL_TEST;
2307 smp->data.type = SMP_T_SINT;
2308 smp->data.u.sint = 0;
2309
2310 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002311 void *ptr;
2312
2313 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2314 if (!ptr) {
2315 if (stkctr == &tmpstkctr)
2316 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002317 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002318 }
2319
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002320 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002321
Willy Tarreau7d562212016-11-25 16:10:05 +01002322 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002323
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002324 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002325
2326 if (stkctr == &tmpstkctr)
2327 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002328 }
2329 return 1;
2330}
2331
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002332/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2333 * frontend counters or from the src.
2334 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2335 * zero is returned if the key is new.
2336 */
2337static int
2338smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2339{
2340 struct stkctr tmpstkctr;
2341 struct stkctr *stkctr;
2342
2343 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2344 if (!stkctr)
2345 return 0;
2346
2347 smp->flags = SMP_F_VOL_TEST;
2348 smp->data.type = SMP_T_SINT;
2349 smp->data.u.sint = 0;
2350
2351 if (stkctr_entry(stkctr) != NULL) {
2352 void *ptr;
2353
2354 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2355 if (!ptr) {
2356 if (stkctr == &tmpstkctr)
2357 stktable_release(stkctr->table, stkctr_entry(stkctr));
2358 return 0; /* parameter not stored */
2359 }
2360
2361 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2362
2363 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2364
2365 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2366
2367 if (stkctr == &tmpstkctr)
2368 stktable_release(stkctr->table, stkctr_entry(stkctr));
2369 }
2370 return 1;
2371}
2372
Willy Tarreau7d562212016-11-25 16:10:05 +01002373/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2374 * tracked frontend counters or from the src.
2375 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2376 * Value zero is returned if the key is new.
2377 */
2378static int
2379smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2380{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002381 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002382 struct stkctr *stkctr;
2383
Emeric Brun819fc6f2017-06-13 19:37:32 +02002384 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002385 if (!stkctr)
2386 return 0;
2387
2388 smp->flags = SMP_F_VOL_TEST;
2389 smp->data.type = SMP_T_SINT;
2390 smp->data.u.sint = 0;
2391 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002392 void *ptr;
2393
2394 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2395 if (!ptr) {
2396 if (stkctr == &tmpstkctr)
2397 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002398 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002399 }
2400
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002401 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002402
Willy Tarreau7d562212016-11-25 16:10:05 +01002403 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2404 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002405
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002406 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002407
2408 if (stkctr == &tmpstkctr)
2409 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002410 }
2411 return 1;
2412}
2413
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002414/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2415 * tracked frontend counters or from the src.
2416 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2417 * Value zero is returned if the key is new.
2418 */
2419static int
2420smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2421{
2422 struct stkctr tmpstkctr;
2423 struct stkctr *stkctr;
2424
2425 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2426 if (!stkctr)
2427 return 0;
2428
2429 smp->flags = SMP_F_VOL_TEST;
2430 smp->data.type = SMP_T_SINT;
2431 smp->data.u.sint = 0;
2432 if (stkctr_entry(stkctr) != NULL) {
2433 void *ptr;
2434
2435 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2436 if (!ptr) {
2437 if (stkctr == &tmpstkctr)
2438 stktable_release(stkctr->table, stkctr_entry(stkctr));
2439 return 0; /* parameter not stored */
2440 }
2441
2442 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2443
2444 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2445 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2446
2447 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2448
2449 if (stkctr == &tmpstkctr)
2450 stktable_release(stkctr->table, stkctr_entry(stkctr));
2451 }
2452 return 1;
2453}
2454
Willy Tarreau7d562212016-11-25 16:10:05 +01002455/* Increment the General Purpose Counter 0 value from the stream's tracked
2456 * frontend counters and return it into temp integer.
2457 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2458 */
2459static int
2460smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2461{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002462 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002463 struct stkctr *stkctr;
2464
Emeric Brun819fc6f2017-06-13 19:37:32 +02002465 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002466 if (!stkctr)
2467 return 0;
2468
2469 smp->flags = SMP_F_VOL_TEST;
2470 smp->data.type = SMP_T_SINT;
2471 smp->data.u.sint = 0;
2472
Emeric Brun819fc6f2017-06-13 19:37:32 +02002473 if (!stkctr_entry(stkctr))
2474 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002475
2476 if (stkctr && stkctr_entry(stkctr)) {
2477 void *ptr1,*ptr2;
2478
Emeric Brun819fc6f2017-06-13 19:37:32 +02002479
Willy Tarreau7d562212016-11-25 16:10:05 +01002480 /* First, update gpc0_rate if it's tracked. Second, update its
2481 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2482 */
2483 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002484 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002485 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002486 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002487
Emeric Brun819fc6f2017-06-13 19:37:32 +02002488 if (ptr1) {
2489 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2490 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2491 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2492 }
2493
2494 if (ptr2)
2495 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2496
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002497 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002498
2499 /* If data was modified, we need to touch to re-schedule sync */
2500 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2501 }
2502 else if (stkctr == &tmpstkctr)
2503 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002504 }
2505 return 1;
2506}
2507
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002508/* Increment the General Purpose Counter 1 value from the stream's tracked
2509 * frontend counters and return it into temp integer.
2510 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2511 */
2512static int
2513smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2514{
2515 struct stkctr tmpstkctr;
2516 struct stkctr *stkctr;
2517
2518 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2519 if (!stkctr)
2520 return 0;
2521
2522 smp->flags = SMP_F_VOL_TEST;
2523 smp->data.type = SMP_T_SINT;
2524 smp->data.u.sint = 0;
2525
2526 if (!stkctr_entry(stkctr))
2527 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2528
2529 if (stkctr && stkctr_entry(stkctr)) {
2530 void *ptr1,*ptr2;
2531
2532
2533 /* First, update gpc1_rate if it's tracked. Second, update its
2534 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2535 */
2536 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2537 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2538 if (ptr1 || ptr2) {
2539 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2540
2541 if (ptr1) {
2542 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2543 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2544 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2545 }
2546
2547 if (ptr2)
2548 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2549
2550 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2551
2552 /* If data was modified, we need to touch to re-schedule sync */
2553 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2554 }
2555 else if (stkctr == &tmpstkctr)
2556 stktable_release(stkctr->table, stkctr_entry(stkctr));
2557 }
2558 return 1;
2559}
2560
Willy Tarreau7d562212016-11-25 16:10:05 +01002561/* Clear the General Purpose Counter 0 value from the stream's tracked
2562 * frontend counters and return its previous value into temp integer.
2563 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2564 */
2565static int
2566smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2567{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002568 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002569 struct stkctr *stkctr;
2570
Emeric Brun819fc6f2017-06-13 19:37:32 +02002571 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002572 if (!stkctr)
2573 return 0;
2574
2575 smp->flags = SMP_F_VOL_TEST;
2576 smp->data.type = SMP_T_SINT;
2577 smp->data.u.sint = 0;
2578
Emeric Brun819fc6f2017-06-13 19:37:32 +02002579 if (!stkctr_entry(stkctr))
2580 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002581
Emeric Brun819fc6f2017-06-13 19:37:32 +02002582 if (stkctr && stkctr_entry(stkctr)) {
2583 void *ptr;
2584
2585 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2586 if (!ptr) {
2587 if (stkctr == &tmpstkctr)
2588 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002589 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002590 }
2591
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002592 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002593
Willy Tarreau7d562212016-11-25 16:10:05 +01002594 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2595 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002596
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002597 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002598
Willy Tarreau7d562212016-11-25 16:10:05 +01002599 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002600 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002601 }
2602 return 1;
2603}
2604
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002605/* Clear the General Purpose Counter 1 value from the stream's tracked
2606 * frontend counters and return its previous value into temp integer.
2607 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2608 */
2609static int
2610smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2611{
2612 struct stkctr tmpstkctr;
2613 struct stkctr *stkctr;
2614
2615 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2616 if (!stkctr)
2617 return 0;
2618
2619 smp->flags = SMP_F_VOL_TEST;
2620 smp->data.type = SMP_T_SINT;
2621 smp->data.u.sint = 0;
2622
2623 if (!stkctr_entry(stkctr))
2624 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2625
2626 if (stkctr && stkctr_entry(stkctr)) {
2627 void *ptr;
2628
2629 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2630 if (!ptr) {
2631 if (stkctr == &tmpstkctr)
2632 stktable_release(stkctr->table, stkctr_entry(stkctr));
2633 return 0; /* parameter not stored */
2634 }
2635
2636 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2637
2638 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2639 stktable_data_cast(ptr, gpc1) = 0;
2640
2641 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2642
2643 /* If data was modified, we need to touch to re-schedule sync */
2644 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2645 }
2646 return 1;
2647}
2648
Willy Tarreau7d562212016-11-25 16:10:05 +01002649/* set <smp> to the cumulated number of connections from the stream's tracked
2650 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2651 * "src_conn_cnt" only.
2652 */
2653static int
2654smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2655{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002656 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002657 struct stkctr *stkctr;
2658
Emeric Brun819fc6f2017-06-13 19:37:32 +02002659 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002660 if (!stkctr)
2661 return 0;
2662
2663 smp->flags = SMP_F_VOL_TEST;
2664 smp->data.type = SMP_T_SINT;
2665 smp->data.u.sint = 0;
2666 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002667 void *ptr;
2668
2669 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2670 if (!ptr) {
2671 if (stkctr == &tmpstkctr)
2672 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002673 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002674 }
2675
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002676 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002677
Willy Tarreau7d562212016-11-25 16:10:05 +01002678 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002679
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002680 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002681
2682 if (stkctr == &tmpstkctr)
2683 stktable_release(stkctr->table, stkctr_entry(stkctr));
2684
2685
Willy Tarreau7d562212016-11-25 16:10:05 +01002686 }
2687 return 1;
2688}
2689
2690/* set <smp> to the connection rate from the stream's tracked frontend
2691 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2692 * only.
2693 */
2694static int
2695smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2696{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002697 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002698 struct stkctr *stkctr;
2699
Emeric Brun819fc6f2017-06-13 19:37:32 +02002700 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002701 if (!stkctr)
2702 return 0;
2703
2704 smp->flags = SMP_F_VOL_TEST;
2705 smp->data.type = SMP_T_SINT;
2706 smp->data.u.sint = 0;
2707 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002708 void *ptr;
2709
2710 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2711 if (!ptr) {
2712 if (stkctr == &tmpstkctr)
2713 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002714 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002715 }
2716
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002717 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002718
Willy Tarreau7d562212016-11-25 16:10:05 +01002719 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2720 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002721
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002722 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002723
2724 if (stkctr == &tmpstkctr)
2725 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002726 }
2727 return 1;
2728}
2729
2730/* set temp integer to the number of connections from the stream's source address
2731 * in the table pointed to by expr, after updating it.
2732 * Accepts exactly 1 argument of type table.
2733 */
2734static int
2735smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2736{
2737 struct connection *conn = objt_conn(smp->sess->origin);
2738 struct stksess *ts;
2739 struct stktable_key *key;
2740 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002741 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002742
2743 if (!conn)
2744 return 0;
2745
Joseph Herlant5662fa42018-11-15 13:43:28 -08002746 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002747 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2748 return 0;
2749
2750 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002751 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002752 if (!key)
2753 return 0;
2754
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002755 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002756
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002757 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002758 /* entry does not exist and could not be created */
2759 return 0;
2760
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002761 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002762 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002763 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002764 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002765
2766 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002767
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002768 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002769
Willy Tarreau7d562212016-11-25 16:10:05 +01002770 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002772 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002773
Willy Tarreau7d562212016-11-25 16:10:05 +01002774 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002775
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002776 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002777
2778 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002779 return 1;
2780}
2781
2782/* set <smp> to the number of concurrent connections from the stream's tracked
2783 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2784 * "src_conn_cur" only.
2785 */
2786static int
2787smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2788{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002789 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002790 struct stkctr *stkctr;
2791
Emeric Brun819fc6f2017-06-13 19:37:32 +02002792 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002793 if (!stkctr)
2794 return 0;
2795
2796 smp->flags = SMP_F_VOL_TEST;
2797 smp->data.type = SMP_T_SINT;
2798 smp->data.u.sint = 0;
2799 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002800 void *ptr;
2801
2802 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2803 if (!ptr) {
2804 if (stkctr == &tmpstkctr)
2805 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002806 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002807 }
2808
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002809 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002810
Willy Tarreau7d562212016-11-25 16:10:05 +01002811 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002812
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002813 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002814
2815 if (stkctr == &tmpstkctr)
2816 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002817 }
2818 return 1;
2819}
2820
2821/* set <smp> to the cumulated number of streams from the stream's tracked
2822 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2823 * "src_sess_cnt" only.
2824 */
2825static int
2826smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2827{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002828 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002829 struct stkctr *stkctr;
2830
Emeric Brun819fc6f2017-06-13 19:37:32 +02002831 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 if (!stkctr)
2833 return 0;
2834
2835 smp->flags = SMP_F_VOL_TEST;
2836 smp->data.type = SMP_T_SINT;
2837 smp->data.u.sint = 0;
2838 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002839 void *ptr;
2840
2841 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2842 if (!ptr) {
2843 if (stkctr == &tmpstkctr)
2844 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002845 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002846 }
2847
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002848 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002849
Willy Tarreau7d562212016-11-25 16:10:05 +01002850 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002851
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002852 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002853
2854 if (stkctr == &tmpstkctr)
2855 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 }
2857 return 1;
2858}
2859
2860/* set <smp> to the stream rate from the stream's tracked frontend counters.
2861 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2862 */
2863static int
2864smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2865{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002866 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002867 struct stkctr *stkctr;
2868
Emeric Brun819fc6f2017-06-13 19:37:32 +02002869 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002870 if (!stkctr)
2871 return 0;
2872
2873 smp->flags = SMP_F_VOL_TEST;
2874 smp->data.type = SMP_T_SINT;
2875 smp->data.u.sint = 0;
2876 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877 void *ptr;
2878
2879 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2880 if (!ptr) {
2881 if (stkctr == &tmpstkctr)
2882 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002883 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002884 }
2885
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002886 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002887
Willy Tarreau7d562212016-11-25 16:10:05 +01002888 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2889 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002890
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002891 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892
2893 if (stkctr == &tmpstkctr)
2894 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 }
2896 return 1;
2897}
2898
2899/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2900 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2901 * "src_http_req_cnt" only.
2902 */
2903static int
2904smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2905{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002906 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002907 struct stkctr *stkctr;
2908
Emeric Brun819fc6f2017-06-13 19:37:32 +02002909 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002910 if (!stkctr)
2911 return 0;
2912
2913 smp->flags = SMP_F_VOL_TEST;
2914 smp->data.type = SMP_T_SINT;
2915 smp->data.u.sint = 0;
2916 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002917 void *ptr;
2918
2919 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2920 if (!ptr) {
2921 if (stkctr == &tmpstkctr)
2922 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002923 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924 }
2925
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002926 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002927
Willy Tarreau7d562212016-11-25 16:10:05 +01002928 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002929
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002930 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931
2932 if (stkctr == &tmpstkctr)
2933 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002934 }
2935 return 1;
2936}
2937
2938/* set <smp> to the HTTP request rate from the stream's tracked frontend
2939 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2940 * "src_http_req_rate" only.
2941 */
2942static int
2943smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2944{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002945 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002946 struct stkctr *stkctr;
2947
Emeric Brun819fc6f2017-06-13 19:37:32 +02002948 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002949 if (!stkctr)
2950 return 0;
2951
2952 smp->flags = SMP_F_VOL_TEST;
2953 smp->data.type = SMP_T_SINT;
2954 smp->data.u.sint = 0;
2955 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956 void *ptr;
2957
2958 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2959 if (!ptr) {
2960 if (stkctr == &tmpstkctr)
2961 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002962 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002963 }
2964
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002965 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002966
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2968 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002969
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002970 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002971
2972 if (stkctr == &tmpstkctr)
2973 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002974 }
2975 return 1;
2976}
2977
2978/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2979 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2980 * "src_http_err_cnt" only.
2981 */
2982static int
2983smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2984{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002985 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002986 struct stkctr *stkctr;
2987
Emeric Brun819fc6f2017-06-13 19:37:32 +02002988 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002989 if (!stkctr)
2990 return 0;
2991
2992 smp->flags = SMP_F_VOL_TEST;
2993 smp->data.type = SMP_T_SINT;
2994 smp->data.u.sint = 0;
2995 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996 void *ptr;
2997
2998 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2999 if (!ptr) {
3000 if (stkctr == &tmpstkctr)
3001 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003002 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003003 }
3004
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003005 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006
Willy Tarreau7d562212016-11-25 16:10:05 +01003007 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003008
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003009 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010
3011 if (stkctr == &tmpstkctr)
3012 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003013 }
3014 return 1;
3015}
3016
3017/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3018 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3019 * "src_http_err_rate" only.
3020 */
3021static int
3022smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3023{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003024 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003025 struct stkctr *stkctr;
3026
Emeric Brun819fc6f2017-06-13 19:37:32 +02003027 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003028 if (!stkctr)
3029 return 0;
3030
3031 smp->flags = SMP_F_VOL_TEST;
3032 smp->data.type = SMP_T_SINT;
3033 smp->data.u.sint = 0;
3034 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003035 void *ptr;
3036
3037 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3038 if (!ptr) {
3039 if (stkctr == &tmpstkctr)
3040 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003041 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003042 }
3043
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003044 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003045
Willy Tarreau7d562212016-11-25 16:10:05 +01003046 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3047 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003048
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003049 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003050
3051 if (stkctr == &tmpstkctr)
3052 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003053 }
3054 return 1;
3055}
3056
3057/* set <smp> to the number of kbytes received from clients, as found in the
3058 * stream's tracked frontend counters. Supports being called as
3059 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3060 */
3061static int
3062smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3063{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003064 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003065 struct stkctr *stkctr;
3066
Emeric Brun819fc6f2017-06-13 19:37:32 +02003067 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003068 if (!stkctr)
3069 return 0;
3070
3071 smp->flags = SMP_F_VOL_TEST;
3072 smp->data.type = SMP_T_SINT;
3073 smp->data.u.sint = 0;
3074 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003075 void *ptr;
3076
3077 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3078 if (!ptr) {
3079 if (stkctr == &tmpstkctr)
3080 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003081 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003082 }
3083
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003084 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085
Willy Tarreau7d562212016-11-25 16:10:05 +01003086 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003087
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003088 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003089
3090 if (stkctr == &tmpstkctr)
3091 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003092 }
3093 return 1;
3094}
3095
3096/* set <smp> to the data rate received from clients in bytes/s, as found
3097 * in the stream's tracked frontend counters. Supports being called as
3098 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3099 */
3100static int
3101smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3102{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003103 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003104 struct stkctr *stkctr;
3105
Emeric Brun819fc6f2017-06-13 19:37:32 +02003106 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003107 if (!stkctr)
3108 return 0;
3109
3110 smp->flags = SMP_F_VOL_TEST;
3111 smp->data.type = SMP_T_SINT;
3112 smp->data.u.sint = 0;
3113 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114 void *ptr;
3115
3116 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3117 if (!ptr) {
3118 if (stkctr == &tmpstkctr)
3119 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003120 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003121 }
3122
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003123 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003124
Willy Tarreau7d562212016-11-25 16:10:05 +01003125 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3126 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003127
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003128 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003129
3130 if (stkctr == &tmpstkctr)
3131 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003132 }
3133 return 1;
3134}
3135
3136/* set <smp> to the number of kbytes sent to clients, as found in the
3137 * stream's tracked frontend counters. Supports being called as
3138 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3139 */
3140static int
3141smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3142{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003143 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003144 struct stkctr *stkctr;
3145
Emeric Brun819fc6f2017-06-13 19:37:32 +02003146 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003147 if (!stkctr)
3148 return 0;
3149
3150 smp->flags = SMP_F_VOL_TEST;
3151 smp->data.type = SMP_T_SINT;
3152 smp->data.u.sint = 0;
3153 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003154 void *ptr;
3155
3156 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3157 if (!ptr) {
3158 if (stkctr == &tmpstkctr)
3159 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003160 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003161 }
3162
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003163 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003164
Willy Tarreau7d562212016-11-25 16:10:05 +01003165 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003166
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003167 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003168
3169 if (stkctr == &tmpstkctr)
3170 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003171 }
3172 return 1;
3173}
3174
3175/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3176 * stream's tracked frontend counters. Supports being called as
3177 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3178 */
3179static int
3180smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3181{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003182 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003183 struct stkctr *stkctr;
3184
Emeric Brun819fc6f2017-06-13 19:37:32 +02003185 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003186 if (!stkctr)
3187 return 0;
3188
3189 smp->flags = SMP_F_VOL_TEST;
3190 smp->data.type = SMP_T_SINT;
3191 smp->data.u.sint = 0;
3192 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003193 void *ptr;
3194
3195 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3196 if (!ptr) {
3197 if (stkctr == &tmpstkctr)
3198 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003199 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003200 }
3201
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003202 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003203
Willy Tarreau7d562212016-11-25 16:10:05 +01003204 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3205 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003206
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003207 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003208
3209 if (stkctr == &tmpstkctr)
3210 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003211 }
3212 return 1;
3213}
3214
3215/* set <smp> to the number of active trackers on the SC entry in the stream's
3216 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3217 */
3218static int
3219smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3220{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003221 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003222 struct stkctr *stkctr;
3223
Emeric Brun819fc6f2017-06-13 19:37:32 +02003224 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003225 if (!stkctr)
3226 return 0;
3227
3228 smp->flags = SMP_F_VOL_TEST;
3229 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230 if (stkctr == &tmpstkctr) {
3231 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3232 stktable_release(stkctr->table, stkctr_entry(stkctr));
3233 }
3234 else {
3235 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3236 }
3237
Willy Tarreau7d562212016-11-25 16:10:05 +01003238 return 1;
3239}
3240
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003241
3242/* The functions below are used to manipulate table contents from the CLI.
3243 * There are 3 main actions, "clear", "set" and "show". The code is shared
3244 * between all actions, and the action is encoded in the void *private in
3245 * the appctx as well as in the keyword registration, among one of the
3246 * following values.
3247 */
3248
3249enum {
3250 STK_CLI_ACT_CLR,
3251 STK_CLI_ACT_SET,
3252 STK_CLI_ACT_SHOW,
3253};
3254
3255/* Dump the status of a table to a stream interface's
3256 * read buffer. It returns 0 if the output buffer is full
3257 * and needs to be called again, otherwise non-zero.
3258 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003259static int table_dump_head_to_buffer(struct buffer *msg,
3260 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003261 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003262{
3263 struct stream *s = si_strm(si);
3264
3265 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003266 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003267
3268 /* any other information should be dumped here */
3269
William Lallemand07a62f72017-05-24 00:57:40 +02003270 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003271 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3272
Willy Tarreau06d80a92017-10-19 14:32:15 +02003273 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003274 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003275 return 0;
3276 }
3277
3278 return 1;
3279}
3280
3281/* Dump a table entry to a stream interface's
3282 * read buffer. It returns 0 if the output buffer is full
3283 * and needs to be called again, otherwise non-zero.
3284 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003285static int table_dump_entry_to_buffer(struct buffer *msg,
3286 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003287 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003288{
3289 int dt;
3290
3291 chunk_appendf(msg, "%p:", entry);
3292
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003293 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003294 char addr[INET_ADDRSTRLEN];
3295 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3296 chunk_appendf(msg, " key=%s", addr);
3297 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003298 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003299 char addr[INET6_ADDRSTRLEN];
3300 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3301 chunk_appendf(msg, " key=%s", addr);
3302 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003303 else if (t->type == SMP_T_SINT) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003304 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3305 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003306 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003307 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003308 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003309 }
3310 else {
3311 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003312 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003313 }
3314
3315 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3316
3317 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3318 void *ptr;
3319
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003320 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003321 continue;
3322 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003323 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003324 else
3325 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3326
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003327 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003328 switch (stktable_data_types[dt].std_type) {
3329 case STD_T_SINT:
3330 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3331 break;
3332 case STD_T_UINT:
3333 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3334 break;
3335 case STD_T_ULL:
3336 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3337 break;
3338 case STD_T_FRQP:
3339 chunk_appendf(msg, "%d",
3340 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003341 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003342 break;
3343 }
3344 }
3345 chunk_appendf(msg, "\n");
3346
Willy Tarreau06d80a92017-10-19 14:32:15 +02003347 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003348 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003349 return 0;
3350 }
3351
3352 return 1;
3353}
3354
3355
3356/* Processes a single table entry matching a specific key passed in argument.
3357 * returns 0 if wants to be called again, 1 if has ended processing.
3358 */
3359static int table_process_entry_per_key(struct appctx *appctx, char **args)
3360{
3361 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003362 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003363 struct stksess *ts;
3364 uint32_t uint32_key;
3365 unsigned char ip6_key[sizeof(struct in6_addr)];
3366 long long value;
3367 int data_type;
3368 int cur_arg;
3369 void *ptr;
3370 struct freq_ctr_period *frqp;
3371
3372 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003373 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003374 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003375 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003376 return 1;
3377 }
3378
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003379 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003380 case SMP_T_IPV4:
3381 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003382 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003383 break;
3384 case SMP_T_IPV6:
3385 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003386 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003387 break;
3388 case SMP_T_SINT:
3389 {
3390 char *endptr;
3391 unsigned long val;
3392 errno = 0;
3393 val = strtoul(args[4], &endptr, 10);
3394 if ((errno == ERANGE && val == ULONG_MAX) ||
3395 (errno != 0 && val == 0) || endptr == args[4] ||
3396 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003397 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003398 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003399 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003400 return 1;
3401 }
3402 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003403 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003404 break;
3405 }
3406 break;
3407 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003408 static_table_key.key = args[4];
3409 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003410 break;
3411 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003412 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003413 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003414 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003415 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3416 break;
3417 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003418 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003419 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3420 break;
3421 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003422 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003423 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3424 break;
3425 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003426 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003427 appctx->ctx.cli.msg = "Unknown action\n";
3428 break;
3429 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003430 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003431 return 1;
3432 }
3433
3434 /* check permissions */
3435 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3436 return 1;
3437
Willy Tarreaua24bc782016-12-14 15:50:35 +01003438 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003439 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003440 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003441 if (!ts)
3442 return 1;
3443 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003444 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3445 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003446 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003447 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003448 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003449 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003450 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003451 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003452 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003453 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003454 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003455 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003456 break;
3457
3458 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003459 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003460 if (!ts)
3461 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003462
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003463 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003464 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003465 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003466 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003467 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003468 return 1;
3469 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003471 break;
3472
3473 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003474 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003475 if (!ts) {
3476 /* don't delete an entry which is currently referenced */
3477 appctx->ctx.cli.severity = LOG_ERR;
3478 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3479 appctx->st0 = CLI_ST_PRINT;
3480 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003481 }
3482
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003483 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003484 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3485 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003486 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003487 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003488 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003489 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003490 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003491 return 1;
3492 }
3493
3494 data_type = stktable_get_data_type(args[cur_arg] + 5);
3495 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003496 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003497 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003498 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003499 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003500 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003501 return 1;
3502 }
3503
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003504 if (!t->data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003505 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003506 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003507 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003508 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003509 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003510 return 1;
3511 }
3512
3513 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003514 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003515 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003516 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003517 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003518 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003519 return 1;
3520 }
3521
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003522 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003523
3524 switch (stktable_data_types[data_type].std_type) {
3525 case STD_T_SINT:
3526 stktable_data_cast(ptr, std_t_sint) = value;
3527 break;
3528 case STD_T_UINT:
3529 stktable_data_cast(ptr, std_t_uint) = value;
3530 break;
3531 case STD_T_ULL:
3532 stktable_data_cast(ptr, std_t_ull) = value;
3533 break;
3534 case STD_T_FRQP:
3535 /* We set both the current and previous values. That way
3536 * the reported frequency is stable during all the period
3537 * then slowly fades out. This allows external tools to
3538 * push measures without having to update them too often.
3539 */
3540 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003541 /* First bit is reserved for the freq_ctr_period lock
3542 Note: here we're still protected by the stksess lock
3543 so we don't need to update the update the freq_ctr_period
3544 using its internal lock */
3545 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003546 frqp->prev_ctr = 0;
3547 frqp->curr_ctr = value;
3548 break;
3549 }
3550 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003551 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003552 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003553 break;
3554
3555 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003556 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003557 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003558 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003559 break;
3560 }
3561 return 1;
3562}
3563
3564/* Prepares the appctx fields with the data-based filters from the command line.
3565 * Returns 0 if the dump can proceed, 1 if has ended processing.
3566 */
3567static int table_prepare_data_request(struct appctx *appctx, char **args)
3568{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003569 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003570 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003571 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003572 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003573 return 1;
3574 }
3575
3576 /* condition on stored data value */
3577 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3578 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003579 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003580 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003581 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003582 return 1;
3583 }
3584
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003585 if (!((struct proxy *)appctx->ctx.table.target)->table->data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003586 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003587 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003588 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003589 return 1;
3590 }
3591
3592 appctx->ctx.table.data_op = get_std_op(args[4]);
3593 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003594 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003595 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003596 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597 return 1;
3598 }
3599
3600 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003601 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003602 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003603 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003604 return 1;
3605 }
3606
3607 /* OK we're done, all the fields are set */
3608 return 0;
3609}
3610
3611/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003612static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003613{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003614 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003615 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003616 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003617 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003618
3619 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003620 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003621 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003622 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003623 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003624 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003625 return 1;
3626 }
3627 }
3628 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003629 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003630 goto err_args;
3631 return 0;
3632 }
3633
3634 if (strcmp(args[3], "key") == 0)
3635 return table_process_entry_per_key(appctx, args);
3636 else if (strncmp(args[3], "data.", 5) == 0)
3637 return table_prepare_data_request(appctx, args);
3638 else if (*args[3])
3639 goto err_args;
3640
3641 return 0;
3642
3643err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003644 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003645 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003646 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003647 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3648 break;
3649 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003650 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003651 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3652 break;
3653 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003654 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003655 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3656 break;
3657 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003658 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003659 appctx->ctx.cli.msg = "Unknown action\n";
3660 break;
3661 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003662 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003663 return 1;
3664}
3665
3666/* This function is used to deal with table operations (dump or clear depending
3667 * on the action stored in appctx->private). It returns 0 if the output buffer is
3668 * full and it needs to be called again, otherwise non-zero.
3669 */
3670static int cli_io_handler_table(struct appctx *appctx)
3671{
3672 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003673 struct stream *s = si_strm(si);
3674 struct ebmb_node *eb;
3675 int dt;
3676 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003677 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003678
3679 /*
3680 * We have 3 possible states in appctx->st2 :
3681 * - STAT_ST_INIT : the first call
3682 * - STAT_ST_INFO : the proxy pointer points to the next table to
3683 * dump, the entry pointer is NULL ;
3684 * - STAT_ST_LIST : the proxy pointer points to the current table
3685 * and the entry pointer points to the next entry to be dumped,
3686 * and the refcount on the next entry is held ;
3687 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3688 * data though.
3689 */
3690
3691 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3692 /* in case of abort, remove any refcount we might have set on an entry */
3693 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003694 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003695 }
3696 return 1;
3697 }
3698
3699 chunk_reset(&trash);
3700
3701 while (appctx->st2 != STAT_ST_FIN) {
3702 switch (appctx->st2) {
3703 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003704 appctx->ctx.table.t = appctx->ctx.table.target;
3705 if (!appctx->ctx.table.t)
3706 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003707
3708 appctx->ctx.table.entry = NULL;
3709 appctx->st2 = STAT_ST_INFO;
3710 break;
3711
3712 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003713 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003714 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003715 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003716 appctx->st2 = STAT_ST_END;
3717 break;
3718 }
3719
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003720 if (appctx->ctx.table.t->size) {
3721 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003722 return 0;
3723
3724 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003725 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003726 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003727 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3728 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003729 if (eb) {
3730 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3731 appctx->ctx.table.entry->ref_cnt++;
3732 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003733 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003734 break;
3735 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003736 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003737 }
3738 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003739 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003740 break;
3741
3742 case STAT_ST_LIST:
3743 skip_entry = 0;
3744
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003745 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003746
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003747 if (appctx->ctx.table.data_type >= 0) {
3748 /* we're filtering on some data contents */
3749 void *ptr;
3750 long long data;
3751
Emeric Brun819fc6f2017-06-13 19:37:32 +02003752
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003753 dt = appctx->ctx.table.data_type;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003754 ptr = stktable_data_ptr(appctx->ctx.table.t,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003755 appctx->ctx.table.entry,
3756 dt);
3757
3758 data = 0;
3759 switch (stktable_data_types[dt].std_type) {
3760 case STD_T_SINT:
3761 data = stktable_data_cast(ptr, std_t_sint);
3762 break;
3763 case STD_T_UINT:
3764 data = stktable_data_cast(ptr, std_t_uint);
3765 break;
3766 case STD_T_ULL:
3767 data = stktable_data_cast(ptr, std_t_ull);
3768 break;
3769 case STD_T_FRQP:
3770 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003771 appctx->ctx.table.t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003772 break;
3773 }
3774
3775 /* skip the entry if the data does not match the test and the value */
3776 if ((data < appctx->ctx.table.value &&
3777 (appctx->ctx.table.data_op == STD_OP_EQ ||
3778 appctx->ctx.table.data_op == STD_OP_GT ||
3779 appctx->ctx.table.data_op == STD_OP_GE)) ||
3780 (data == appctx->ctx.table.value &&
3781 (appctx->ctx.table.data_op == STD_OP_NE ||
3782 appctx->ctx.table.data_op == STD_OP_GT ||
3783 appctx->ctx.table.data_op == STD_OP_LT)) ||
3784 (data > appctx->ctx.table.value &&
3785 (appctx->ctx.table.data_op == STD_OP_EQ ||
3786 appctx->ctx.table.data_op == STD_OP_LT ||
3787 appctx->ctx.table.data_op == STD_OP_LE)))
3788 skip_entry = 1;
3789 }
3790
3791 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003792 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003793 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003794 return 0;
3795 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003796
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003797 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003798
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003799 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003800 appctx->ctx.table.entry->ref_cnt--;
3801
3802 eb = ebmb_next(&appctx->ctx.table.entry->key);
3803 if (eb) {
3804 struct stksess *old = appctx->ctx.table.entry;
3805 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3806 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003807 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003808 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003809 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003810 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003811 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003812 break;
3813 }
3814
3815
3816 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003817 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003818 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003819 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003820
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003821 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003822
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003823 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003824 appctx->st2 = STAT_ST_INFO;
3825 break;
3826
3827 case STAT_ST_END:
3828 appctx->st2 = STAT_ST_FIN;
3829 break;
3830 }
3831 }
3832 return 1;
3833}
3834
3835static void cli_release_show_table(struct appctx *appctx)
3836{
3837 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003838 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003839 }
3840}
3841
3842/* register cli keywords */
3843static struct cli_kw_list cli_kws = {{ },{
3844 { { "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 },
3845 { { "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 },
3846 { { "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 },
3847 {{},}
3848}};
3849
Willy Tarreau0108d902018-11-25 19:14:37 +01003850INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003851
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003852static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003853 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003854 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003855 { "sc-set-gpt0", parse_set_gpt0, 1 },
3856 { /* END */ }
3857}};
3858
Willy Tarreau0108d902018-11-25 19:14:37 +01003859INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3860
Willy Tarreau620408f2016-10-21 16:37:51 +02003861static struct action_kw_list tcp_sess_kws = { { }, {
3862 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003863 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003864 { "sc-set-gpt0", parse_set_gpt0, 1 },
3865 { /* END */ }
3866}};
3867
Willy Tarreau0108d902018-11-25 19:14:37 +01003868INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3869
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003870static struct action_kw_list tcp_req_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_cont_keywords_register, &tcp_req_kws);
3878
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003879static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003880 { "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 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003882 { "sc-set-gpt0", parse_set_gpt0, 1 },
3883 { /* END */ }
3884}};
3885
Willy Tarreau0108d902018-11-25 19:14:37 +01003886INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3887
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003888static struct action_kw_list http_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, http_req_keywords_register, &http_req_kws);
3896
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003897static struct action_kw_list http_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, http_res_keywords_register, &http_res_kws);
3905
Willy Tarreau7d562212016-11-25 16:10:05 +01003906///* Note: must not be declared <const> as its list will be overwritten.
3907// * Please take care of keeping this list alphabetically sorted.
3908// */
3909//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3910// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3911// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3912// { /* END */ },
3913//}};
3914/* Note: must not be declared <const> as its list will be overwritten.
3915 * Please take care of keeping this list alphabetically sorted.
3916 */
3917static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3918 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3919 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3920 { "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 +01003921 { "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 +01003922 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3923 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3924 { "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 +01003925 { "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 +01003926 { "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 +01003927 { "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 +01003928 { "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 +01003929 { "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 +01003930 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3931 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3932 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3933 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3934 { "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 +01003935 { "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 +01003936 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3937 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3938 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3939 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3940 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3941 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3942 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3943 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3944 { "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 +01003945 { "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 +01003946 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3947 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3948 { "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 +01003949 { "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 +01003950 { "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 +01003951 { "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 +01003952 { "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 +01003953 { "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 +01003954 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3955 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3956 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3957 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3958 { "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 +01003959 { "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 +01003960 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3961 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3962 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3963 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3964 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3965 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3966 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3967 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3968 { "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 +01003969 { "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 +01003970 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3971 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3972 { "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 +01003973 { "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 +01003974 { "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 +01003975 { "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 +01003976 { "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 +01003977 { "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 +01003978 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3979 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3980 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3981 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3982 { "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 +01003983 { "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 +01003984 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3985 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3986 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3987 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3988 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3989 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3990 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3991 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3992 { "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 +01003993 { "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 +01003994 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3995 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3996 { "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 +01003997 { "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 +01003998 { "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 +01003999 { "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 +01004000 { "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 +01004001 { "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 +01004002 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4003 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4004 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4005 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "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 +01004007 { "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 +01004008 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4009 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4010 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4011 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4012 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4013 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4014 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4015 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4016 { "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 +01004017 { "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 +01004018 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4019 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4020 { "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 +01004021 { "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 +01004022 { "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 +01004023 { "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 +01004024 { "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 +01004025 { "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 +01004026 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4027 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4028 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4029 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4030 { "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 +01004031 { "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 +01004032 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4033 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4034 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4035 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4036 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4037 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4038 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4039 { /* END */ },
4040}};
4041
Willy Tarreau0108d902018-11-25 19:14:37 +01004042INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004043
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004044/* Note: must not be declared <const> as its list will be overwritten */
4045static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004046 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4047 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4048 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4049 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4050 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4051 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4052 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4053 { "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 +01004054 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004055 { "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 +01004056 { "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 +02004057 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4058 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4059 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4060 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4061 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4062 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4063 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4064 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4065 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4066 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004067 { /* END */ },
4068}};
4069
Willy Tarreau0108d902018-11-25 19:14:37 +01004070INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);