blob: a555e646315728fae40eedf0fd45b3b49537b3a5 [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/*
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100698 * Parse a line with <linenum> as number in <file> configuration file to configure
699 * the stick-table with <t> as address and <id> as ID.
700 * <peers> provides the "peers" section pointer only if this function is called
701 * from a "peers" section.
702 * <nid> is the stick-table name which is sent over the network. It must be equal
703 * to <id> if this stick-table is parsed from a proxy section, and prefixed by <peers>
704 * "peers" section name followed by a '/' character if parsed from a "peers" section.
705 * This is the responsability of the caller to check this.
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100706 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
707 */
708int parse_stick_table(const char *file, int linenum, char **args,
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100709 struct stktable *t, char *id, char *nid, struct peers *peers)
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100710{
711 int err_code = 0;
712 int idx = 1;
713 unsigned int val;
714
715 if (!id || !*id) {
716 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
717 err_code |= ERR_ALERT | ERR_ABORT;
718 goto out;
719 }
720
721 /* Store the "peers" section if this function is called from a "peers" section. */
722 if (peers) {
723 t->peers.p = peers;
724 idx++;
725 }
726
727 t->id = id;
Frédéric Lécaillec02766a2019-03-20 15:06:55 +0100728 t->nid = nid;
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100729 t->type = (unsigned int)-1;
730 t->conf.file = file;
731 t->conf.line = linenum;
732
733 while (*args[idx]) {
734 const char *err;
735
736 if (strcmp(args[idx], "size") == 0) {
737 idx++;
738 if (!*(args[idx])) {
739 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
740 file, linenum, args[0], args[idx-1]);
741 err_code |= ERR_ALERT | ERR_FATAL;
742 goto out;
743 }
744 if ((err = parse_size_err(args[idx], &t->size))) {
745 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
746 file, linenum, args[0], *err, args[idx-1]);
747 err_code |= ERR_ALERT | ERR_FATAL;
748 goto out;
749 }
750 idx++;
751 }
752 /* This argument does not exit in "peers" section. */
753 else if (!peers && strcmp(args[idx], "peers") == 0) {
754 idx++;
755 if (!*(args[idx])) {
756 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
757 file, linenum, args[0], args[idx-1]);
758 err_code |= ERR_ALERT | ERR_FATAL;
759 goto out;
760 }
761 t->peers.name = strdup(args[idx++]);
762 }
763 else if (strcmp(args[idx], "expire") == 0) {
764 idx++;
765 if (!*(args[idx])) {
766 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
767 file, linenum, args[0], args[idx-1]);
768 err_code |= ERR_ALERT | ERR_FATAL;
769 goto out;
770 }
771 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
772 if (err) {
773 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
774 file, linenum, args[0], *err, args[idx-1]);
775 err_code |= ERR_ALERT | ERR_FATAL;
776 goto out;
777 }
778 if (val > INT_MAX) {
779 ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n",
780 file, linenum, val);
781 err_code |= ERR_ALERT | ERR_FATAL;
782 goto out;
783 }
784 t->expire = val;
785 idx++;
786 }
787 else if (strcmp(args[idx], "nopurge") == 0) {
788 t->nopurge = 1;
789 idx++;
790 }
791 else if (strcmp(args[idx], "type") == 0) {
792 idx++;
793 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
794 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
795 file, linenum, args[0], args[idx]);
796 err_code |= ERR_ALERT | ERR_FATAL;
797 goto out;
798 }
799 /* idx already points to next arg */
800 }
801 else if (strcmp(args[idx], "store") == 0) {
802 int type, err;
803 char *cw, *nw, *sa;
804
805 idx++;
806 nw = args[idx];
807 while (*nw) {
808 /* the "store" keyword supports a comma-separated list */
809 cw = nw;
810 sa = NULL; /* store arg */
811 while (*nw && *nw != ',') {
812 if (*nw == '(') {
813 *nw = 0;
814 sa = ++nw;
815 while (*nw != ')') {
816 if (!*nw) {
817 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
818 file, linenum, args[0], cw);
819 err_code |= ERR_ALERT | ERR_FATAL;
820 goto out;
821 }
822 nw++;
823 }
824 *nw = '\0';
825 }
826 nw++;
827 }
828 if (*nw)
829 *nw++ = '\0';
830 type = stktable_get_data_type(cw);
831 if (type < 0) {
832 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
833 file, linenum, args[0], cw);
834 err_code |= ERR_ALERT | ERR_FATAL;
835 goto out;
836 }
837
838 err = stktable_alloc_data_type(t, type, sa);
839 switch (err) {
840 case PE_NONE: break;
841 case PE_EXIST:
842 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
843 file, linenum, args[0], cw);
844 err_code |= ERR_WARN;
845 break;
846
847 case PE_ARG_MISSING:
848 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
849 file, linenum, args[0], cw);
850 err_code |= ERR_ALERT | ERR_FATAL;
851 goto out;
852
853 case PE_ARG_NOT_USED:
854 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
855 file, linenum, args[0], cw);
856 err_code |= ERR_ALERT | ERR_FATAL;
857 goto out;
858
859 default:
860 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
861 file, linenum, args[0], cw);
862 err_code |= ERR_ALERT | ERR_FATAL;
863 goto out;
864 }
865 }
866 idx++;
867 }
868 else {
869 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
870 file, linenum, args[0], args[idx]);
871 err_code |= ERR_ALERT | ERR_FATAL;
872 goto out;
873 }
874 }
875
876 if (!t->size) {
877 ha_alert("parsing [%s:%d] : %s: missing size.\n",
878 file, linenum, args[0]);
879 err_code |= ERR_ALERT | ERR_FATAL;
880 goto out;
881 }
882
883 if (t->type == (unsigned int)-1) {
884 ha_alert("parsing [%s:%d] : %s: missing type.\n",
885 file, linenum, args[0]);
886 err_code |= ERR_ALERT | ERR_FATAL;
887 goto out;
888 }
889
890 out:
891 return err_code;
892}
893
Willy Tarreau8fed9032014-07-03 17:02:46 +0200894/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200895 * Note that the sample *is* modified and that the returned key may point
896 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200897 * Returns NULL if the sample could not be converted (eg: no matching type),
898 * otherwise a pointer to the static stktable_key filled with what is needed
899 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200900 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200901struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200902{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200903 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200904 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200905 return NULL;
906
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200907 /* Fill static_table_key. */
908 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200909
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200910 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200911 static_table_key.key = &smp->data.u.ipv4;
912 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200913 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200914
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200915 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200916 static_table_key.key = &smp->data.u.ipv6;
917 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200918 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200919
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200920 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200921 /* The stick table require a 32bit unsigned int, "sint" is a
922 * signed 64 it, so we can convert it inplace.
923 */
924 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200925 static_table_key.key = &smp->data.u.sint;
926 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200927 break;
928
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200929 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200930 if (!smp_make_safe(smp))
931 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200932 static_table_key.key = smp->data.u.str.area;
933 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200934 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200935
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200936 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200937 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200938 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200939 if (!smp_make_rw(smp))
940 return NULL;
941
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200942 if (smp->data.u.str.size < t->key_size)
943 if (!smp_dup(smp))
944 return NULL;
945 if (smp->data.u.str.size < t->key_size)
946 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200947 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
948 t->key_size - smp->data.u.str.data);
949 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200950 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200951 static_table_key.key = smp->data.u.str.area;
952 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200953 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200954
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200955 default: /* impossible case. */
956 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200957 }
958
Christopher Fauletca20d022017-08-29 15:30:31 +0200959 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200960}
961
962/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200963 * Process a fetch + format conversion as defined by the sample expression <expr>
964 * on request or response considering the <opt> parameter. Returns either NULL if
965 * no key could be extracted, or a pointer to the converted result stored in
966 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
967 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200968 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
969 * without SMP_OPT_FINAL). The output will be usable like this :
970 *
971 * return MAY_CHANGE FINAL Meaning for the sample
972 * NULL 0 * Not present and will never be (eg: header)
973 * NULL 1 0 Not present or unstable, could change (eg: req_len)
974 * NULL 1 1 Not present, will not change anymore
975 * smp 0 * Present and will not change (eg: header)
976 * smp 1 0 not possible
977 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200978 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200979struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200980 unsigned int opt, struct sample_expr *expr, struct sample *smp)
981{
982 if (smp)
983 memset(smp, 0, sizeof(*smp));
984
Willy Tarreau192252e2015-04-04 01:47:55 +0200985 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200986 if (!smp)
987 return NULL;
988
989 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
990 return NULL; /* we can only use stable samples */
991
992 return smp_to_stkey(smp, t);
993}
994
995/*
Willy Tarreau12785782012-04-27 21:37:17 +0200996 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200997 * type <table_type>, otherwise zero. Used in configuration check.
998 */
Willy Tarreau12785782012-04-27 21:37:17 +0200999int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001000{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001001 int out_type;
1002
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +02001003 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001004 return 0;
1005
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001006 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001007
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +02001008 /* Convert sample. */
1009 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +01001010 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001011
Willy Tarreauf0b38bf2010-06-06 13:22:23 +02001012 return 1;
1013}
Emeric Brun3bd697e2010-01-04 15:23:48 +01001014
Willy Tarreauedee1d62014-07-15 16:44:27 +02001015/* Extra data types processing : after the last one, some room may remain
1016 * before STKTABLE_DATA_TYPES that may be used to register extra data types
1017 * at run time.
1018 */
Willy Tarreau08d5f982010-06-06 13:34:54 +02001019struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001020 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +02001021 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001022 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +02001023 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +02001024 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
1025 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1026 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
1027 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
1028 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1029 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
1030 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1031 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
1032 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1033 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
1034 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1035 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1036 [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 +01001037 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1038 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Frédéric Lécaille5ad57ea2019-05-17 10:08:29 +02001039 [STKTABLE_DT_SERVER_NAME] = { .name = "server_name", .std_type = STD_T_DICT },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001040};
1041
Willy Tarreauedee1d62014-07-15 16:44:27 +02001042/* Registers stick-table extra data type with index <idx>, name <name>, type
1043 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1044 * index is automatically allocated. The allocated index is returned, or -1 if
1045 * no free index was found or <name> was already registered. The <name> is used
1046 * directly as a pointer, so if it's not stable, the caller must allocate it.
1047 */
1048int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1049{
1050 if (idx < 0) {
1051 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1052 if (!stktable_data_types[idx].name)
1053 break;
1054
1055 if (strcmp(stktable_data_types[idx].name, name) == 0)
1056 return -1;
1057 }
1058 }
1059
1060 if (idx >= STKTABLE_DATA_TYPES)
1061 return -1;
1062
1063 if (stktable_data_types[idx].name != NULL)
1064 return -1;
1065
1066 stktable_data_types[idx].name = name;
1067 stktable_data_types[idx].std_type = std_type;
1068 stktable_data_types[idx].arg_type = arg_type;
1069 return idx;
1070}
1071
Willy Tarreau08d5f982010-06-06 13:34:54 +02001072/*
1073 * Returns the data type number for the stktable_data_type whose name is <name>,
1074 * or <0 if not found.
1075 */
1076int stktable_get_data_type(char *name)
1077{
1078 int type;
1079
1080 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001081 if (!stktable_data_types[type].name)
1082 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001083 if (strcmp(name, stktable_data_types[type].name) == 0)
1084 return type;
1085 }
1086 return -1;
1087}
1088
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001089/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1090 * it up into this table. Returns true if found, false otherwise. The input
1091 * type is STR so that input samples are converted to string (since all types
1092 * can be converted to strings), then the function casts the string again into
1093 * the table's type. This is a double conversion, but in the future we might
1094 * support automatic input types to perform the cast on the fly.
1095 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001096static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001097{
1098 struct stktable *t;
1099 struct stktable_key *key;
1100 struct stksess *ts;
1101
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001102 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001103
1104 key = smp_to_stkey(smp, t);
1105 if (!key)
1106 return 0;
1107
1108 ts = stktable_lookup_key(t, key);
1109
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001110 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001111 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001112 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001113 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001114 return 1;
1115}
1116
1117/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1118 * it up into this table. Returns the data rate received from clients in bytes/s
1119 * if the key is present in the table, otherwise zero, so that comparisons can
1120 * be easily performed. If the inspected parameter is not stored in the table,
1121 * <not found> is returned.
1122 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001123static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001124{
1125 struct stktable *t;
1126 struct stktable_key *key;
1127 struct stksess *ts;
1128 void *ptr;
1129
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001130 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001131
1132 key = smp_to_stkey(smp, t);
1133 if (!key)
1134 return 0;
1135
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001136 ts = stktable_lookup_key(t, key);
1137
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001138 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001139 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001140 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001141
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001142 if (!ts) /* key not present */
1143 return 1;
1144
1145 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001146 if (ptr)
1147 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1148 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001149
Daniel Corbett3e60b112018-05-27 09:47:12 -04001150 stktable_release(t, ts);
1151 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001152}
1153
1154/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1155 * it up into this table. Returns the cumulated number of connections for the key
1156 * if the key is present in the table, otherwise zero, so that comparisons can
1157 * be easily performed. If the inspected parameter is not stored in the table,
1158 * <not found> is returned.
1159 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001160static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001161{
1162 struct stktable *t;
1163 struct stktable_key *key;
1164 struct stksess *ts;
1165 void *ptr;
1166
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001167 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001168
1169 key = smp_to_stkey(smp, t);
1170 if (!key)
1171 return 0;
1172
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001173 ts = stktable_lookup_key(t, key);
1174
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001175 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001176 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001177 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001178
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001179 if (!ts) /* key not present */
1180 return 1;
1181
1182 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001183 if (ptr)
1184 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001185
Daniel Corbett3e60b112018-05-27 09:47:12 -04001186 stktable_release(t, ts);
1187 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001188}
1189
1190/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1191 * it up into this table. Returns the number of concurrent connections for the
1192 * key if the key is present in the table, otherwise zero, so that comparisons
1193 * can be easily performed. If the inspected parameter is not stored in the
1194 * table, <not found> is returned.
1195 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001196static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001197{
1198 struct stktable *t;
1199 struct stktable_key *key;
1200 struct stksess *ts;
1201 void *ptr;
1202
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001203 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001204
1205 key = smp_to_stkey(smp, t);
1206 if (!key)
1207 return 0;
1208
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001209 ts = stktable_lookup_key(t, key);
1210
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001211 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001212 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001213 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001214
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001215 if (!ts) /* key not present */
1216 return 1;
1217
1218 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001219 if (ptr)
1220 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001221
Daniel Corbett3e60b112018-05-27 09:47:12 -04001222 stktable_release(t, ts);
1223 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001224}
1225
1226/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1227 * it up into this table. Returns the rate of incoming connections from the key
1228 * if the key is present in the table, otherwise zero, so that comparisons can
1229 * be easily performed. If the inspected parameter is not stored in the table,
1230 * <not found> is returned.
1231 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001232static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001233{
1234 struct stktable *t;
1235 struct stktable_key *key;
1236 struct stksess *ts;
1237 void *ptr;
1238
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001239 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001240
1241 key = smp_to_stkey(smp, t);
1242 if (!key)
1243 return 0;
1244
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001245 ts = stktable_lookup_key(t, key);
1246
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001247 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001248 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001249 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001250
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251 if (!ts) /* key not present */
1252 return 1;
1253
1254 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001255 if (ptr)
1256 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1257 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001258
Daniel Corbett3e60b112018-05-27 09:47:12 -04001259 stktable_release(t, ts);
1260 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261}
1262
1263/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1264 * it up into this table. Returns the data rate sent to clients in bytes/s
1265 * if the key is present in the table, otherwise zero, so that comparisons can
1266 * be easily performed. If the inspected parameter is not stored in the table,
1267 * <not found> is returned.
1268 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001269static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001270{
1271 struct stktable *t;
1272 struct stktable_key *key;
1273 struct stksess *ts;
1274 void *ptr;
1275
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001276 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001277
1278 key = smp_to_stkey(smp, t);
1279 if (!key)
1280 return 0;
1281
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001282 ts = stktable_lookup_key(t, key);
1283
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001284 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001285 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001286 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001287
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001288 if (!ts) /* key not present */
1289 return 1;
1290
1291 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001292 if (ptr)
1293 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1294 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001295
Daniel Corbett3e60b112018-05-27 09:47:12 -04001296 stktable_release(t, ts);
1297 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001298}
1299
1300/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001301 * it up into this table. Returns the value of the GPT0 tag for the key
1302 * if the key is present in the table, otherwise false, so that comparisons can
1303 * be easily performed. If the inspected parameter is not stored in the table,
1304 * <not found> is returned.
1305 */
1306static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1307{
1308 struct stktable *t;
1309 struct stktable_key *key;
1310 struct stksess *ts;
1311 void *ptr;
1312
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001313 t = arg_p[0].data.t;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001314
1315 key = smp_to_stkey(smp, t);
1316 if (!key)
1317 return 0;
1318
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001319 ts = stktable_lookup_key(t, key);
1320
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001321 smp->flags = SMP_F_VOL_TEST;
1322 smp->data.type = SMP_T_SINT;
1323 smp->data.u.sint = 0;
1324
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001325 if (!ts) /* key not present */
1326 return 1;
1327
1328 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001329 if (ptr)
1330 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001331
Daniel Corbett3e60b112018-05-27 09:47:12 -04001332 stktable_release(t, ts);
1333 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001334}
1335
1336/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001337 * it up into this table. Returns the value of the GPC0 counter for the key
1338 * if the key is present in the table, otherwise zero, so that comparisons can
1339 * be easily performed. If the inspected parameter is not stored in the table,
1340 * <not found> is returned.
1341 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001342static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343{
1344 struct stktable *t;
1345 struct stktable_key *key;
1346 struct stksess *ts;
1347 void *ptr;
1348
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001349 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350
1351 key = smp_to_stkey(smp, t);
1352 if (!key)
1353 return 0;
1354
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001355 ts = stktable_lookup_key(t, key);
1356
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001358 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001359 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361 if (!ts) /* key not present */
1362 return 1;
1363
1364 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001365 if (ptr)
1366 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001367
Daniel Corbett3e60b112018-05-27 09:47:12 -04001368 stktable_release(t, ts);
1369 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370}
1371
1372/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1373 * it up into this table. Returns the event rate of the GPC0 counter for the key
1374 * if the key is present in the table, otherwise zero, so that comparisons can
1375 * be easily performed. If the inspected parameter is not stored in the table,
1376 * <not found> is returned.
1377 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001378static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379{
1380 struct stktable *t;
1381 struct stktable_key *key;
1382 struct stksess *ts;
1383 void *ptr;
1384
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001385 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386
1387 key = smp_to_stkey(smp, t);
1388 if (!key)
1389 return 0;
1390
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001391 ts = stktable_lookup_key(t, key);
1392
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001394 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001395 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001396
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001397 if (!ts) /* key not present */
1398 return 1;
1399
1400 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001401 if (ptr)
1402 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1403 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001404
Daniel Corbett3e60b112018-05-27 09:47:12 -04001405 stktable_release(t, ts);
1406 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001407}
1408
1409/* 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 +01001410 * it up into this table. Returns the value of the GPC1 counter for the key
1411 * if the key is present in the table, otherwise zero, so that comparisons can
1412 * be easily performed. If the inspected parameter is not stored in the table,
1413 * <not found> is returned.
1414 */
1415static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1416{
1417 struct stktable *t;
1418 struct stktable_key *key;
1419 struct stksess *ts;
1420 void *ptr;
1421
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001422 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001423
1424 key = smp_to_stkey(smp, t);
1425 if (!key)
1426 return 0;
1427
1428 ts = stktable_lookup_key(t, key);
1429
1430 smp->flags = SMP_F_VOL_TEST;
1431 smp->data.type = SMP_T_SINT;
1432 smp->data.u.sint = 0;
1433
1434 if (!ts) /* key not present */
1435 return 1;
1436
1437 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001438 if (ptr)
1439 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001440
Daniel Corbett3e60b112018-05-27 09:47:12 -04001441 stktable_release(t, ts);
1442 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001443}
1444
1445/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1446 * it up into this table. Returns the event rate of the GPC1 counter for the key
1447 * if the key is present in the table, otherwise zero, so that comparisons can
1448 * be easily performed. If the inspected parameter is not stored in the table,
1449 * <not found> is returned.
1450 */
1451static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1452{
1453 struct stktable *t;
1454 struct stktable_key *key;
1455 struct stksess *ts;
1456 void *ptr;
1457
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001458 t = arg_p[0].data.t;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001459
1460 key = smp_to_stkey(smp, t);
1461 if (!key)
1462 return 0;
1463
1464 ts = stktable_lookup_key(t, key);
1465
1466 smp->flags = SMP_F_VOL_TEST;
1467 smp->data.type = SMP_T_SINT;
1468 smp->data.u.sint = 0;
1469
1470 if (!ts) /* key not present */
1471 return 1;
1472
1473 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001474 if (ptr)
1475 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1476 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001477
Daniel Corbett3e60b112018-05-27 09:47:12 -04001478 stktable_release(t, ts);
1479 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001480}
1481
1482/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001483 * it up into this table. Returns the cumulated number of HTTP request errors
1484 * for the key if the key is present in the table, otherwise zero, so that
1485 * comparisons can be easily performed. If the inspected parameter is not stored
1486 * in the table, <not found> is returned.
1487 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001488static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001489{
1490 struct stktable *t;
1491 struct stktable_key *key;
1492 struct stksess *ts;
1493 void *ptr;
1494
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001495 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496
1497 key = smp_to_stkey(smp, t);
1498 if (!key)
1499 return 0;
1500
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001501 ts = stktable_lookup_key(t, key);
1502
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001503 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001504 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001505 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001506
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001507 if (!ts) /* key not present */
1508 return 1;
1509
1510 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001511 if (ptr)
1512 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001513
Daniel Corbett3e60b112018-05-27 09:47:12 -04001514 stktable_release(t, ts);
1515 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001516}
1517
1518/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1519 * it up into this table. Returns the HTTP request error rate the key
1520 * if the key is present in the table, otherwise zero, so that comparisons can
1521 * be easily performed. If the inspected parameter is not stored in the table,
1522 * <not found> is returned.
1523 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001524static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001525{
1526 struct stktable *t;
1527 struct stktable_key *key;
1528 struct stksess *ts;
1529 void *ptr;
1530
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001531 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532
1533 key = smp_to_stkey(smp, t);
1534 if (!key)
1535 return 0;
1536
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001537 ts = stktable_lookup_key(t, key);
1538
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001539 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001540 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001541 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001542
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001543 if (!ts) /* key not present */
1544 return 1;
1545
1546 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001547 if (ptr)
1548 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1549 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001550
Daniel Corbett3e60b112018-05-27 09:47:12 -04001551 stktable_release(t, ts);
1552 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001553}
1554
1555/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1556 * it up into this table. Returns the cumulated number of HTTP request for the
1557 * key if the key is present in the table, otherwise zero, so that comparisons
1558 * can be easily performed. If the inspected parameter is not stored in the
1559 * table, <not found> is returned.
1560 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001561static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001562{
1563 struct stktable *t;
1564 struct stktable_key *key;
1565 struct stksess *ts;
1566 void *ptr;
1567
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001568 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001569
1570 key = smp_to_stkey(smp, t);
1571 if (!key)
1572 return 0;
1573
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001574 ts = stktable_lookup_key(t, key);
1575
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001576 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001577 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001578 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001579
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001580 if (!ts) /* key not present */
1581 return 1;
1582
1583 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001584 if (ptr)
1585 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001586
Daniel Corbett3e60b112018-05-27 09:47:12 -04001587 stktable_release(t, ts);
1588 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001589}
1590
1591/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1592 * it up into this table. Returns the HTTP request rate the key if the key is
1593 * present in the table, otherwise zero, so that comparisons can be easily
1594 * performed. If the inspected parameter is not stored in the table, <not found>
1595 * is returned.
1596 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001597static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001598{
1599 struct stktable *t;
1600 struct stktable_key *key;
1601 struct stksess *ts;
1602 void *ptr;
1603
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001604 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001605
1606 key = smp_to_stkey(smp, t);
1607 if (!key)
1608 return 0;
1609
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001610 ts = stktable_lookup_key(t, key);
1611
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001612 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001613 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001614 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001615
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001616 if (!ts) /* key not present */
1617 return 1;
1618
1619 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001620 if (ptr)
1621 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1622 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001623
Daniel Corbett3e60b112018-05-27 09:47:12 -04001624 stktable_release(t, ts);
1625 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001626}
1627
1628/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1629 * it up into this table. Returns the volume of datareceived from clients in kbytes
1630 * if the key is present in the table, otherwise zero, so that comparisons can
1631 * be easily performed. If the inspected parameter is not stored in the table,
1632 * <not found> is returned.
1633 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001634static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001635{
1636 struct stktable *t;
1637 struct stktable_key *key;
1638 struct stksess *ts;
1639 void *ptr;
1640
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001641 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001642
1643 key = smp_to_stkey(smp, t);
1644 if (!key)
1645 return 0;
1646
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001647 ts = stktable_lookup_key(t, key);
1648
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001649 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001650 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001651 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001652
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001653 if (!ts) /* key not present */
1654 return 1;
1655
1656 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001657 if (ptr)
1658 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001659
Daniel Corbett3e60b112018-05-27 09:47:12 -04001660 stktable_release(t, ts);
1661 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001662}
1663
1664/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1665 * it up into this table. Returns the volume of data sent to clients in kbytes
1666 * if the key is present in the table, otherwise zero, so that comparisons can
1667 * be easily performed. If the inspected parameter is not stored in the table,
1668 * <not found> is returned.
1669 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001670static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001671{
1672 struct stktable *t;
1673 struct stktable_key *key;
1674 struct stksess *ts;
1675 void *ptr;
1676
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001677 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001678
1679 key = smp_to_stkey(smp, t);
1680 if (!key)
1681 return 0;
1682
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001683 ts = stktable_lookup_key(t, key);
1684
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001685 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001686 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001687 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001688
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001689 if (!ts) /* key not present */
1690 return 1;
1691
1692 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001693 if (ptr)
1694 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001695
Daniel Corbett3e60b112018-05-27 09:47:12 -04001696 stktable_release(t, ts);
1697 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001698}
1699
1700/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1701 * it up into this table. Returns the server ID associated with the key if the
1702 * key is present in the table, otherwise zero, so that comparisons can be
1703 * easily performed. If the inspected parameter is not stored in the table,
1704 * <not found> is returned.
1705 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001706static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001707{
1708 struct stktable *t;
1709 struct stktable_key *key;
1710 struct stksess *ts;
1711 void *ptr;
1712
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001713 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001714
1715 key = smp_to_stkey(smp, t);
1716 if (!key)
1717 return 0;
1718
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001719 ts = stktable_lookup_key(t, key);
1720
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001721 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001722 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001723 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001724
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001725 if (!ts) /* key not present */
1726 return 1;
1727
1728 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001729 if (ptr)
1730 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001731
Daniel Corbett3e60b112018-05-27 09:47:12 -04001732 stktable_release(t, ts);
1733 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001734}
1735
1736/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1737 * it up into this table. Returns the cumulated number of sessions for the
1738 * key if the key is present in the table, otherwise zero, so that comparisons
1739 * can be easily performed. If the inspected parameter is not stored in the
1740 * table, <not found> is returned.
1741 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001742static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001743{
1744 struct stktable *t;
1745 struct stktable_key *key;
1746 struct stksess *ts;
1747 void *ptr;
1748
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001749 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001750
1751 key = smp_to_stkey(smp, t);
1752 if (!key)
1753 return 0;
1754
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001755 ts = stktable_lookup_key(t, key);
1756
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001757 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001758 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001759 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001760
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001761 if (!ts) /* key not present */
1762 return 1;
1763
1764 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001765 if (ptr)
1766 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001767
Daniel Corbett3e60b112018-05-27 09:47:12 -04001768 stktable_release(t, ts);
1769 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001770}
1771
1772/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1773 * it up into this table. Returns the session rate the key if the key is
1774 * present in the table, otherwise zero, so that comparisons can be easily
1775 * performed. If the inspected parameter is not stored in the table, <not found>
1776 * is returned.
1777 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001778static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001779{
1780 struct stktable *t;
1781 struct stktable_key *key;
1782 struct stksess *ts;
1783 void *ptr;
1784
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001785 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001786
1787 key = smp_to_stkey(smp, t);
1788 if (!key)
1789 return 0;
1790
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001791 ts = stktable_lookup_key(t, key);
1792
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001793 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001794 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001795 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001796
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001797 if (!ts) /* key not present */
1798 return 1;
1799
1800 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001801 if (ptr)
1802 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1803 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001804
Daniel Corbett3e60b112018-05-27 09:47:12 -04001805 stktable_release(t, ts);
1806 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001807}
1808
1809/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1810 * it up into this table. Returns the amount of concurrent connections tracking
1811 * the same key if the key is present in the table, otherwise zero, so that
1812 * comparisons can be easily performed. If the inspected parameter is not
1813 * stored in the table, <not found> is returned.
1814 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001815static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001816{
1817 struct stktable *t;
1818 struct stktable_key *key;
1819 struct stksess *ts;
1820
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01001821 t = arg_p[0].data.t;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001822
1823 key = smp_to_stkey(smp, t);
1824 if (!key)
1825 return 0;
1826
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001827 ts = stktable_lookup_key(t, key);
1828
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001829 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001830 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001831 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001832
Tim Duesterhus65189c12018-06-26 15:57:29 +02001833 if (!ts)
1834 return 1;
1835
1836 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001837
Daniel Corbett3e60b112018-05-27 09:47:12 -04001838 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001839 return 1;
1840}
1841
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001842/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001843static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001844 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001845{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001846 struct stksess *ts;
1847 struct stkctr *stkctr;
1848
1849 /* Extract the stksess, return OK if no stksess available. */
1850 if (s)
1851 stkctr = &s->stkctr[rule->arg.gpc.sc];
1852 else
1853 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001854
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001855 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001856 if (ts) {
1857 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001858
Willy Tarreau79c1e912016-01-25 14:54:45 +01001859 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1860 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001861 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1862 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001863 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001864
1865 if (ptr1)
1866 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001867 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001868
Emeric Brun819fc6f2017-06-13 19:37:32 +02001869 if (ptr2)
1870 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001871
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001872 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001873
1874 /* If data was modified, we need to touch to re-schedule sync */
1875 stktable_touch_local(stkctr->table, ts, 0);
1876 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001877 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001878 return ACT_RET_CONT;
1879}
1880
1881/* This function is a common parser for using variables. It understands
1882 * the formats:
1883 *
1884 * sc-inc-gpc0(<stick-table ID>)
1885 *
1886 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1887 * it returns 1 and the variable <expr> is filled with the pointer to the
1888 * expression to execute.
1889 */
1890static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1891 struct act_rule *rule, char **err)
1892{
1893 const char *cmd_name = args[*arg-1];
1894 char *error;
1895
1896 cmd_name += strlen("sc-inc-gpc0");
1897 if (*cmd_name == '\0') {
1898 /* default stick table id. */
1899 rule->arg.gpc.sc = 0;
1900 } else {
1901 /* parse the stick table id. */
1902 if (*cmd_name != '(') {
1903 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1904 return ACT_RET_PRS_ERR;
1905 }
1906 cmd_name++; /* jump the '(' */
1907 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1908 if (*error != ')') {
1909 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1910 return ACT_RET_PRS_ERR;
1911 }
1912
1913 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1914 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1915 ACT_ACTION_TRK_SCMAX-1);
1916 return ACT_RET_PRS_ERR;
1917 }
1918 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001919 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001920 rule->action_ptr = action_inc_gpc0;
1921 return ACT_RET_PRS_OK;
1922}
1923
1924/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001925static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1926 struct session *sess, struct stream *s, int flags)
1927{
1928 struct stksess *ts;
1929 struct stkctr *stkctr;
1930
1931 /* Extract the stksess, return OK if no stksess available. */
1932 if (s)
1933 stkctr = &s->stkctr[rule->arg.gpc.sc];
1934 else
1935 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1936
1937 ts = stkctr_entry(stkctr);
1938 if (ts) {
1939 void *ptr1, *ptr2;
1940
1941 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1942 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1943 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1944 if (ptr1 || ptr2) {
1945 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1946
1947 if (ptr1)
1948 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1949 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1950
1951 if (ptr2)
1952 stktable_data_cast(ptr2, gpc1)++;
1953
1954 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1955
1956 /* If data was modified, we need to touch to re-schedule sync */
1957 stktable_touch_local(stkctr->table, ts, 0);
1958 }
1959 }
1960 return ACT_RET_CONT;
1961}
1962
1963/* This function is a common parser for using variables. It understands
1964 * the formats:
1965 *
1966 * sc-inc-gpc1(<stick-table ID>)
1967 *
1968 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1969 * it returns 1 and the variable <expr> is filled with the pointer to the
1970 * expression to execute.
1971 */
1972static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1973 struct act_rule *rule, char **err)
1974{
1975 const char *cmd_name = args[*arg-1];
1976 char *error;
1977
1978 cmd_name += strlen("sc-inc-gpc1");
1979 if (*cmd_name == '\0') {
1980 /* default stick table id. */
1981 rule->arg.gpc.sc = 0;
1982 } else {
1983 /* parse the stick table id. */
1984 if (*cmd_name != '(') {
1985 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1986 return ACT_RET_PRS_ERR;
1987 }
1988 cmd_name++; /* jump the '(' */
1989 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1990 if (*error != ')') {
1991 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1992 return ACT_RET_PRS_ERR;
1993 }
1994
1995 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1996 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1997 ACT_ACTION_TRK_SCMAX-1);
1998 return ACT_RET_PRS_ERR;
1999 }
2000 }
2001 rule->action = ACT_CUSTOM;
2002 rule->action_ptr = action_inc_gpc1;
2003 return ACT_RET_PRS_OK;
2004}
2005
2006/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002007static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02002008 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002009{
2010 void *ptr;
2011 struct stksess *ts;
2012 struct stkctr *stkctr;
2013
2014 /* Extract the stksess, return OK if no stksess available. */
2015 if (s)
2016 stkctr = &s->stkctr[rule->arg.gpt.sc];
2017 else
2018 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01002019
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002020 ts = stkctr_entry(stkctr);
2021 if (!ts)
2022 return ACT_RET_CONT;
2023
2024 /* Store the sample in the required sc, and ignore errors. */
2025 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002026 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002027 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002028
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002029 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002030
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002031 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002032
2033 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01002034 }
2035
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002036 return ACT_RET_CONT;
2037}
2038
2039/* This function is a common parser for using variables. It understands
2040 * the format:
2041 *
2042 * set-gpt0(<stick-table ID>) <expression>
2043 *
2044 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2045 * it returns 1 and the variable <expr> is filled with the pointer to the
2046 * expression to execute.
2047 */
2048static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2049 struct act_rule *rule, char **err)
2050
2051
2052{
2053 const char *cmd_name = args[*arg-1];
2054 char *error;
2055
2056 cmd_name += strlen("sc-set-gpt0");
2057 if (*cmd_name == '\0') {
2058 /* default stick table id. */
2059 rule->arg.gpt.sc = 0;
2060 } else {
2061 /* parse the stick table id. */
2062 if (*cmd_name != '(') {
2063 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2064 return ACT_RET_PRS_ERR;
2065 }
2066 cmd_name++; /* jump the '(' */
2067 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2068 if (*error != ')') {
2069 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2070 return ACT_RET_PRS_ERR;
2071 }
2072
2073 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
2074 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2075 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
2076 return ACT_RET_PRS_ERR;
2077 }
2078 }
2079
2080 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2081 if (*error != '\0') {
2082 memprintf(err, "invalid integer value '%s'", args[*arg]);
2083 return ACT_RET_PRS_ERR;
2084 }
2085 (*arg)++;
2086
Thierry FOURNIER42148732015-09-02 17:17:33 +02002087 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002088 rule->action_ptr = action_set_gpt0;
2089
2090 return ACT_RET_PRS_OK;
2091}
2092
Willy Tarreau7d562212016-11-25 16:10:05 +01002093/* set temp integer to the number of used entries in the table pointed to by expr.
2094 * Accepts exactly 1 argument of type table.
2095 */
2096static int
2097smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2098{
2099 smp->flags = SMP_F_VOL_TEST;
2100 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002101 smp->data.u.sint = args->data.t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002102 return 1;
2103}
2104
2105/* set temp integer to the number of free entries in the table pointed to by expr.
2106 * Accepts exactly 1 argument of type table.
2107 */
2108static int
2109smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2110{
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002111 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002112
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002113 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002114 smp->flags = SMP_F_VOL_TEST;
2115 smp->data.type = SMP_T_SINT;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002116 smp->data.u.sint = t->size - t->current;
Willy Tarreau7d562212016-11-25 16:10:05 +01002117 return 1;
2118}
2119
2120/* Returns a pointer to a stkctr depending on the fetch keyword name.
2121 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2122 * sc[0-9]_* will return a pointer to the respective field in the
2123 * stream <l4>. sc_* requires an UINT argument specifying the stick
2124 * counter number. src_* will fill a locally allocated structure with
2125 * the table and entry corresponding to what is specified with src_*.
2126 * NULL may be returned if the designated stkctr is not tracked. For
2127 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2128 * passed. When present, the currently tracked key is then looked up
2129 * in the specified table instead of the current table. The purpose is
2130 * to be able to convery multiple values per key (eg: have gpc0 from
2131 * multiple tables). <strm> is allowed to be NULL, in which case only
2132 * the session will be consulted.
2133 */
2134struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002135smp_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 +01002136{
Willy Tarreau7d562212016-11-25 16:10:05 +01002137 struct stkctr *stkptr;
2138 struct stksess *stksess;
2139 unsigned int num = kw[2] - '0';
2140 int arg = 0;
2141
2142 if (num == '_' - '0') {
2143 /* sc_* variant, args[0] = ctr# (mandatory) */
2144 num = args[arg++].data.sint;
2145 if (num >= MAX_SESS_STKCTR)
2146 return NULL;
2147 }
2148 else if (num > 9) { /* src_* variant, args[0] = table */
2149 struct stktable_key *key;
2150 struct connection *conn = objt_conn(sess->origin);
2151 struct sample smp;
2152
2153 if (!conn)
2154 return NULL;
2155
Joseph Herlant5662fa42018-11-15 13:43:28 -08002156 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002157 smp.px = NULL;
2158 smp.sess = sess;
2159 smp.strm = strm;
2160 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2161 return NULL;
2162
2163 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002164 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002165 if (!key)
2166 return NULL;
2167
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002168 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002169 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2170 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002171 }
2172
2173 /* Here, <num> contains the counter number from 0 to 9 for
2174 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2175 * args[arg] is the first optional argument. We first lookup the
2176 * ctr form the stream, then from the session if it was not there.
2177 */
2178
2179 if (strm)
2180 stkptr = &strm->stkctr[num];
2181 if (!strm || !stkctr_entry(stkptr)) {
2182 stkptr = &sess->stkctr[num];
2183 if (!stkctr_entry(stkptr))
2184 return NULL;
2185 }
2186
2187 stksess = stkctr_entry(stkptr);
2188 if (!stksess)
2189 return NULL;
2190
2191 if (unlikely(args[arg].type == ARGT_TAB)) {
2192 /* an alternate table was specified, let's look up the same key there */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002193 stkctr->table = args[arg].data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002194 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2195 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002196 }
2197 return stkptr;
2198}
2199
2200/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2201 * the entry if it doesn't exist yet. This is needed for a few fetch
2202 * functions which need to create an entry, such as src_inc_gpc* and
2203 * src_clr_gpc*.
2204 */
2205struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002206smp_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 +01002207{
Willy Tarreau7d562212016-11-25 16:10:05 +01002208 struct stktable_key *key;
2209 struct connection *conn = objt_conn(sess->origin);
2210 struct sample smp;
2211
2212 if (strncmp(kw, "src_", 4) != 0)
2213 return NULL;
2214
2215 if (!conn)
2216 return NULL;
2217
Joseph Herlant5662fa42018-11-15 13:43:28 -08002218 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002219 smp.px = NULL;
2220 smp.sess = sess;
2221 smp.strm = strm;
2222 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2223 return NULL;
2224
2225 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002226 key = smp_to_stkey(&smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002227 if (!key)
2228 return NULL;
2229
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002230 stkctr->table = args->data.t;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002231 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2232 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002233}
2234
2235/* set return a boolean indicating if the requested stream counter is
2236 * currently being tracked or not.
2237 * Supports being called as "sc[0-9]_tracked" only.
2238 */
2239static int
2240smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2241{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002242 struct stkctr tmpstkctr;
2243 struct stkctr *stkctr;
2244
Willy Tarreau7d562212016-11-25 16:10:05 +01002245 smp->flags = SMP_F_VOL_TEST;
2246 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002247 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2248 smp->data.u.sint = !!stkctr;
2249
2250 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002251 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002252 stktable_release(stkctr->table, stkctr_entry(stkctr));
2253
Willy Tarreau7d562212016-11-25 16:10:05 +01002254 return 1;
2255}
2256
2257/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2258 * frontend counters or from the src.
2259 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2260 * zero is returned if the key is new.
2261 */
2262static int
2263smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2264{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002265 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002266 struct stkctr *stkctr;
2267
Emeric Brun819fc6f2017-06-13 19:37:32 +02002268 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002269 if (!stkctr)
2270 return 0;
2271
2272 smp->flags = SMP_F_VOL_TEST;
2273 smp->data.type = SMP_T_SINT;
2274 smp->data.u.sint = 0;
2275
Emeric Brun819fc6f2017-06-13 19:37:32 +02002276 if (stkctr_entry(stkctr)) {
2277 void *ptr;
2278
2279 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2280 if (!ptr) {
2281 if (stkctr == &tmpstkctr)
2282 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002283 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002284 }
2285
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002286 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002287
Willy Tarreau7d562212016-11-25 16:10:05 +01002288 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002289
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002290 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002291
2292 if (stkctr == &tmpstkctr)
2293 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002294 }
2295 return 1;
2296}
2297
2298/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2299 * frontend counters or from the src.
2300 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2301 * zero is returned if the key is new.
2302 */
2303static int
2304smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2305{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002306 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002307 struct stkctr *stkctr;
2308
Emeric Brun819fc6f2017-06-13 19:37:32 +02002309 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002310 if (!stkctr)
2311 return 0;
2312
2313 smp->flags = SMP_F_VOL_TEST;
2314 smp->data.type = SMP_T_SINT;
2315 smp->data.u.sint = 0;
2316
2317 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002318 void *ptr;
2319
2320 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2321 if (!ptr) {
2322 if (stkctr == &tmpstkctr)
2323 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002324 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002325 }
2326
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002327 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002328
Willy Tarreau7d562212016-11-25 16:10:05 +01002329 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002330
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002331 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002332
2333 if (stkctr == &tmpstkctr)
2334 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002335 }
2336 return 1;
2337}
2338
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002339/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2340 * frontend counters or from the src.
2341 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2342 * zero is returned if the key is new.
2343 */
2344static int
2345smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2346{
2347 struct stkctr tmpstkctr;
2348 struct stkctr *stkctr;
2349
2350 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2351 if (!stkctr)
2352 return 0;
2353
2354 smp->flags = SMP_F_VOL_TEST;
2355 smp->data.type = SMP_T_SINT;
2356 smp->data.u.sint = 0;
2357
2358 if (stkctr_entry(stkctr) != NULL) {
2359 void *ptr;
2360
2361 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2362 if (!ptr) {
2363 if (stkctr == &tmpstkctr)
2364 stktable_release(stkctr->table, stkctr_entry(stkctr));
2365 return 0; /* parameter not stored */
2366 }
2367
2368 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2369
2370 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2371
2372 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2373
2374 if (stkctr == &tmpstkctr)
2375 stktable_release(stkctr->table, stkctr_entry(stkctr));
2376 }
2377 return 1;
2378}
2379
Willy Tarreau7d562212016-11-25 16:10:05 +01002380/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2381 * tracked frontend counters or from the src.
2382 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2383 * Value zero is returned if the key is new.
2384 */
2385static int
2386smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2387{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002388 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002389 struct stkctr *stkctr;
2390
Emeric Brun819fc6f2017-06-13 19:37:32 +02002391 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002392 if (!stkctr)
2393 return 0;
2394
2395 smp->flags = SMP_F_VOL_TEST;
2396 smp->data.type = SMP_T_SINT;
2397 smp->data.u.sint = 0;
2398 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002399 void *ptr;
2400
2401 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2402 if (!ptr) {
2403 if (stkctr == &tmpstkctr)
2404 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002405 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002406 }
2407
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002408 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002409
Willy Tarreau7d562212016-11-25 16:10:05 +01002410 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2411 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002412
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002413 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002414
2415 if (stkctr == &tmpstkctr)
2416 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002417 }
2418 return 1;
2419}
2420
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002421/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2422 * tracked frontend counters or from the src.
2423 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2424 * Value zero is returned if the key is new.
2425 */
2426static int
2427smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2428{
2429 struct stkctr tmpstkctr;
2430 struct stkctr *stkctr;
2431
2432 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2433 if (!stkctr)
2434 return 0;
2435
2436 smp->flags = SMP_F_VOL_TEST;
2437 smp->data.type = SMP_T_SINT;
2438 smp->data.u.sint = 0;
2439 if (stkctr_entry(stkctr) != NULL) {
2440 void *ptr;
2441
2442 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2443 if (!ptr) {
2444 if (stkctr == &tmpstkctr)
2445 stktable_release(stkctr->table, stkctr_entry(stkctr));
2446 return 0; /* parameter not stored */
2447 }
2448
2449 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2450
2451 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2452 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2453
2454 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2455
2456 if (stkctr == &tmpstkctr)
2457 stktable_release(stkctr->table, stkctr_entry(stkctr));
2458 }
2459 return 1;
2460}
2461
Willy Tarreau7d562212016-11-25 16:10:05 +01002462/* Increment the General Purpose Counter 0 value from the stream's tracked
2463 * frontend counters and return it into temp integer.
2464 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2465 */
2466static int
2467smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2468{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002469 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002470 struct stkctr *stkctr;
2471
Emeric Brun819fc6f2017-06-13 19:37:32 +02002472 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002473 if (!stkctr)
2474 return 0;
2475
2476 smp->flags = SMP_F_VOL_TEST;
2477 smp->data.type = SMP_T_SINT;
2478 smp->data.u.sint = 0;
2479
Emeric Brun819fc6f2017-06-13 19:37:32 +02002480 if (!stkctr_entry(stkctr))
2481 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002482
2483 if (stkctr && stkctr_entry(stkctr)) {
2484 void *ptr1,*ptr2;
2485
Emeric Brun819fc6f2017-06-13 19:37:32 +02002486
Willy Tarreau7d562212016-11-25 16:10:05 +01002487 /* First, update gpc0_rate if it's tracked. Second, update its
2488 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2489 */
2490 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002491 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002492 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002493 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002494
Emeric Brun819fc6f2017-06-13 19:37:32 +02002495 if (ptr1) {
2496 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2497 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2498 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2499 }
2500
2501 if (ptr2)
2502 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2503
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002504 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002505
2506 /* If data was modified, we need to touch to re-schedule sync */
2507 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2508 }
2509 else if (stkctr == &tmpstkctr)
2510 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002511 }
2512 return 1;
2513}
2514
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002515/* Increment the General Purpose Counter 1 value from the stream's tracked
2516 * frontend counters and return it into temp integer.
2517 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2518 */
2519static int
2520smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2521{
2522 struct stkctr tmpstkctr;
2523 struct stkctr *stkctr;
2524
2525 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2526 if (!stkctr)
2527 return 0;
2528
2529 smp->flags = SMP_F_VOL_TEST;
2530 smp->data.type = SMP_T_SINT;
2531 smp->data.u.sint = 0;
2532
2533 if (!stkctr_entry(stkctr))
2534 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2535
2536 if (stkctr && stkctr_entry(stkctr)) {
2537 void *ptr1,*ptr2;
2538
2539
2540 /* First, update gpc1_rate if it's tracked. Second, update its
2541 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2542 */
2543 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2544 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2545 if (ptr1 || ptr2) {
2546 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2547
2548 if (ptr1) {
2549 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2550 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2551 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2552 }
2553
2554 if (ptr2)
2555 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2556
2557 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2558
2559 /* If data was modified, we need to touch to re-schedule sync */
2560 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2561 }
2562 else if (stkctr == &tmpstkctr)
2563 stktable_release(stkctr->table, stkctr_entry(stkctr));
2564 }
2565 return 1;
2566}
2567
Willy Tarreau7d562212016-11-25 16:10:05 +01002568/* Clear the General Purpose Counter 0 value from the stream's tracked
2569 * frontend counters and return its previous value into temp integer.
2570 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2571 */
2572static int
2573smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2574{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002575 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002576 struct stkctr *stkctr;
2577
Emeric Brun819fc6f2017-06-13 19:37:32 +02002578 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002579 if (!stkctr)
2580 return 0;
2581
2582 smp->flags = SMP_F_VOL_TEST;
2583 smp->data.type = SMP_T_SINT;
2584 smp->data.u.sint = 0;
2585
Emeric Brun819fc6f2017-06-13 19:37:32 +02002586 if (!stkctr_entry(stkctr))
2587 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002588
Emeric Brun819fc6f2017-06-13 19:37:32 +02002589 if (stkctr && stkctr_entry(stkctr)) {
2590 void *ptr;
2591
2592 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2593 if (!ptr) {
2594 if (stkctr == &tmpstkctr)
2595 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002596 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002597 }
2598
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002599 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002600
Willy Tarreau7d562212016-11-25 16:10:05 +01002601 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2602 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002603
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002604 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002605
Willy Tarreau7d562212016-11-25 16:10:05 +01002606 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002607 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002608 }
2609 return 1;
2610}
2611
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002612/* Clear the General Purpose Counter 1 value from the stream's tracked
2613 * frontend counters and return its previous value into temp integer.
2614 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2615 */
2616static int
2617smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2618{
2619 struct stkctr tmpstkctr;
2620 struct stkctr *stkctr;
2621
2622 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2623 if (!stkctr)
2624 return 0;
2625
2626 smp->flags = SMP_F_VOL_TEST;
2627 smp->data.type = SMP_T_SINT;
2628 smp->data.u.sint = 0;
2629
2630 if (!stkctr_entry(stkctr))
2631 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2632
2633 if (stkctr && stkctr_entry(stkctr)) {
2634 void *ptr;
2635
2636 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2637 if (!ptr) {
2638 if (stkctr == &tmpstkctr)
2639 stktable_release(stkctr->table, stkctr_entry(stkctr));
2640 return 0; /* parameter not stored */
2641 }
2642
2643 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2644
2645 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2646 stktable_data_cast(ptr, gpc1) = 0;
2647
2648 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2649
2650 /* If data was modified, we need to touch to re-schedule sync */
2651 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2652 }
2653 return 1;
2654}
2655
Willy Tarreau7d562212016-11-25 16:10:05 +01002656/* set <smp> to the cumulated number of connections from the stream's tracked
2657 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2658 * "src_conn_cnt" only.
2659 */
2660static int
2661smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2662{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002663 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002664 struct stkctr *stkctr;
2665
Emeric Brun819fc6f2017-06-13 19:37:32 +02002666 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002667 if (!stkctr)
2668 return 0;
2669
2670 smp->flags = SMP_F_VOL_TEST;
2671 smp->data.type = SMP_T_SINT;
2672 smp->data.u.sint = 0;
2673 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002674 void *ptr;
2675
2676 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2677 if (!ptr) {
2678 if (stkctr == &tmpstkctr)
2679 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002680 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002681 }
2682
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002683 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002684
Willy Tarreau7d562212016-11-25 16:10:05 +01002685 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002686
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002687 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002688
2689 if (stkctr == &tmpstkctr)
2690 stktable_release(stkctr->table, stkctr_entry(stkctr));
2691
2692
Willy Tarreau7d562212016-11-25 16:10:05 +01002693 }
2694 return 1;
2695}
2696
2697/* set <smp> to the connection rate from the stream's tracked frontend
2698 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2699 * only.
2700 */
2701static int
2702smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2703{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002704 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002705 struct stkctr *stkctr;
2706
Emeric Brun819fc6f2017-06-13 19:37:32 +02002707 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002708 if (!stkctr)
2709 return 0;
2710
2711 smp->flags = SMP_F_VOL_TEST;
2712 smp->data.type = SMP_T_SINT;
2713 smp->data.u.sint = 0;
2714 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002715 void *ptr;
2716
2717 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2718 if (!ptr) {
2719 if (stkctr == &tmpstkctr)
2720 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002721 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002722 }
2723
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002724 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002725
Willy Tarreau7d562212016-11-25 16:10:05 +01002726 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2727 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002728
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002729 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730
2731 if (stkctr == &tmpstkctr)
2732 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002733 }
2734 return 1;
2735}
2736
2737/* set temp integer to the number of connections from the stream's source address
2738 * in the table pointed to by expr, after updating it.
2739 * Accepts exactly 1 argument of type table.
2740 */
2741static int
2742smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2743{
2744 struct connection *conn = objt_conn(smp->sess->origin);
2745 struct stksess *ts;
2746 struct stktable_key *key;
2747 void *ptr;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002748 struct stktable *t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002749
2750 if (!conn)
2751 return 0;
2752
Joseph Herlant5662fa42018-11-15 13:43:28 -08002753 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002754 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2755 return 0;
2756
2757 /* Converts into key. */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002758 key = smp_to_stkey(smp, args->data.t);
Willy Tarreau7d562212016-11-25 16:10:05 +01002759 if (!key)
2760 return 0;
2761
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002762 t = args->data.t;
Willy Tarreau7d562212016-11-25 16:10:05 +01002763
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002764 if ((ts = stktable_get_entry(t, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002765 /* entry does not exist and could not be created */
2766 return 0;
2767
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002768 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002769 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002770 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002772
2773 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002774
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002775 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002776
Willy Tarreau7d562212016-11-25 16:10:05 +01002777 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002778
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002779 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780
Willy Tarreau7d562212016-11-25 16:10:05 +01002781 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002782
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01002783 stktable_touch_local(t, ts, 1);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002784
2785 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002786 return 1;
2787}
2788
2789/* set <smp> to the number of concurrent connections from the stream's tracked
2790 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2791 * "src_conn_cur" only.
2792 */
2793static int
2794smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2795{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002796 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002797 struct stkctr *stkctr;
2798
Emeric Brun819fc6f2017-06-13 19:37:32 +02002799 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002800 if (!stkctr)
2801 return 0;
2802
2803 smp->flags = SMP_F_VOL_TEST;
2804 smp->data.type = SMP_T_SINT;
2805 smp->data.u.sint = 0;
2806 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002807 void *ptr;
2808
2809 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2810 if (!ptr) {
2811 if (stkctr == &tmpstkctr)
2812 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002813 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002814 }
2815
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002816 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002817
Willy Tarreau7d562212016-11-25 16:10:05 +01002818 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002819
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002820 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002821
2822 if (stkctr == &tmpstkctr)
2823 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002824 }
2825 return 1;
2826}
2827
2828/* set <smp> to the cumulated number of streams from the stream's tracked
2829 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2830 * "src_sess_cnt" only.
2831 */
2832static int
2833smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2834{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002836 struct stkctr *stkctr;
2837
Emeric Brun819fc6f2017-06-13 19:37:32 +02002838 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002839 if (!stkctr)
2840 return 0;
2841
2842 smp->flags = SMP_F_VOL_TEST;
2843 smp->data.type = SMP_T_SINT;
2844 smp->data.u.sint = 0;
2845 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002846 void *ptr;
2847
2848 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2849 if (!ptr) {
2850 if (stkctr == &tmpstkctr)
2851 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002852 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002853 }
2854
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002855 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002856
Willy Tarreau7d562212016-11-25 16:10:05 +01002857 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002858
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002859 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002860
2861 if (stkctr == &tmpstkctr)
2862 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002863 }
2864 return 1;
2865}
2866
2867/* set <smp> to the stream rate from the stream's tracked frontend counters.
2868 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2869 */
2870static int
2871smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2872{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002873 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002874 struct stkctr *stkctr;
2875
Emeric Brun819fc6f2017-06-13 19:37:32 +02002876 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002877 if (!stkctr)
2878 return 0;
2879
2880 smp->flags = SMP_F_VOL_TEST;
2881 smp->data.type = SMP_T_SINT;
2882 smp->data.u.sint = 0;
2883 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002884 void *ptr;
2885
2886 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2887 if (!ptr) {
2888 if (stkctr == &tmpstkctr)
2889 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002890 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002891 }
2892
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002893 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002894
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2896 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002897
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002898 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002899
2900 if (stkctr == &tmpstkctr)
2901 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002902 }
2903 return 1;
2904}
2905
2906/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2907 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2908 * "src_http_req_cnt" only.
2909 */
2910static int
2911smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2912{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002913 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002914 struct stkctr *stkctr;
2915
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 if (!stkctr)
2918 return 0;
2919
2920 smp->flags = SMP_F_VOL_TEST;
2921 smp->data.type = SMP_T_SINT;
2922 smp->data.u.sint = 0;
2923 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924 void *ptr;
2925
2926 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2927 if (!ptr) {
2928 if (stkctr == &tmpstkctr)
2929 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002930 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931 }
2932
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002933 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934
Willy Tarreau7d562212016-11-25 16:10:05 +01002935 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002936
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002937 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002938
2939 if (stkctr == &tmpstkctr)
2940 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002941 }
2942 return 1;
2943}
2944
2945/* set <smp> to the HTTP request rate from the stream's tracked frontend
2946 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2947 * "src_http_req_rate" only.
2948 */
2949static int
2950smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2951{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002953 struct stkctr *stkctr;
2954
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002956 if (!stkctr)
2957 return 0;
2958
2959 smp->flags = SMP_F_VOL_TEST;
2960 smp->data.type = SMP_T_SINT;
2961 smp->data.u.sint = 0;
2962 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002963 void *ptr;
2964
2965 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2966 if (!ptr) {
2967 if (stkctr == &tmpstkctr)
2968 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002969 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002970 }
2971
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002972 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002973
Willy Tarreau7d562212016-11-25 16:10:05 +01002974 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2975 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002976
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002977 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978
2979 if (stkctr == &tmpstkctr)
2980 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002981 }
2982 return 1;
2983}
2984
2985/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2986 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2987 * "src_http_err_cnt" only.
2988 */
2989static int
2990smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2991{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002993 struct stkctr *stkctr;
2994
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002996 if (!stkctr)
2997 return 0;
2998
2999 smp->flags = SMP_F_VOL_TEST;
3000 smp->data.type = SMP_T_SINT;
3001 smp->data.u.sint = 0;
3002 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003003 void *ptr;
3004
3005 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
3006 if (!ptr) {
3007 if (stkctr == &tmpstkctr)
3008 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003009 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003010 }
3011
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003012 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003013
Willy Tarreau7d562212016-11-25 16:10:05 +01003014 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003015
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003016 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003017
3018 if (stkctr == &tmpstkctr)
3019 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003020 }
3021 return 1;
3022}
3023
3024/* set <smp> to the HTTP request error rate from the stream's tracked frontend
3025 * counters. Supports being called as "sc[0-9]_http_err_rate" or
3026 * "src_http_err_rate" only.
3027 */
3028static int
3029smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3030{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003031 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003032 struct stkctr *stkctr;
3033
Emeric Brun819fc6f2017-06-13 19:37:32 +02003034 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003035 if (!stkctr)
3036 return 0;
3037
3038 smp->flags = SMP_F_VOL_TEST;
3039 smp->data.type = SMP_T_SINT;
3040 smp->data.u.sint = 0;
3041 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003042 void *ptr;
3043
3044 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3045 if (!ptr) {
3046 if (stkctr == &tmpstkctr)
3047 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003048 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003049 }
3050
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003051 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003052
Willy Tarreau7d562212016-11-25 16:10:05 +01003053 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3054 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003055
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003056 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003057
3058 if (stkctr == &tmpstkctr)
3059 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003060 }
3061 return 1;
3062}
3063
3064/* set <smp> to the number of kbytes received from clients, as found in the
3065 * stream's tracked frontend counters. Supports being called as
3066 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3067 */
3068static int
3069smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3070{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003071 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003072 struct stkctr *stkctr;
3073
Emeric Brun819fc6f2017-06-13 19:37:32 +02003074 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003075 if (!stkctr)
3076 return 0;
3077
3078 smp->flags = SMP_F_VOL_TEST;
3079 smp->data.type = SMP_T_SINT;
3080 smp->data.u.sint = 0;
3081 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003082 void *ptr;
3083
3084 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3085 if (!ptr) {
3086 if (stkctr == &tmpstkctr)
3087 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003088 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003089 }
3090
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003091 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003092
Willy Tarreau7d562212016-11-25 16:10:05 +01003093 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003094
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003095 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003096
3097 if (stkctr == &tmpstkctr)
3098 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003099 }
3100 return 1;
3101}
3102
3103/* set <smp> to the data rate received from clients in bytes/s, as found
3104 * in the stream's tracked frontend counters. Supports being called as
3105 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3106 */
3107static int
3108smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3109{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003110 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003111 struct stkctr *stkctr;
3112
Emeric Brun819fc6f2017-06-13 19:37:32 +02003113 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003114 if (!stkctr)
3115 return 0;
3116
3117 smp->flags = SMP_F_VOL_TEST;
3118 smp->data.type = SMP_T_SINT;
3119 smp->data.u.sint = 0;
3120 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003121 void *ptr;
3122
3123 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3124 if (!ptr) {
3125 if (stkctr == &tmpstkctr)
3126 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003127 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003128 }
3129
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003130 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003131
Willy Tarreau7d562212016-11-25 16:10:05 +01003132 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3133 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003134
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003135 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003136
3137 if (stkctr == &tmpstkctr)
3138 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003139 }
3140 return 1;
3141}
3142
3143/* set <smp> to the number of kbytes sent to clients, as found in the
3144 * stream's tracked frontend counters. Supports being called as
3145 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3146 */
3147static int
3148smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3149{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003150 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003151 struct stkctr *stkctr;
3152
Emeric Brun819fc6f2017-06-13 19:37:32 +02003153 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003154 if (!stkctr)
3155 return 0;
3156
3157 smp->flags = SMP_F_VOL_TEST;
3158 smp->data.type = SMP_T_SINT;
3159 smp->data.u.sint = 0;
3160 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003161 void *ptr;
3162
3163 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3164 if (!ptr) {
3165 if (stkctr == &tmpstkctr)
3166 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003167 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003168 }
3169
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003170 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003171
Willy Tarreau7d562212016-11-25 16:10:05 +01003172 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003173
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003174 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003175
3176 if (stkctr == &tmpstkctr)
3177 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003178 }
3179 return 1;
3180}
3181
3182/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3183 * stream's tracked frontend counters. Supports being called as
3184 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3185 */
3186static int
3187smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3188{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003189 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003190 struct stkctr *stkctr;
3191
Emeric Brun819fc6f2017-06-13 19:37:32 +02003192 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003193 if (!stkctr)
3194 return 0;
3195
3196 smp->flags = SMP_F_VOL_TEST;
3197 smp->data.type = SMP_T_SINT;
3198 smp->data.u.sint = 0;
3199 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003200 void *ptr;
3201
3202 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3203 if (!ptr) {
3204 if (stkctr == &tmpstkctr)
3205 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003206 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003207 }
3208
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003209 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003210
Willy Tarreau7d562212016-11-25 16:10:05 +01003211 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3212 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003213
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003214 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003215
3216 if (stkctr == &tmpstkctr)
3217 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003218 }
3219 return 1;
3220}
3221
3222/* set <smp> to the number of active trackers on the SC entry in the stream's
3223 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3224 */
3225static int
3226smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3227{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003229 struct stkctr *stkctr;
3230
Emeric Brun819fc6f2017-06-13 19:37:32 +02003231 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003232 if (!stkctr)
3233 return 0;
3234
3235 smp->flags = SMP_F_VOL_TEST;
3236 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003237 if (stkctr == &tmpstkctr) {
3238 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3239 stktable_release(stkctr->table, stkctr_entry(stkctr));
3240 }
3241 else {
3242 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3243 }
3244
Willy Tarreau7d562212016-11-25 16:10:05 +01003245 return 1;
3246}
3247
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003248
3249/* The functions below are used to manipulate table contents from the CLI.
3250 * There are 3 main actions, "clear", "set" and "show". The code is shared
3251 * between all actions, and the action is encoded in the void *private in
3252 * the appctx as well as in the keyword registration, among one of the
3253 * following values.
3254 */
3255
3256enum {
3257 STK_CLI_ACT_CLR,
3258 STK_CLI_ACT_SET,
3259 STK_CLI_ACT_SHOW,
3260};
3261
3262/* Dump the status of a table to a stream interface's
3263 * read buffer. It returns 0 if the output buffer is full
3264 * and needs to be called again, otherwise non-zero.
3265 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003266static int table_dump_head_to_buffer(struct buffer *msg,
3267 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003268 struct stktable *t, struct stktable *target)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003269{
3270 struct stream *s = si_strm(si);
3271
3272 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003273 t->id, stktable_types[t->type].kw, t->size, t->current);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003274
3275 /* any other information should be dumped here */
3276
William Lallemand07a62f72017-05-24 00:57:40 +02003277 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003278 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3279
Willy Tarreau06d80a92017-10-19 14:32:15 +02003280 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003281 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003282 return 0;
3283 }
3284
3285 return 1;
3286}
3287
3288/* Dump a table entry to a stream interface's
3289 * read buffer. It returns 0 if the output buffer is full
3290 * and needs to be called again, otherwise non-zero.
3291 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003292static int table_dump_entry_to_buffer(struct buffer *msg,
3293 struct stream_interface *si,
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003294 struct stktable *t, struct stksess *entry)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003295{
3296 int dt;
3297
3298 chunk_appendf(msg, "%p:", entry);
3299
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003300 if (t->type == SMP_T_IPV4) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003301 char addr[INET_ADDRSTRLEN];
3302 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3303 chunk_appendf(msg, " key=%s", addr);
3304 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003305 else if (t->type == SMP_T_IPV6) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003306 char addr[INET6_ADDRSTRLEN];
3307 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3308 chunk_appendf(msg, " key=%s", addr);
3309 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003310 else if (t->type == SMP_T_SINT) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003311 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3312 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003313 else if (t->type == SMP_T_STR) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003314 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003315 dump_text(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003316 }
3317 else {
3318 chunk_appendf(msg, " key=");
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003319 dump_binary(msg, (const char *)entry->key.key, t->key_size);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003320 }
3321
3322 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3323
3324 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3325 void *ptr;
3326
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003327 if (t->data_ofs[dt] == 0)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003328 continue;
3329 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003330 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003331 else
3332 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3333
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003334 ptr = stktable_data_ptr(t, entry, dt);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003335 switch (stktable_data_types[dt].std_type) {
3336 case STD_T_SINT:
3337 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3338 break;
3339 case STD_T_UINT:
3340 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3341 break;
3342 case STD_T_ULL:
3343 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3344 break;
3345 case STD_T_FRQP:
3346 chunk_appendf(msg, "%d",
3347 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003348 t->data_arg[dt].u));
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003349 break;
Frédéric Lécaille16b4f542019-05-23 12:15:04 +02003350 case STD_T_DICT: {
3351 struct dict_entry *de;
3352 de = stktable_data_cast(ptr, std_t_dict);
3353 chunk_appendf(msg, "%s", de ? (char *)de->value.key : "-");
3354 break;
3355 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003356 }
3357 }
3358 chunk_appendf(msg, "\n");
3359
Willy Tarreau06d80a92017-10-19 14:32:15 +02003360 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003361 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003362 return 0;
3363 }
3364
3365 return 1;
3366}
3367
3368
3369/* Processes a single table entry matching a specific key passed in argument.
3370 * returns 0 if wants to be called again, 1 if has ended processing.
3371 */
3372static int table_process_entry_per_key(struct appctx *appctx, char **args)
3373{
3374 struct stream_interface *si = appctx->owner;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003375 struct stktable *t = appctx->ctx.table.target;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003376 struct stksess *ts;
3377 uint32_t uint32_key;
3378 unsigned char ip6_key[sizeof(struct in6_addr)];
3379 long long value;
3380 int data_type;
3381 int cur_arg;
3382 void *ptr;
3383 struct freq_ctr_period *frqp;
3384
3385 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003386 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003387 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003388 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003389 return 1;
3390 }
3391
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003392 switch (t->type) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003393 case SMP_T_IPV4:
3394 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003395 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003396 break;
3397 case SMP_T_IPV6:
3398 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003399 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003400 break;
3401 case SMP_T_SINT:
3402 {
3403 char *endptr;
3404 unsigned long val;
3405 errno = 0;
3406 val = strtoul(args[4], &endptr, 10);
3407 if ((errno == ERANGE && val == ULONG_MAX) ||
3408 (errno != 0 && val == 0) || endptr == args[4] ||
3409 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003410 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003411 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003412 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003413 return 1;
3414 }
3415 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003416 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003417 break;
3418 }
3419 break;
3420 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003421 static_table_key.key = args[4];
3422 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003423 break;
3424 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003425 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003426 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003427 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003428 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3429 break;
3430 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003431 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003432 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3433 break;
3434 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003435 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003436 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3437 break;
3438 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003439 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003440 appctx->ctx.cli.msg = "Unknown action\n";
3441 break;
3442 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003443 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003444 return 1;
3445 }
3446
3447 /* check permissions */
3448 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3449 return 1;
3450
Willy Tarreaua24bc782016-12-14 15:50:35 +01003451 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003452 case STK_CLI_ACT_SHOW:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003453 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003454 if (!ts)
3455 return 1;
3456 chunk_reset(&trash);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003457 if (!table_dump_head_to_buffer(&trash, si, t, t)) {
3458 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003459 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003460 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003461 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003462 if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003463 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003464 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003465 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003466 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003467 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003468 stktable_release(t, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003469 break;
3470
3471 case STK_CLI_ACT_CLR:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003472 ts = stktable_lookup_key(t, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003473 if (!ts)
3474 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003475
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003476 if (!stksess_kill(t, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003477 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003478 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003479 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003480 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003481 return 1;
3482 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003483
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003484 break;
3485
3486 case STK_CLI_ACT_SET:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003487 ts = stktable_get_entry(t, &static_table_key);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003488 if (!ts) {
3489 /* don't delete an entry which is currently referenced */
3490 appctx->ctx.cli.severity = LOG_ERR;
3491 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3492 appctx->st0 = CLI_ST_PRINT;
3493 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003494 }
3495
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003496 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003497 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3498 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003499 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003500 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003501 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003502 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003503 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003504 return 1;
3505 }
3506
3507 data_type = stktable_get_data_type(args[cur_arg] + 5);
3508 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003509 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003510 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003511 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003512 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003513 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003514 return 1;
3515 }
3516
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003517 if (!t->data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003518 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003519 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003520 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003521 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003522 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003523 return 1;
3524 }
3525
3526 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003527 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003528 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003529 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003530 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003531 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003532 return 1;
3533 }
3534
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003535 ptr = stktable_data_ptr(t, ts, data_type);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003536
3537 switch (stktable_data_types[data_type].std_type) {
3538 case STD_T_SINT:
3539 stktable_data_cast(ptr, std_t_sint) = value;
3540 break;
3541 case STD_T_UINT:
3542 stktable_data_cast(ptr, std_t_uint) = value;
3543 break;
3544 case STD_T_ULL:
3545 stktable_data_cast(ptr, std_t_ull) = value;
3546 break;
3547 case STD_T_FRQP:
3548 /* We set both the current and previous values. That way
3549 * the reported frequency is stable during all the period
3550 * then slowly fades out. This allows external tools to
3551 * push measures without having to update them too often.
3552 */
3553 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003554 /* First bit is reserved for the freq_ctr_period lock
3555 Note: here we're still protected by the stksess lock
3556 so we don't need to update the update the freq_ctr_period
3557 using its internal lock */
3558 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003559 frqp->prev_ctr = 0;
3560 frqp->curr_ctr = value;
3561 break;
3562 }
3563 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003564 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003565 stktable_touch_local(t, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003566 break;
3567
3568 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003569 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003570 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003571 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003572 break;
3573 }
3574 return 1;
3575}
3576
3577/* Prepares the appctx fields with the data-based filters from the command line.
3578 * Returns 0 if the dump can proceed, 1 if has ended processing.
3579 */
3580static int table_prepare_data_request(struct appctx *appctx, char **args)
3581{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003582 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003583 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003584 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003585 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003586 return 1;
3587 }
3588
3589 /* condition on stored data value */
3590 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3591 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003592 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003593 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003594 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003595 return 1;
3596 }
3597
Dragan Dosen7d61a332019-05-07 14:16:18 +02003598 if (!((struct proxy *)appctx->ctx.table.target)->table ||
3599 !((struct proxy *)appctx->ctx.table.target)->table->data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003600 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003601 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003602 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003603 return 1;
3604 }
3605
3606 appctx->ctx.table.data_op = get_std_op(args[4]);
3607 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003608 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003609 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003610 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003611 return 1;
3612 }
3613
3614 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003615 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003616 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003617 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003618 return 1;
3619 }
3620
3621 /* OK we're done, all the fields are set */
3622 return 0;
3623}
3624
3625/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003626static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003627{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003628 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003629 appctx->ctx.table.target = NULL;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003630 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003631 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003632
3633 if (*args[2]) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003634 appctx->ctx.table.target = stktable_find_by_name(args[2]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003635 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003636 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003637 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003638 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003639 return 1;
3640 }
3641 }
3642 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003643 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003644 goto err_args;
3645 return 0;
3646 }
3647
3648 if (strcmp(args[3], "key") == 0)
3649 return table_process_entry_per_key(appctx, args);
3650 else if (strncmp(args[3], "data.", 5) == 0)
3651 return table_prepare_data_request(appctx, args);
3652 else if (*args[3])
3653 goto err_args;
3654
3655 return 0;
3656
3657err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003658 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003659 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003660 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003661 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3662 break;
3663 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003664 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003665 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3666 break;
3667 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003668 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003669 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3670 break;
3671 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003672 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003673 appctx->ctx.cli.msg = "Unknown action\n";
3674 break;
3675 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003676 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003677 return 1;
3678}
3679
3680/* This function is used to deal with table operations (dump or clear depending
3681 * on the action stored in appctx->private). It returns 0 if the output buffer is
3682 * full and it needs to be called again, otherwise non-zero.
3683 */
3684static int cli_io_handler_table(struct appctx *appctx)
3685{
3686 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003687 struct stream *s = si_strm(si);
3688 struct ebmb_node *eb;
3689 int dt;
3690 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003691 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003692
3693 /*
3694 * We have 3 possible states in appctx->st2 :
3695 * - STAT_ST_INIT : the first call
3696 * - STAT_ST_INFO : the proxy pointer points to the next table to
3697 * dump, the entry pointer is NULL ;
3698 * - STAT_ST_LIST : the proxy pointer points to the current table
3699 * and the entry pointer points to the next entry to be dumped,
3700 * and the refcount on the next entry is held ;
3701 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3702 * data though.
3703 */
3704
3705 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3706 /* in case of abort, remove any refcount we might have set on an entry */
3707 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003708 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003709 }
3710 return 1;
3711 }
3712
3713 chunk_reset(&trash);
3714
3715 while (appctx->st2 != STAT_ST_FIN) {
3716 switch (appctx->st2) {
3717 case STAT_ST_INIT:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003718 appctx->ctx.table.t = appctx->ctx.table.target;
3719 if (!appctx->ctx.table.t)
3720 appctx->ctx.table.t = stktables_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003721
3722 appctx->ctx.table.entry = NULL;
3723 appctx->st2 = STAT_ST_INFO;
3724 break;
3725
3726 case STAT_ST_INFO:
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003727 if (!appctx->ctx.table.t ||
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003728 (appctx->ctx.table.target &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003729 appctx->ctx.table.t != appctx->ctx.table.target)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003730 appctx->st2 = STAT_ST_END;
3731 break;
3732 }
3733
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003734 if (appctx->ctx.table.t->size) {
3735 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003736 return 0;
3737
3738 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003739 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003740 /* dump entries only if table explicitly requested */
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003741 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
3742 eb = ebmb_first(&appctx->ctx.table.t->keys);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003743 if (eb) {
3744 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3745 appctx->ctx.table.entry->ref_cnt++;
3746 appctx->st2 = STAT_ST_LIST;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003747 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003748 break;
3749 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003750 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003751 }
3752 }
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003753 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003754 break;
3755
3756 case STAT_ST_LIST:
3757 skip_entry = 0;
3758
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003759 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003760
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003761 if (appctx->ctx.table.data_type >= 0) {
3762 /* we're filtering on some data contents */
3763 void *ptr;
3764 long long data;
3765
Emeric Brun819fc6f2017-06-13 19:37:32 +02003766
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003767 dt = appctx->ctx.table.data_type;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003768 ptr = stktable_data_ptr(appctx->ctx.table.t,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003769 appctx->ctx.table.entry,
3770 dt);
3771
3772 data = 0;
3773 switch (stktable_data_types[dt].std_type) {
3774 case STD_T_SINT:
3775 data = stktable_data_cast(ptr, std_t_sint);
3776 break;
3777 case STD_T_UINT:
3778 data = stktable_data_cast(ptr, std_t_uint);
3779 break;
3780 case STD_T_ULL:
3781 data = stktable_data_cast(ptr, std_t_ull);
3782 break;
3783 case STD_T_FRQP:
3784 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003785 appctx->ctx.table.t->data_arg[dt].u);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003786 break;
3787 }
3788
3789 /* skip the entry if the data does not match the test and the value */
3790 if ((data < appctx->ctx.table.value &&
3791 (appctx->ctx.table.data_op == STD_OP_EQ ||
3792 appctx->ctx.table.data_op == STD_OP_GT ||
3793 appctx->ctx.table.data_op == STD_OP_GE)) ||
3794 (data == appctx->ctx.table.value &&
3795 (appctx->ctx.table.data_op == STD_OP_NE ||
3796 appctx->ctx.table.data_op == STD_OP_GT ||
3797 appctx->ctx.table.data_op == STD_OP_LT)) ||
3798 (data > appctx->ctx.table.value &&
3799 (appctx->ctx.table.data_op == STD_OP_EQ ||
3800 appctx->ctx.table.data_op == STD_OP_LT ||
3801 appctx->ctx.table.data_op == STD_OP_LE)))
3802 skip_entry = 1;
3803 }
3804
3805 if (show && !skip_entry &&
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003806 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003807 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003808 return 0;
3809 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003810
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003811 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003812
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003813 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003814 appctx->ctx.table.entry->ref_cnt--;
3815
3816 eb = ebmb_next(&appctx->ctx.table.entry->key);
3817 if (eb) {
3818 struct stksess *old = appctx->ctx.table.entry;
3819 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3820 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003821 __stksess_kill_if_expired(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003822 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003823 __stksess_kill(appctx->ctx.table.t, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003824 appctx->ctx.table.entry->ref_cnt++;
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003825 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003826 break;
3827 }
3828
3829
3830 if (show)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003831 __stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003832 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003833 __stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003834
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003835 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003836
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003837 appctx->ctx.table.t = appctx->ctx.table.t->next;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003838 appctx->st2 = STAT_ST_INFO;
3839 break;
3840
3841 case STAT_ST_END:
3842 appctx->st2 = STAT_ST_FIN;
3843 break;
3844 }
3845 }
3846 return 1;
3847}
3848
3849static void cli_release_show_table(struct appctx *appctx)
3850{
3851 if (appctx->st2 == STAT_ST_LIST) {
Frédéric Lécaille1b8e68e2019-03-14 07:07:41 +01003852 stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003853 }
3854}
3855
3856/* register cli keywords */
3857static struct cli_kw_list cli_kws = {{ },{
3858 { { "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 },
3859 { { "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 },
3860 { { "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 },
3861 {{},}
3862}};
3863
Willy Tarreau0108d902018-11-25 19:14:37 +01003864INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003865
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003866static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003867 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003868 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003869 { "sc-set-gpt0", parse_set_gpt0, 1 },
3870 { /* END */ }
3871}};
3872
Willy Tarreau0108d902018-11-25 19:14:37 +01003873INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3874
Willy Tarreau620408f2016-10-21 16:37:51 +02003875static struct action_kw_list tcp_sess_kws = { { }, {
3876 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003877 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003878 { "sc-set-gpt0", parse_set_gpt0, 1 },
3879 { /* END */ }
3880}};
3881
Willy Tarreau0108d902018-11-25 19:14:37 +01003882INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3883
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003884static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003885 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003886 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003887 { "sc-set-gpt0", parse_set_gpt0, 1 },
3888 { /* END */ }
3889}};
3890
Willy Tarreau0108d902018-11-25 19:14:37 +01003891INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3892
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003893static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003894 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003895 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003896 { "sc-set-gpt0", parse_set_gpt0, 1 },
3897 { /* END */ }
3898}};
3899
Willy Tarreau0108d902018-11-25 19:14:37 +01003900INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3901
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003902static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003903 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003904 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003905 { "sc-set-gpt0", parse_set_gpt0, 1 },
3906 { /* END */ }
3907}};
3908
Willy Tarreau0108d902018-11-25 19:14:37 +01003909INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3910
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003911static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003912 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003913 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003914 { "sc-set-gpt0", parse_set_gpt0, 1 },
3915 { /* END */ }
3916}};
3917
Willy Tarreau0108d902018-11-25 19:14:37 +01003918INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3919
Willy Tarreau7d562212016-11-25 16:10:05 +01003920///* Note: must not be declared <const> as its list will be overwritten.
3921// * Please take care of keeping this list alphabetically sorted.
3922// */
3923//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3924// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3925// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3926// { /* END */ },
3927//}};
3928/* Note: must not be declared <const> as its list will be overwritten.
3929 * Please take care of keeping this list alphabetically sorted.
3930 */
3931static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3932 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3933 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3934 { "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 +01003935 { "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 +01003936 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3937 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3938 { "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 +01003939 { "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 +01003940 { "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 +01003941 { "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 +01003942 { "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 +01003943 { "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 +01003944 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3945 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3946 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3947 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3948 { "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 +01003949 { "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 +01003950 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3951 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3952 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3953 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3954 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3955 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3956 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3957 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3958 { "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 +01003959 { "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 +01003960 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3961 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3962 { "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 +01003963 { "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 +01003964 { "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 +01003965 { "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 +01003966 { "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 +01003967 { "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 +01003968 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3969 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3970 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3971 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3972 { "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 +01003973 { "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 +01003974 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3975 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3976 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3977 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3978 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3979 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3980 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3981 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3982 { "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 +01003983 { "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 +01003984 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3985 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3986 { "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 +01003987 { "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 +01003988 { "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 +01003989 { "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 +01003990 { "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 +01003991 { "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 +01003992 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3993 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3994 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3995 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3996 { "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 +01003997 { "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 +01003998 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3999 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4000 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4001 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4002 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4003 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4004 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4005 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4006 { "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 +01004007 { "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 +01004008 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4009 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4010 { "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 +01004011 { "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 +01004012 { "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 +01004013 { "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 +01004014 { "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 +01004015 { "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 +01004016 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4017 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4018 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4019 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4020 { "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 +01004021 { "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 +01004022 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4023 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4024 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4025 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4026 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
4027 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4028 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4029 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4030 { "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 +01004031 { "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 +01004032 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4033 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4034 { "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 +01004035 { "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 +01004036 { "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 +01004037 { "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 +01004038 { "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 +01004039 { "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 +01004040 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4041 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4042 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4043 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4044 { "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 +01004045 { "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 +01004046 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4047 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4048 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4049 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4050 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4051 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4052 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4053 { /* END */ },
4054}};
4055
Willy Tarreau0108d902018-11-25 19:14:37 +01004056INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004057
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004058/* Note: must not be declared <const> as its list will be overwritten */
4059static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004060 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4061 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4062 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4063 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4064 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4065 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4066 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4067 { "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 +01004068 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004069 { "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 +01004070 { "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 +02004071 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4072 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4073 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4074 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4075 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4076 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4077 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4078 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4079 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4080 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004081 { /* END */ },
4082}};
4083
Willy Tarreau0108d902018-11-25 19:14:37 +01004084INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);