blob: d8053dc04f3262edd8b3cd5e790cd46242ec8f54 [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
Olivier Houchard52dabbc2018-11-14 17:54:36 +010050#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +010051/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020052 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
53 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010054 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020055void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010056{
57 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010058 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010059}
60
61/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020062 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
63 * in table <t>.
64 * This function locks the table
65 */
66void stksess_free(struct stktable *t, struct stksess *ts)
67{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010068 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020069 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010070 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020071}
72
73/*
Willy Tarreauf6efda12010-08-03 20:34:06 +020074 * Kill an stksess (only if its ref_cnt is zero).
75 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020076int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +020077{
78 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +020079 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +020080
81 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +020082 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +020083 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +020084 __stksess_free(t, ts);
85 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +020086}
87
88/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020089 * Decrease the refcount if decrefcnt is not 0.
90 * and try to kill the stksess
91 * This function locks the table
92 */
93int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
94{
95 int ret;
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 if (decrefcnt)
99 ts->ref_cnt--;
100 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100101 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200102
103 return ret;
104}
105
106/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200107 * Initialize or update the key in the sticky session <ts> present in table <t>
108 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100109 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200110void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100111{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200112 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200113 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100114 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200115 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
116 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100117 }
118}
119
120
121/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200122 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
123 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100124 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200125static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100126{
Willy Tarreau393379c2010-06-06 12:11:37 +0200127 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200128 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200129 ts->key.node.leaf_p = NULL;
130 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200131 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200132 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100133 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100134 return ts;
135}
136
137/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200138 * Trash oldest <to_batch> sticky sessions from table <t>
139 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100140 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200141int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100142{
143 struct stksess *ts;
144 struct eb32_node *eb;
145 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200146 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100147
148 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
149
150 while (batched < to_batch) {
151
152 if (unlikely(!eb)) {
153 /* we might have reached the end of the tree, typically because
154 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200155 * half. Let's loop back to the beginning of the tree now if we
156 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100157 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200158 if (looped)
159 break;
160 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100161 eb = eb32_first(&t->exps);
162 if (likely(!eb))
163 break;
164 }
165
166 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200167 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100168 eb = eb32_next(eb);
169
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200170 /* don't delete an entry which is currently referenced */
171 if (ts->ref_cnt)
172 continue;
173
Willy Tarreau86257dc2010-06-06 12:57:10 +0200174 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100175
Willy Tarreau86257dc2010-06-06 12:57:10 +0200176 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100177 if (!tick_isset(ts->expire))
178 continue;
179
Willy Tarreau86257dc2010-06-06 12:57:10 +0200180 ts->exp.key = ts->expire;
181 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100182
Willy Tarreau86257dc2010-06-06 12:57:10 +0200183 if (!eb || eb->key > ts->exp.key)
184 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100185
186 continue;
187 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100188
Willy Tarreauaea940e2010-06-06 11:56:36 +0200189 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200190 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200191 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200192 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100193 batched++;
194 }
195
196 return batched;
197}
198
199/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200200 * Trash oldest <to_batch> sticky sessions from table <t>
201 * Returns number of trashed sticky sessions.
202 * This function locks the table
203 */
204int stktable_trash_oldest(struct stktable *t, int to_batch)
205{
206 int ret;
207
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100208 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200209 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100210 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200211
212 return ret;
213}
214/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200215 * Allocate and initialise a new sticky session.
216 * The new sticky session is returned or NULL in case of lack of memory.
217 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200218 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
219 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100220 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200221struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100222{
223 struct stksess *ts;
224
225 if (unlikely(t->current == t->size)) {
226 if ( t->nopurge )
227 return NULL;
228
Emeric Brun819fc6f2017-06-13 19:37:32 +0200229 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100230 return NULL;
231 }
232
Willy Tarreaubafbe012017-11-24 17:34:44 +0100233 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100234 if (ts) {
235 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100236 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200237 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200238 if (key)
239 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100240 }
241
242 return ts;
243}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200244/*
245 * Allocate and initialise a new sticky session.
246 * The new sticky session is returned or NULL in case of lack of memory.
247 * Sticky sessions should only be allocated this way, and must be freed using
248 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
249 * is not NULL, it is assigned to the new session.
250 * This function locks the table
251 */
252struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
253{
254 struct stksess *ts;
255
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100256 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200257 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100258 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200259
260 return ts;
261}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262
263/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200264 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200265 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100266 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200267struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100268{
269 struct ebmb_node *eb;
270
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200271 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200272 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 +0100273 else
274 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
275
276 if (unlikely(!eb)) {
277 /* no session found */
278 return NULL;
279 }
280
Willy Tarreau86257dc2010-06-06 12:57:10 +0200281 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100282}
283
Emeric Brun819fc6f2017-06-13 19:37:32 +0200284/*
285 * Looks in table <t> for a sticky session matching key <key>.
286 * Returns pointer on requested sticky session or NULL if none was found.
287 * The refcount of the found entry is increased and this function
288 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200289 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200290struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200291{
292 struct stksess *ts;
293
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100294 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200295 ts = __stktable_lookup_key(t, key);
296 if (ts)
297 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100298 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200299
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200300 return ts;
301}
302
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200303/*
304 * Looks in table <t> for a sticky session with same key as <ts>.
305 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100306 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200307struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100309 struct ebmb_node *eb;
310
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200311 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200312 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100313 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200314 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200316 if (unlikely(!eb))
317 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100318
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200319 return ebmb_entry(eb, struct stksess, key);
320}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100321
Emeric Brun819fc6f2017-06-13 19:37:32 +0200322/*
323 * Looks in table <t> for a sticky session with same key as <ts>.
324 * Returns pointer on requested sticky session or NULL if none was found.
325 * The refcount of the found entry is increased and this function
326 * is protected using the table lock
327 */
328struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
329{
330 struct stksess *lts;
331
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100332 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200333 lts = __stktable_lookup(t, ts);
334 if (lts)
335 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100336 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200337
338 return lts;
339}
340
Willy Tarreaucb183642010-06-06 17:58:34 +0200341/* Update the expiration timer for <ts> but do not touch its expiration node.
342 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200343 * The node will be also inserted into the update tree if needed, at a position
344 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200345 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200346void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200347{
Emeric Brun85e77c72010-09-23 18:16:52 +0200348 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200349 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200350 if (t->expire) {
351 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
352 task_queue(t->exp_task);
353 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200354
Emeric Brun819fc6f2017-06-13 19:37:32 +0200355 /* If sync is enabled */
356 if (t->sync_task) {
357 if (local) {
358 /* If this entry is not in the tree
359 or not scheduled for at least one peer */
360 if (!ts->upd.node.leaf_p
361 || (int)(t->commitupdate - ts->upd.key) >= 0
362 || (int)(ts->upd.key - t->localupdate) >= 0) {
363 ts->upd.key = ++t->update;
364 t->localupdate = t->update;
365 eb32_delete(&ts->upd);
366 eb = eb32_insert(&t->updates, &ts->upd);
367 if (eb != &ts->upd) {
368 eb32_delete(eb);
369 eb32_insert(&t->updates, &ts->upd);
370 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200371 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200373 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200374 else {
375 /* If this entry is not in the tree */
376 if (!ts->upd.node.leaf_p) {
377 ts->upd.key= (++t->update)+(2147483648U);
378 eb = eb32_insert(&t->updates, &ts->upd);
379 if (eb != &ts->upd) {
380 eb32_delete(eb);
381 eb32_insert(&t->updates, &ts->upd);
382 }
383 }
384 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200385 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200386}
387
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200388/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200389 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200390 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200391 * The node will be also inserted into the update tree if needed, at a position
392 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200393 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200394void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
395{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100396 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200397 __stktable_touch_with_exp(t, ts, 0, ts->expire);
398 if (decrefcnt)
399 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100400 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200401}
402
403/* Update the expiration timer for <ts> but do not touch its expiration node.
404 * The table's expiration timer is updated using the date of expiration coming from
405 * <t> stick-table configuration.
406 * The node will be also inserted into the update tree if needed, at a position
407 * considering the update was made locally
408 */
409void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200410{
411 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
412
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100413 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200414 __stktable_touch_with_exp(t, ts, 1, expire);
415 if (decrefcnt)
416 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100417 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200418}
Willy Tarreau43e90352018-06-27 06:25:57 +0200419/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
420static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200421{
Willy Tarreau43e90352018-06-27 06:25:57 +0200422 if (!ts)
423 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100424 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200425 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100426 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200427}
428
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200429/* Insert new sticky session <ts> in the table. It is assumed that it does not
430 * yet exist (the caller must check this). The table's timeout is updated if it
431 * is set. <ts> is returned.
432 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200434{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100435
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200436 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200437 ts->exp.key = ts->expire;
438 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200439 if (t->expire) {
440 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
441 task_queue(t->exp_task);
442 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200443}
444
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200445/* Returns a valid or initialized stksess for the specified stktable_key in the
446 * specified table, or NULL if the key was NULL, or if no entry was found nor
447 * could be created. The entry's expiration is updated.
448 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200449struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200450{
451 struct stksess *ts;
452
453 if (!key)
454 return NULL;
455
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200457 if (ts == NULL) {
458 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200459 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200460 if (!ts)
461 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200462 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200463 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200464 return ts;
465}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200466/* Returns a valid or initialized stksess for the specified stktable_key in the
467 * specified table, or NULL if the key was NULL, or if no entry was found nor
468 * could be created. The entry's expiration is updated.
469 * This function locks the table, and the refcount of the entry is increased.
470 */
471struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
472{
473 struct stksess *ts;
474
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100475 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200476 ts = __stktable_get_entry(table, key);
477 if (ts)
478 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100479 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200480
481 return ts;
482}
483
484/* Lookup for an entry with the same key and store the submitted
485 * stksess if not found.
486 */
487struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
488{
489 struct stksess *ts;
490
491 ts = __stktable_lookup(table, nts);
492 if (ts == NULL) {
493 ts = nts;
494 __stktable_store(table, ts);
495 }
496 return ts;
497}
498
499/* Lookup for an entry with the same key and store the submitted
500 * stksess if not found.
501 * This function locks the table, and the refcount of the entry is increased.
502 */
503struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
504{
505 struct stksess *ts;
506
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100507 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508 ts = __stktable_set_entry(table, nts);
509 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100510 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200511
Emeric Brun819fc6f2017-06-13 19:37:32 +0200512 return ts;
513}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100514/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200515 * Trash expired sticky sessions from table <t>. The next expiration date is
516 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100517 */
518static int stktable_trash_expired(struct stktable *t)
519{
520 struct stksess *ts;
521 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200522 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100523
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100524 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100525 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
526
527 while (1) {
528 if (unlikely(!eb)) {
529 /* we might have reached the end of the tree, typically because
530 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200531 * half. Let's loop back to the beginning of the tree now if we
532 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100533 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200534 if (looped)
535 break;
536 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100537 eb = eb32_first(&t->exps);
538 if (likely(!eb))
539 break;
540 }
541
542 if (likely(tick_is_lt(now_ms, eb->key))) {
543 /* timer not expired yet, revisit it later */
544 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100545 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100546 }
547
548 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200549 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100550 eb = eb32_next(eb);
551
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200552 /* don't delete an entry which is currently referenced */
553 if (ts->ref_cnt)
554 continue;
555
Willy Tarreau86257dc2010-06-06 12:57:10 +0200556 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100557
558 if (!tick_is_expired(ts->expire, now_ms)) {
559 if (!tick_isset(ts->expire))
560 continue;
561
Willy Tarreau86257dc2010-06-06 12:57:10 +0200562 ts->exp.key = ts->expire;
563 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100564
Willy Tarreau86257dc2010-06-06 12:57:10 +0200565 if (!eb || eb->key > ts->exp.key)
566 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100567 continue;
568 }
569
570 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200571 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200572 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200573 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100574 }
575
576 /* We have found no task to expire in any tree */
577 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100578out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100579 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100580 return t->exp_next;
581}
582
583/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200584 * Task processing function to trash expired sticky sessions. A pointer to the
585 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100586 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200587static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100588{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200589 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100590
591 task->expire = stktable_trash_expired(t);
592 return task;
593}
594
Willy Tarreauaea940e2010-06-06 11:56:36 +0200595/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100596int stktable_init(struct stktable *t)
597{
598 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200599 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100601 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100602 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100603
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100604 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 +0100605
606 t->exp_next = TICK_ETERNITY;
607 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200608 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200609 if (!t->exp_task)
610 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100611 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100612 t->exp_task->context = (void *)t;
613 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200614 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200615 peers_register_table(t->peers.p, t);
616 }
617
Emeric Brun3bd697e2010-01-04 15:23:48 +0100618 return t->pool != NULL;
619 }
620 return 1;
621}
622
623/*
624 * Configuration keywords of known table types
625 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200626struct stktable_type stktable_types[SMP_TYPES] = {
627 [SMP_T_SINT] = { "integer", 0, 4 },
628 [SMP_T_IPV4] = { "ip", 0, 4 },
629 [SMP_T_IPV6] = { "ipv6", 0, 16 },
630 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
631 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
632};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100633
634/*
635 * Parse table type configuration.
636 * Returns 0 on successful parsing, else 1.
637 * <myidx> is set at next configuration <args> index.
638 */
639int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
640{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200641 for (*type = 0; *type < SMP_TYPES; (*type)++) {
642 if (!stktable_types[*type].kw)
643 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100644 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
645 continue;
646
647 *key_size = stktable_types[*type].default_size;
648 (*myidx)++;
649
Willy Tarreauaea940e2010-06-06 11:56:36 +0200650 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100651 if (strcmp("len", args[*myidx]) == 0) {
652 (*myidx)++;
653 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200654 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200656 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200657 /* null terminated string needs +1 for '\0'. */
658 (*key_size)++;
659 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100660 (*myidx)++;
661 }
662 }
663 return 0;
664 }
665 return 1;
666}
667
Frédéric Lécailled456aa42019-03-08 14:47:00 +0100668/*
669 * Parse a line with <linenum> as number in <file> configuration file to configure the
670 * stick-table with <t> as address and <id> as ID.
671 * <peers> provides the "peers" section pointer only if this function is called from a "peers" section.
672 * Return an error status with ERR_* flags set if required, 0 if no error was encountered.
673 */
674int parse_stick_table(const char *file, int linenum, char **args,
675 struct stktable *t, char *id, struct peers *peers)
676{
677 int err_code = 0;
678 int idx = 1;
679 unsigned int val;
680
681 if (!id || !*id) {
682 ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]);
683 err_code |= ERR_ALERT | ERR_ABORT;
684 goto out;
685 }
686
687 /* Store the "peers" section if this function is called from a "peers" section. */
688 if (peers) {
689 t->peers.p = peers;
690 idx++;
691 }
692
693 t->id = id;
694 t->type = (unsigned int)-1;
695 t->conf.file = file;
696 t->conf.line = linenum;
697
698 while (*args[idx]) {
699 const char *err;
700
701 if (strcmp(args[idx], "size") == 0) {
702 idx++;
703 if (!*(args[idx])) {
704 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
705 file, linenum, args[0], args[idx-1]);
706 err_code |= ERR_ALERT | ERR_FATAL;
707 goto out;
708 }
709 if ((err = parse_size_err(args[idx], &t->size))) {
710 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
711 file, linenum, args[0], *err, args[idx-1]);
712 err_code |= ERR_ALERT | ERR_FATAL;
713 goto out;
714 }
715 idx++;
716 }
717 /* This argument does not exit in "peers" section. */
718 else if (!peers && strcmp(args[idx], "peers") == 0) {
719 idx++;
720 if (!*(args[idx])) {
721 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
722 file, linenum, args[0], args[idx-1]);
723 err_code |= ERR_ALERT | ERR_FATAL;
724 goto out;
725 }
726 t->peers.name = strdup(args[idx++]);
727 }
728 else if (strcmp(args[idx], "expire") == 0) {
729 idx++;
730 if (!*(args[idx])) {
731 ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
732 file, linenum, args[0], args[idx-1]);
733 err_code |= ERR_ALERT | ERR_FATAL;
734 goto out;
735 }
736 err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
737 if (err) {
738 ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
739 file, linenum, args[0], *err, args[idx-1]);
740 err_code |= ERR_ALERT | ERR_FATAL;
741 goto out;
742 }
743 if (val > INT_MAX) {
744 ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n",
745 file, linenum, val);
746 err_code |= ERR_ALERT | ERR_FATAL;
747 goto out;
748 }
749 t->expire = val;
750 idx++;
751 }
752 else if (strcmp(args[idx], "nopurge") == 0) {
753 t->nopurge = 1;
754 idx++;
755 }
756 else if (strcmp(args[idx], "type") == 0) {
757 idx++;
758 if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) {
759 ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n",
760 file, linenum, args[0], args[idx]);
761 err_code |= ERR_ALERT | ERR_FATAL;
762 goto out;
763 }
764 /* idx already points to next arg */
765 }
766 else if (strcmp(args[idx], "store") == 0) {
767 int type, err;
768 char *cw, *nw, *sa;
769
770 idx++;
771 nw = args[idx];
772 while (*nw) {
773 /* the "store" keyword supports a comma-separated list */
774 cw = nw;
775 sa = NULL; /* store arg */
776 while (*nw && *nw != ',') {
777 if (*nw == '(') {
778 *nw = 0;
779 sa = ++nw;
780 while (*nw != ')') {
781 if (!*nw) {
782 ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n",
783 file, linenum, args[0], cw);
784 err_code |= ERR_ALERT | ERR_FATAL;
785 goto out;
786 }
787 nw++;
788 }
789 *nw = '\0';
790 }
791 nw++;
792 }
793 if (*nw)
794 *nw++ = '\0';
795 type = stktable_get_data_type(cw);
796 if (type < 0) {
797 ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n",
798 file, linenum, args[0], cw);
799 err_code |= ERR_ALERT | ERR_FATAL;
800 goto out;
801 }
802
803 err = stktable_alloc_data_type(t, type, sa);
804 switch (err) {
805 case PE_NONE: break;
806 case PE_EXIST:
807 ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n",
808 file, linenum, args[0], cw);
809 err_code |= ERR_WARN;
810 break;
811
812 case PE_ARG_MISSING:
813 ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n",
814 file, linenum, args[0], cw);
815 err_code |= ERR_ALERT | ERR_FATAL;
816 goto out;
817
818 case PE_ARG_NOT_USED:
819 ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n",
820 file, linenum, args[0], cw);
821 err_code |= ERR_ALERT | ERR_FATAL;
822 goto out;
823
824 default:
825 ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
826 file, linenum, args[0], cw);
827 err_code |= ERR_ALERT | ERR_FATAL;
828 goto out;
829 }
830 }
831 idx++;
832 }
833 else {
834 ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
835 file, linenum, args[0], args[idx]);
836 err_code |= ERR_ALERT | ERR_FATAL;
837 goto out;
838 }
839 }
840
841 if (!t->size) {
842 ha_alert("parsing [%s:%d] : %s: missing size.\n",
843 file, linenum, args[0]);
844 err_code |= ERR_ALERT | ERR_FATAL;
845 goto out;
846 }
847
848 if (t->type == (unsigned int)-1) {
849 ha_alert("parsing [%s:%d] : %s: missing type.\n",
850 file, linenum, args[0]);
851 err_code |= ERR_ALERT | ERR_FATAL;
852 goto out;
853 }
854
855 out:
856 return err_code;
857}
858
Willy Tarreau8fed9032014-07-03 17:02:46 +0200859/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200860 * Note that the sample *is* modified and that the returned key may point
861 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200862 * Returns NULL if the sample could not be converted (eg: no matching type),
863 * otherwise a pointer to the static stktable_key filled with what is needed
864 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200865 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200866struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200867{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200868 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200869 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200870 return NULL;
871
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200872 /* Fill static_table_key. */
873 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200874
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200875 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200876 static_table_key.key = &smp->data.u.ipv4;
877 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200878 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200879
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200880 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200881 static_table_key.key = &smp->data.u.ipv6;
882 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200883 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200884
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200885 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200886 /* The stick table require a 32bit unsigned int, "sint" is a
887 * signed 64 it, so we can convert it inplace.
888 */
889 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200890 static_table_key.key = &smp->data.u.sint;
891 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200892 break;
893
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200894 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200895 if (!smp_make_safe(smp))
896 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200897 static_table_key.key = smp->data.u.str.area;
898 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200899 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200900
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200901 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200902 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200903 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200904 if (!smp_make_rw(smp))
905 return NULL;
906
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200907 if (smp->data.u.str.size < t->key_size)
908 if (!smp_dup(smp))
909 return NULL;
910 if (smp->data.u.str.size < t->key_size)
911 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200912 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
913 t->key_size - smp->data.u.str.data);
914 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200915 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200916 static_table_key.key = smp->data.u.str.area;
917 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200918 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200919
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200920 default: /* impossible case. */
921 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200922 }
923
Christopher Fauletca20d022017-08-29 15:30:31 +0200924 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200925}
926
927/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200928 * Process a fetch + format conversion as defined by the sample expression <expr>
929 * on request or response considering the <opt> parameter. Returns either NULL if
930 * no key could be extracted, or a pointer to the converted result stored in
931 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
932 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200933 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
934 * without SMP_OPT_FINAL). The output will be usable like this :
935 *
936 * return MAY_CHANGE FINAL Meaning for the sample
937 * NULL 0 * Not present and will never be (eg: header)
938 * NULL 1 0 Not present or unstable, could change (eg: req_len)
939 * NULL 1 1 Not present, will not change anymore
940 * smp 0 * Present and will not change (eg: header)
941 * smp 1 0 not possible
942 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200943 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200944struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200945 unsigned int opt, struct sample_expr *expr, struct sample *smp)
946{
947 if (smp)
948 memset(smp, 0, sizeof(*smp));
949
Willy Tarreau192252e2015-04-04 01:47:55 +0200950 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200951 if (!smp)
952 return NULL;
953
954 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
955 return NULL; /* we can only use stable samples */
956
957 return smp_to_stkey(smp, t);
958}
959
960/*
Willy Tarreau12785782012-04-27 21:37:17 +0200961 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200962 * type <table_type>, otherwise zero. Used in configuration check.
963 */
Willy Tarreau12785782012-04-27 21:37:17 +0200964int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200965{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100966 int out_type;
967
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200968 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200969 return 0;
970
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100971 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200972
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200973 /* Convert sample. */
974 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100975 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200976
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200977 return 1;
978}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100979
Willy Tarreauedee1d62014-07-15 16:44:27 +0200980/* Extra data types processing : after the last one, some room may remain
981 * before STKTABLE_DATA_TYPES that may be used to register extra data types
982 * at run time.
983 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200984struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200985 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200986 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200987 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200988 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200989 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
990 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
991 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
992 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
993 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
994 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
995 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
996 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
997 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
998 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
999 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
1000 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
1001 [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 +01001002 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
1003 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +02001004};
1005
Willy Tarreauedee1d62014-07-15 16:44:27 +02001006/* Registers stick-table extra data type with index <idx>, name <name>, type
1007 * <std_type> and arg type <arg_type>. If the index is negative, the next free
1008 * index is automatically allocated. The allocated index is returned, or -1 if
1009 * no free index was found or <name> was already registered. The <name> is used
1010 * directly as a pointer, so if it's not stable, the caller must allocate it.
1011 */
1012int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
1013{
1014 if (idx < 0) {
1015 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
1016 if (!stktable_data_types[idx].name)
1017 break;
1018
1019 if (strcmp(stktable_data_types[idx].name, name) == 0)
1020 return -1;
1021 }
1022 }
1023
1024 if (idx >= STKTABLE_DATA_TYPES)
1025 return -1;
1026
1027 if (stktable_data_types[idx].name != NULL)
1028 return -1;
1029
1030 stktable_data_types[idx].name = name;
1031 stktable_data_types[idx].std_type = std_type;
1032 stktable_data_types[idx].arg_type = arg_type;
1033 return idx;
1034}
1035
Willy Tarreau08d5f982010-06-06 13:34:54 +02001036/*
1037 * Returns the data type number for the stktable_data_type whose name is <name>,
1038 * or <0 if not found.
1039 */
1040int stktable_get_data_type(char *name)
1041{
1042 int type;
1043
1044 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +02001045 if (!stktable_data_types[type].name)
1046 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +02001047 if (strcmp(name, stktable_data_types[type].name) == 0)
1048 return type;
1049 }
1050 return -1;
1051}
1052
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001053/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1054 * it up into this table. Returns true if found, false otherwise. The input
1055 * type is STR so that input samples are converted to string (since all types
1056 * can be converted to strings), then the function casts the string again into
1057 * the table's type. This is a double conversion, but in the future we might
1058 * support automatic input types to perform the cast on the fly.
1059 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001060static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001061{
1062 struct stktable *t;
1063 struct stktable_key *key;
1064 struct stksess *ts;
1065
1066 t = &arg_p[0].data.prx->table;
1067
1068 key = smp_to_stkey(smp, t);
1069 if (!key)
1070 return 0;
1071
1072 ts = stktable_lookup_key(t, key);
1073
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001074 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001075 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001076 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +02001077 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001078 return 1;
1079}
1080
1081/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1082 * it up into this table. Returns the data rate received from clients in bytes/s
1083 * if the key is present in the table, otherwise zero, so that comparisons can
1084 * be easily performed. If the inspected parameter is not stored in the table,
1085 * <not found> is returned.
1086 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001087static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001088{
1089 struct stktable *t;
1090 struct stktable_key *key;
1091 struct stksess *ts;
1092 void *ptr;
1093
1094 t = &arg_p[0].data.prx->table;
1095
1096 key = smp_to_stkey(smp, t);
1097 if (!key)
1098 return 0;
1099
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001100 ts = stktable_lookup_key(t, key);
1101
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001102 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001103 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001104 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001105
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001106 if (!ts) /* key not present */
1107 return 1;
1108
1109 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001110 if (ptr)
1111 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
1112 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001113
Daniel Corbett3e60b112018-05-27 09:47:12 -04001114 stktable_release(t, ts);
1115 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001116}
1117
1118/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1119 * it up into this table. Returns the cumulated number of connections for the key
1120 * if the key is present in the table, otherwise zero, so that comparisons can
1121 * be easily performed. If the inspected parameter is not stored in the table,
1122 * <not found> is returned.
1123 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001124static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001125{
1126 struct stktable *t;
1127 struct stktable_key *key;
1128 struct stksess *ts;
1129 void *ptr;
1130
1131 t = &arg_p[0].data.prx->table;
1132
1133 key = smp_to_stkey(smp, t);
1134 if (!key)
1135 return 0;
1136
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001137 ts = stktable_lookup_key(t, key);
1138
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001139 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001140 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001141 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001142
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001143 if (!ts) /* key not present */
1144 return 1;
1145
1146 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001147 if (ptr)
1148 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
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 number of concurrent connections for the
1156 * key if the key is present in the table, otherwise zero, so that comparisons
1157 * can be easily performed. If the inspected parameter is not stored in the
1158 * table, <not found> is returned.
1159 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001160static int sample_conv_table_conn_cur(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
1167 t = &arg_p[0].data.prx->table;
1168
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_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001183 if (ptr)
1184 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
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 rate of incoming connections from the key
1192 * if the key is present in the table, otherwise zero, so that comparisons can
1193 * be easily performed. If the inspected parameter is not stored in the table,
1194 * <not found> is returned.
1195 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001196static int sample_conv_table_conn_rate(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
1203 t = &arg_p[0].data.prx->table;
1204
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_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001219 if (ptr)
1220 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1221 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001222
Daniel Corbett3e60b112018-05-27 09:47:12 -04001223 stktable_release(t, ts);
1224 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001225}
1226
1227/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1228 * it up into this table. Returns the data rate sent to clients in bytes/s
1229 * if the key is present in the table, otherwise zero, so that comparisons can
1230 * be easily performed. If the inspected parameter is not stored in the table,
1231 * <not found> is returned.
1232 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001233static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001234{
1235 struct stktable *t;
1236 struct stktable_key *key;
1237 struct stksess *ts;
1238 void *ptr;
1239
1240 t = &arg_p[0].data.prx->table;
1241
1242 key = smp_to_stkey(smp, t);
1243 if (!key)
1244 return 0;
1245
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001246 ts = stktable_lookup_key(t, key);
1247
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001248 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001249 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001250 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001252 if (!ts) /* key not present */
1253 return 1;
1254
1255 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001256 if (ptr)
1257 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1258 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001259
Daniel Corbett3e60b112018-05-27 09:47:12 -04001260 stktable_release(t, ts);
1261 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001262}
1263
1264/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001265 * it up into this table. Returns the value of the GPT0 tag for the key
1266 * if the key is present in the table, otherwise false, so that comparisons can
1267 * be easily performed. If the inspected parameter is not stored in the table,
1268 * <not found> is returned.
1269 */
1270static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1271{
1272 struct stktable *t;
1273 struct stktable_key *key;
1274 struct stksess *ts;
1275 void *ptr;
1276
1277 t = &arg_p[0].data.prx->table;
1278
1279 key = smp_to_stkey(smp, t);
1280 if (!key)
1281 return 0;
1282
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001283 ts = stktable_lookup_key(t, key);
1284
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001285 smp->flags = SMP_F_VOL_TEST;
1286 smp->data.type = SMP_T_SINT;
1287 smp->data.u.sint = 0;
1288
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001289 if (!ts) /* key not present */
1290 return 1;
1291
1292 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001293 if (ptr)
1294 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001295
Daniel Corbett3e60b112018-05-27 09:47:12 -04001296 stktable_release(t, ts);
1297 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001298}
1299
1300/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301 * it up into this table. Returns the value of the GPC0 counter for the key
1302 * if the key is present in the table, otherwise zero, so that comparisons can
1303 * be easily performed. If the inspected parameter is not stored in the table,
1304 * <not found> is returned.
1305 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001306static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307{
1308 struct stktable *t;
1309 struct stktable_key *key;
1310 struct stksess *ts;
1311 void *ptr;
1312
1313 t = &arg_p[0].data.prx->table;
1314
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
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001321 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001322 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001323 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001324
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001325 if (!ts) /* key not present */
1326 return 1;
1327
1328 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001329 if (ptr)
1330 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001331
Daniel Corbett3e60b112018-05-27 09:47:12 -04001332 stktable_release(t, ts);
1333 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334}
1335
1336/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1337 * it up into this table. Returns the event rate 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_rate(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
1349 t = &arg_p[0].data.prx->table;
1350
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_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001365 if (ptr)
1366 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1367 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001368
Daniel Corbett3e60b112018-05-27 09:47:12 -04001369 stktable_release(t, ts);
1370 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001371}
1372
1373/* 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 +01001374 * it up into this table. Returns the value of the GPC1 counter for the key
1375 * if the key is present in the table, otherwise zero, so that comparisons can
1376 * be easily performed. If the inspected parameter is not stored in the table,
1377 * <not found> is returned.
1378 */
1379static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1380{
1381 struct stktable *t;
1382 struct stktable_key *key;
1383 struct stksess *ts;
1384 void *ptr;
1385
1386 t = &arg_p[0].data.prx->table;
1387
1388 key = smp_to_stkey(smp, t);
1389 if (!key)
1390 return 0;
1391
1392 ts = stktable_lookup_key(t, key);
1393
1394 smp->flags = SMP_F_VOL_TEST;
1395 smp->data.type = SMP_T_SINT;
1396 smp->data.u.sint = 0;
1397
1398 if (!ts) /* key not present */
1399 return 1;
1400
1401 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001402 if (ptr)
1403 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001404
Daniel Corbett3e60b112018-05-27 09:47:12 -04001405 stktable_release(t, ts);
1406 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001407}
1408
1409/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1410 * it up into this table. Returns the event rate 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_rate(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
1422 t = &arg_p[0].data.prx->table;
1423
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_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001438 if (ptr)
1439 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1440 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001441
Daniel Corbett3e60b112018-05-27 09:47:12 -04001442 stktable_release(t, ts);
1443 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001444}
1445
1446/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001447 * it up into this table. Returns the cumulated number of HTTP request errors
1448 * for the key if the key is present in the table, otherwise zero, so that
1449 * comparisons can be easily performed. If the inspected parameter is not stored
1450 * in the table, <not found> is returned.
1451 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001452static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453{
1454 struct stktable *t;
1455 struct stktable_key *key;
1456 struct stksess *ts;
1457 void *ptr;
1458
1459 t = &arg_p[0].data.prx->table;
1460
1461 key = smp_to_stkey(smp, t);
1462 if (!key)
1463 return 0;
1464
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001465 ts = stktable_lookup_key(t, key);
1466
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001467 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001468 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001469 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001471 if (!ts) /* key not present */
1472 return 1;
1473
1474 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001475 if (ptr)
1476 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001477
Daniel Corbett3e60b112018-05-27 09:47:12 -04001478 stktable_release(t, ts);
1479 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001480}
1481
1482/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1483 * it up into this table. Returns the HTTP request error rate the key
1484 * if the key is present in the table, otherwise zero, so that comparisons can
1485 * be easily performed. If the inspected parameter is not stored in the table,
1486 * <not found> is returned.
1487 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001488static int sample_conv_table_http_err_rate(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
1495 t = &arg_p[0].data.prx->table;
1496
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_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001511 if (ptr)
1512 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1513 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001514
Daniel Corbett3e60b112018-05-27 09:47:12 -04001515 stktable_release(t, ts);
1516 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001517}
1518
1519/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1520 * it up into this table. Returns the cumulated number of HTTP request for the
1521 * key if the key is present in the table, otherwise zero, so that comparisons
1522 * can be easily performed. If the inspected parameter is not stored in the
1523 * table, <not found> is returned.
1524 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001525static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001526{
1527 struct stktable *t;
1528 struct stktable_key *key;
1529 struct stksess *ts;
1530 void *ptr;
1531
1532 t = &arg_p[0].data.prx->table;
1533
1534 key = smp_to_stkey(smp, t);
1535 if (!key)
1536 return 0;
1537
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001538 ts = stktable_lookup_key(t, key);
1539
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001540 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001541 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001542 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001543
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001544 if (!ts) /* key not present */
1545 return 1;
1546
1547 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001548 if (ptr)
1549 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
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 HTTP request rate the key if the key is
1557 * present in the table, otherwise zero, so that comparisons can be easily
1558 * performed. If the inspected parameter is not stored in the table, <not found>
1559 * is returned.
1560 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001561static int sample_conv_table_http_req_rate(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
1568 t = &arg_p[0].data.prx->table;
1569
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_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001584 if (ptr)
1585 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1586 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001587
Daniel Corbett3e60b112018-05-27 09:47:12 -04001588 stktable_release(t, ts);
1589 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001590}
1591
1592/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1593 * it up into this table. Returns the volume of datareceived from clients in kbytes
1594 * if the key is present in the table, otherwise zero, so that comparisons can
1595 * be easily performed. If the inspected parameter is not stored in the table,
1596 * <not found> is returned.
1597 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001598static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599{
1600 struct stktable *t;
1601 struct stktable_key *key;
1602 struct stksess *ts;
1603 void *ptr;
1604
1605 t = &arg_p[0].data.prx->table;
1606
1607 key = smp_to_stkey(smp, t);
1608 if (!key)
1609 return 0;
1610
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001611 ts = stktable_lookup_key(t, key);
1612
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001613 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001614 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001615 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001616
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001617 if (!ts) /* key not present */
1618 return 1;
1619
1620 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001621 if (ptr)
1622 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
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 data sent to 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_out(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
1641 t = &arg_p[0].data.prx->table;
1642
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_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001657 if (ptr)
1658 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_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 server ID associated with the key if the
1666 * key is present in the table, otherwise zero, so that comparisons can be
1667 * 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_server_id(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
1677 t = &arg_p[0].data.prx->table;
1678
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_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001693 if (ptr)
1694 smp->data.u.sint = stktable_data_cast(ptr, server_id);
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 cumulated number of sessions for the
1702 * key if the key is present in the table, otherwise zero, so that comparisons
1703 * can be easily performed. If the inspected parameter is not stored in the
1704 * table, <not found> is returned.
1705 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001706static int sample_conv_table_sess_cnt(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
1713 t = &arg_p[0].data.prx->table;
1714
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_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001729 if (ptr)
1730 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
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 session rate the key if the key is
1738 * present in the table, otherwise zero, so that comparisons can be easily
1739 * performed. If the inspected parameter is not stored in the table, <not found>
1740 * is returned.
1741 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001742static int sample_conv_table_sess_rate(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
1749 t = &arg_p[0].data.prx->table;
1750
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_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001765 if (ptr)
1766 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1767 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001768
Daniel Corbett3e60b112018-05-27 09:47:12 -04001769 stktable_release(t, ts);
1770 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001771}
1772
1773/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1774 * it up into this table. Returns the amount of concurrent connections tracking
1775 * the same key if the key is present in the table, otherwise zero, so that
1776 * comparisons can be easily performed. If the inspected parameter is not
1777 * stored in the table, <not found> is returned.
1778 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001779static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001780{
1781 struct stktable *t;
1782 struct stktable_key *key;
1783 struct stksess *ts;
1784
1785 t = &arg_p[0].data.prx->table;
1786
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
Tim Duesterhus65189c12018-06-26 15:57:29 +02001797 if (!ts)
1798 return 1;
1799
1800 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001801
Daniel Corbett3e60b112018-05-27 09:47:12 -04001802 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001803 return 1;
1804}
1805
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001806/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001807static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001808 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001809{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001810 struct stksess *ts;
1811 struct stkctr *stkctr;
1812
1813 /* Extract the stksess, return OK if no stksess available. */
1814 if (s)
1815 stkctr = &s->stkctr[rule->arg.gpc.sc];
1816 else
1817 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001818
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001819 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001820 if (ts) {
1821 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001822
Willy Tarreau79c1e912016-01-25 14:54:45 +01001823 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1824 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001825 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1826 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001827 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001828
1829 if (ptr1)
1830 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001831 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001832
Emeric Brun819fc6f2017-06-13 19:37:32 +02001833 if (ptr2)
1834 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001835
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001836 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001837
1838 /* If data was modified, we need to touch to re-schedule sync */
1839 stktable_touch_local(stkctr->table, ts, 0);
1840 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001841 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001842 return ACT_RET_CONT;
1843}
1844
1845/* This function is a common parser for using variables. It understands
1846 * the formats:
1847 *
1848 * sc-inc-gpc0(<stick-table ID>)
1849 *
1850 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1851 * it returns 1 and the variable <expr> is filled with the pointer to the
1852 * expression to execute.
1853 */
1854static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1855 struct act_rule *rule, char **err)
1856{
1857 const char *cmd_name = args[*arg-1];
1858 char *error;
1859
1860 cmd_name += strlen("sc-inc-gpc0");
1861 if (*cmd_name == '\0') {
1862 /* default stick table id. */
1863 rule->arg.gpc.sc = 0;
1864 } else {
1865 /* parse the stick table id. */
1866 if (*cmd_name != '(') {
1867 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1868 return ACT_RET_PRS_ERR;
1869 }
1870 cmd_name++; /* jump the '(' */
1871 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1872 if (*error != ')') {
1873 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1874 return ACT_RET_PRS_ERR;
1875 }
1876
1877 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1878 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1879 ACT_ACTION_TRK_SCMAX-1);
1880 return ACT_RET_PRS_ERR;
1881 }
1882 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001883 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001884 rule->action_ptr = action_inc_gpc0;
1885 return ACT_RET_PRS_OK;
1886}
1887
1888/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001889static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1890 struct session *sess, struct stream *s, int flags)
1891{
1892 struct stksess *ts;
1893 struct stkctr *stkctr;
1894
1895 /* Extract the stksess, return OK if no stksess available. */
1896 if (s)
1897 stkctr = &s->stkctr[rule->arg.gpc.sc];
1898 else
1899 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1900
1901 ts = stkctr_entry(stkctr);
1902 if (ts) {
1903 void *ptr1, *ptr2;
1904
1905 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1906 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1907 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1908 if (ptr1 || ptr2) {
1909 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1910
1911 if (ptr1)
1912 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1913 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1914
1915 if (ptr2)
1916 stktable_data_cast(ptr2, gpc1)++;
1917
1918 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1919
1920 /* If data was modified, we need to touch to re-schedule sync */
1921 stktable_touch_local(stkctr->table, ts, 0);
1922 }
1923 }
1924 return ACT_RET_CONT;
1925}
1926
1927/* This function is a common parser for using variables. It understands
1928 * the formats:
1929 *
1930 * sc-inc-gpc1(<stick-table ID>)
1931 *
1932 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1933 * it returns 1 and the variable <expr> is filled with the pointer to the
1934 * expression to execute.
1935 */
1936static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1937 struct act_rule *rule, char **err)
1938{
1939 const char *cmd_name = args[*arg-1];
1940 char *error;
1941
1942 cmd_name += strlen("sc-inc-gpc1");
1943 if (*cmd_name == '\0') {
1944 /* default stick table id. */
1945 rule->arg.gpc.sc = 0;
1946 } else {
1947 /* parse the stick table id. */
1948 if (*cmd_name != '(') {
1949 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1950 return ACT_RET_PRS_ERR;
1951 }
1952 cmd_name++; /* jump the '(' */
1953 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1954 if (*error != ')') {
1955 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1956 return ACT_RET_PRS_ERR;
1957 }
1958
1959 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1960 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1961 ACT_ACTION_TRK_SCMAX-1);
1962 return ACT_RET_PRS_ERR;
1963 }
1964 }
1965 rule->action = ACT_CUSTOM;
1966 rule->action_ptr = action_inc_gpc1;
1967 return ACT_RET_PRS_OK;
1968}
1969
1970/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001971static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001972 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001973{
1974 void *ptr;
1975 struct stksess *ts;
1976 struct stkctr *stkctr;
1977
1978 /* Extract the stksess, return OK if no stksess available. */
1979 if (s)
1980 stkctr = &s->stkctr[rule->arg.gpt.sc];
1981 else
1982 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001983
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001984 ts = stkctr_entry(stkctr);
1985 if (!ts)
1986 return ACT_RET_CONT;
1987
1988 /* Store the sample in the required sc, and ignore errors. */
1989 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001990 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001991 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001992
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001993 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001994
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001995 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001996
1997 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001998 }
1999
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002000 return ACT_RET_CONT;
2001}
2002
2003/* This function is a common parser for using variables. It understands
2004 * the format:
2005 *
2006 * set-gpt0(<stick-table ID>) <expression>
2007 *
2008 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
2009 * it returns 1 and the variable <expr> is filled with the pointer to the
2010 * expression to execute.
2011 */
2012static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
2013 struct act_rule *rule, char **err)
2014
2015
2016{
2017 const char *cmd_name = args[*arg-1];
2018 char *error;
2019
2020 cmd_name += strlen("sc-set-gpt0");
2021 if (*cmd_name == '\0') {
2022 /* default stick table id. */
2023 rule->arg.gpt.sc = 0;
2024 } else {
2025 /* parse the stick table id. */
2026 if (*cmd_name != '(') {
2027 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2028 return ACT_RET_PRS_ERR;
2029 }
2030 cmd_name++; /* jump the '(' */
2031 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
2032 if (*error != ')') {
2033 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
2034 return ACT_RET_PRS_ERR;
2035 }
2036
2037 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
2038 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
2039 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
2040 return ACT_RET_PRS_ERR;
2041 }
2042 }
2043
2044 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
2045 if (*error != '\0') {
2046 memprintf(err, "invalid integer value '%s'", args[*arg]);
2047 return ACT_RET_PRS_ERR;
2048 }
2049 (*arg)++;
2050
Thierry FOURNIER42148732015-09-02 17:17:33 +02002051 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02002052 rule->action_ptr = action_set_gpt0;
2053
2054 return ACT_RET_PRS_OK;
2055}
2056
Willy Tarreau7d562212016-11-25 16:10:05 +01002057/* set temp integer to the number of used entries in the table pointed to by expr.
2058 * Accepts exactly 1 argument of type table.
2059 */
2060static int
2061smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2062{
2063 smp->flags = SMP_F_VOL_TEST;
2064 smp->data.type = SMP_T_SINT;
2065 smp->data.u.sint = args->data.prx->table.current;
2066 return 1;
2067}
2068
2069/* set temp integer to the number of free entries in the table pointed to by expr.
2070 * Accepts exactly 1 argument of type table.
2071 */
2072static int
2073smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
2074{
2075 struct proxy *px;
2076
2077 px = args->data.prx;
2078 smp->flags = SMP_F_VOL_TEST;
2079 smp->data.type = SMP_T_SINT;
2080 smp->data.u.sint = px->table.size - px->table.current;
2081 return 1;
2082}
2083
2084/* Returns a pointer to a stkctr depending on the fetch keyword name.
2085 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
2086 * sc[0-9]_* will return a pointer to the respective field in the
2087 * stream <l4>. sc_* requires an UINT argument specifying the stick
2088 * counter number. src_* will fill a locally allocated structure with
2089 * the table and entry corresponding to what is specified with src_*.
2090 * NULL may be returned if the designated stkctr is not tracked. For
2091 * the sc_* and sc[0-9]_* forms, an optional table argument may be
2092 * passed. When present, the currently tracked key is then looked up
2093 * in the specified table instead of the current table. The purpose is
2094 * to be able to convery multiple values per key (eg: have gpc0 from
2095 * multiple tables). <strm> is allowed to be NULL, in which case only
2096 * the session will be consulted.
2097 */
2098struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002099smp_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 +01002100{
Willy Tarreau7d562212016-11-25 16:10:05 +01002101 struct stkctr *stkptr;
2102 struct stksess *stksess;
2103 unsigned int num = kw[2] - '0';
2104 int arg = 0;
2105
2106 if (num == '_' - '0') {
2107 /* sc_* variant, args[0] = ctr# (mandatory) */
2108 num = args[arg++].data.sint;
2109 if (num >= MAX_SESS_STKCTR)
2110 return NULL;
2111 }
2112 else if (num > 9) { /* src_* variant, args[0] = table */
2113 struct stktable_key *key;
2114 struct connection *conn = objt_conn(sess->origin);
2115 struct sample smp;
2116
2117 if (!conn)
2118 return NULL;
2119
Joseph Herlant5662fa42018-11-15 13:43:28 -08002120 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002121 smp.px = NULL;
2122 smp.sess = sess;
2123 smp.strm = strm;
2124 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2125 return NULL;
2126
2127 /* Converts into key. */
2128 key = smp_to_stkey(&smp, &args->data.prx->table);
2129 if (!key)
2130 return NULL;
2131
Emeric Brun819fc6f2017-06-13 19:37:32 +02002132 stkctr->table = &args->data.prx->table;
2133 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
2134 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002135 }
2136
2137 /* Here, <num> contains the counter number from 0 to 9 for
2138 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
2139 * args[arg] is the first optional argument. We first lookup the
2140 * ctr form the stream, then from the session if it was not there.
2141 */
2142
2143 if (strm)
2144 stkptr = &strm->stkctr[num];
2145 if (!strm || !stkctr_entry(stkptr)) {
2146 stkptr = &sess->stkctr[num];
2147 if (!stkctr_entry(stkptr))
2148 return NULL;
2149 }
2150
2151 stksess = stkctr_entry(stkptr);
2152 if (!stksess)
2153 return NULL;
2154
2155 if (unlikely(args[arg].type == ARGT_TAB)) {
2156 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002157 stkctr->table = &args[arg].data.prx->table;
2158 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
2159 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002160 }
2161 return stkptr;
2162}
2163
2164/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
2165 * the entry if it doesn't exist yet. This is needed for a few fetch
2166 * functions which need to create an entry, such as src_inc_gpc* and
2167 * src_clr_gpc*.
2168 */
2169struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02002170smp_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 +01002171{
Willy Tarreau7d562212016-11-25 16:10:05 +01002172 struct stktable_key *key;
2173 struct connection *conn = objt_conn(sess->origin);
2174 struct sample smp;
2175
2176 if (strncmp(kw, "src_", 4) != 0)
2177 return NULL;
2178
2179 if (!conn)
2180 return NULL;
2181
Joseph Herlant5662fa42018-11-15 13:43:28 -08002182 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002183 smp.px = NULL;
2184 smp.sess = sess;
2185 smp.strm = strm;
2186 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
2187 return NULL;
2188
2189 /* Converts into key. */
2190 key = smp_to_stkey(&smp, &args->data.prx->table);
2191 if (!key)
2192 return NULL;
2193
Emeric Brun819fc6f2017-06-13 19:37:32 +02002194 stkctr->table = &args->data.prx->table;
2195 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2196 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002197}
2198
2199/* set return a boolean indicating if the requested stream counter is
2200 * currently being tracked or not.
2201 * Supports being called as "sc[0-9]_tracked" only.
2202 */
2203static int
2204smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2205{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002206 struct stkctr tmpstkctr;
2207 struct stkctr *stkctr;
2208
Willy Tarreau7d562212016-11-25 16:10:05 +01002209 smp->flags = SMP_F_VOL_TEST;
2210 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002211 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2212 smp->data.u.sint = !!stkctr;
2213
2214 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002215 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002216 stktable_release(stkctr->table, stkctr_entry(stkctr));
2217
Willy Tarreau7d562212016-11-25 16:10:05 +01002218 return 1;
2219}
2220
2221/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2222 * frontend counters or from the src.
2223 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2224 * zero is returned if the key is new.
2225 */
2226static int
2227smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2228{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002229 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002230 struct stkctr *stkctr;
2231
Emeric Brun819fc6f2017-06-13 19:37:32 +02002232 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002233 if (!stkctr)
2234 return 0;
2235
2236 smp->flags = SMP_F_VOL_TEST;
2237 smp->data.type = SMP_T_SINT;
2238 smp->data.u.sint = 0;
2239
Emeric Brun819fc6f2017-06-13 19:37:32 +02002240 if (stkctr_entry(stkctr)) {
2241 void *ptr;
2242
2243 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2244 if (!ptr) {
2245 if (stkctr == &tmpstkctr)
2246 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002247 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002248 }
2249
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002250 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002251
Willy Tarreau7d562212016-11-25 16:10:05 +01002252 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002253
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002254 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002255
2256 if (stkctr == &tmpstkctr)
2257 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002258 }
2259 return 1;
2260}
2261
2262/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2263 * frontend counters or from the src.
2264 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2265 * zero is returned if the key is new.
2266 */
2267static int
2268smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2269{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002270 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002271 struct stkctr *stkctr;
2272
Emeric Brun819fc6f2017-06-13 19:37:32 +02002273 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002274 if (!stkctr)
2275 return 0;
2276
2277 smp->flags = SMP_F_VOL_TEST;
2278 smp->data.type = SMP_T_SINT;
2279 smp->data.u.sint = 0;
2280
2281 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002282 void *ptr;
2283
2284 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2285 if (!ptr) {
2286 if (stkctr == &tmpstkctr)
2287 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002288 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002289 }
2290
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002291 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002292
Willy Tarreau7d562212016-11-25 16:10:05 +01002293 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002294
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002295 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002296
2297 if (stkctr == &tmpstkctr)
2298 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002299 }
2300 return 1;
2301}
2302
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002303/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2304 * frontend counters or from the src.
2305 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2306 * zero is returned if the key is new.
2307 */
2308static int
2309smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2310{
2311 struct stkctr tmpstkctr;
2312 struct stkctr *stkctr;
2313
2314 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2315 if (!stkctr)
2316 return 0;
2317
2318 smp->flags = SMP_F_VOL_TEST;
2319 smp->data.type = SMP_T_SINT;
2320 smp->data.u.sint = 0;
2321
2322 if (stkctr_entry(stkctr) != NULL) {
2323 void *ptr;
2324
2325 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2326 if (!ptr) {
2327 if (stkctr == &tmpstkctr)
2328 stktable_release(stkctr->table, stkctr_entry(stkctr));
2329 return 0; /* parameter not stored */
2330 }
2331
2332 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2333
2334 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2335
2336 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2337
2338 if (stkctr == &tmpstkctr)
2339 stktable_release(stkctr->table, stkctr_entry(stkctr));
2340 }
2341 return 1;
2342}
2343
Willy Tarreau7d562212016-11-25 16:10:05 +01002344/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2345 * tracked frontend counters or from the src.
2346 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2347 * Value zero is returned if the key is new.
2348 */
2349static int
2350smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2351{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002352 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002353 struct stkctr *stkctr;
2354
Emeric Brun819fc6f2017-06-13 19:37:32 +02002355 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002356 if (!stkctr)
2357 return 0;
2358
2359 smp->flags = SMP_F_VOL_TEST;
2360 smp->data.type = SMP_T_SINT;
2361 smp->data.u.sint = 0;
2362 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002363 void *ptr;
2364
2365 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2366 if (!ptr) {
2367 if (stkctr == &tmpstkctr)
2368 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002369 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002370 }
2371
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002372 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002373
Willy Tarreau7d562212016-11-25 16:10:05 +01002374 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2375 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002376
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002377 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002378
2379 if (stkctr == &tmpstkctr)
2380 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002381 }
2382 return 1;
2383}
2384
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002385/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2386 * tracked frontend counters or from the src.
2387 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2388 * Value zero is returned if the key is new.
2389 */
2390static int
2391smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2392{
2393 struct stkctr tmpstkctr;
2394 struct stkctr *stkctr;
2395
2396 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2397 if (!stkctr)
2398 return 0;
2399
2400 smp->flags = SMP_F_VOL_TEST;
2401 smp->data.type = SMP_T_SINT;
2402 smp->data.u.sint = 0;
2403 if (stkctr_entry(stkctr) != NULL) {
2404 void *ptr;
2405
2406 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2407 if (!ptr) {
2408 if (stkctr == &tmpstkctr)
2409 stktable_release(stkctr->table, stkctr_entry(stkctr));
2410 return 0; /* parameter not stored */
2411 }
2412
2413 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2414
2415 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2416 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2417
2418 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2419
2420 if (stkctr == &tmpstkctr)
2421 stktable_release(stkctr->table, stkctr_entry(stkctr));
2422 }
2423 return 1;
2424}
2425
Willy Tarreau7d562212016-11-25 16:10:05 +01002426/* Increment the General Purpose Counter 0 value from the stream's tracked
2427 * frontend counters and return it into temp integer.
2428 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2429 */
2430static int
2431smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2432{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002433 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002434 struct stkctr *stkctr;
2435
Emeric Brun819fc6f2017-06-13 19:37:32 +02002436 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002437 if (!stkctr)
2438 return 0;
2439
2440 smp->flags = SMP_F_VOL_TEST;
2441 smp->data.type = SMP_T_SINT;
2442 smp->data.u.sint = 0;
2443
Emeric Brun819fc6f2017-06-13 19:37:32 +02002444 if (!stkctr_entry(stkctr))
2445 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002446
2447 if (stkctr && stkctr_entry(stkctr)) {
2448 void *ptr1,*ptr2;
2449
Emeric Brun819fc6f2017-06-13 19:37:32 +02002450
Willy Tarreau7d562212016-11-25 16:10:05 +01002451 /* First, update gpc0_rate if it's tracked. Second, update its
2452 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2453 */
2454 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002455 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002456 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002457 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002458
Emeric Brun819fc6f2017-06-13 19:37:32 +02002459 if (ptr1) {
2460 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2461 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2462 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2463 }
2464
2465 if (ptr2)
2466 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2467
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002468 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002469
2470 /* If data was modified, we need to touch to re-schedule sync */
2471 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2472 }
2473 else if (stkctr == &tmpstkctr)
2474 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002475 }
2476 return 1;
2477}
2478
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002479/* Increment the General Purpose Counter 1 value from the stream's tracked
2480 * frontend counters and return it into temp integer.
2481 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2482 */
2483static int
2484smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2485{
2486 struct stkctr tmpstkctr;
2487 struct stkctr *stkctr;
2488
2489 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2490 if (!stkctr)
2491 return 0;
2492
2493 smp->flags = SMP_F_VOL_TEST;
2494 smp->data.type = SMP_T_SINT;
2495 smp->data.u.sint = 0;
2496
2497 if (!stkctr_entry(stkctr))
2498 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2499
2500 if (stkctr && stkctr_entry(stkctr)) {
2501 void *ptr1,*ptr2;
2502
2503
2504 /* First, update gpc1_rate if it's tracked. Second, update its
2505 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2506 */
2507 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2508 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2509 if (ptr1 || ptr2) {
2510 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2511
2512 if (ptr1) {
2513 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2514 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2515 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2516 }
2517
2518 if (ptr2)
2519 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2520
2521 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2522
2523 /* If data was modified, we need to touch to re-schedule sync */
2524 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2525 }
2526 else if (stkctr == &tmpstkctr)
2527 stktable_release(stkctr->table, stkctr_entry(stkctr));
2528 }
2529 return 1;
2530}
2531
Willy Tarreau7d562212016-11-25 16:10:05 +01002532/* Clear the General Purpose Counter 0 value from the stream's tracked
2533 * frontend counters and return its previous value into temp integer.
2534 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2535 */
2536static int
2537smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2538{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002539 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002540 struct stkctr *stkctr;
2541
Emeric Brun819fc6f2017-06-13 19:37:32 +02002542 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002543 if (!stkctr)
2544 return 0;
2545
2546 smp->flags = SMP_F_VOL_TEST;
2547 smp->data.type = SMP_T_SINT;
2548 smp->data.u.sint = 0;
2549
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550 if (!stkctr_entry(stkctr))
2551 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002552
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553 if (stkctr && stkctr_entry(stkctr)) {
2554 void *ptr;
2555
2556 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2557 if (!ptr) {
2558 if (stkctr == &tmpstkctr)
2559 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002560 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002561 }
2562
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002563 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002564
Willy Tarreau7d562212016-11-25 16:10:05 +01002565 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2566 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002567
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002568 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002569
Willy Tarreau7d562212016-11-25 16:10:05 +01002570 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002571 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002572 }
2573 return 1;
2574}
2575
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002576/* Clear the General Purpose Counter 1 value from the stream's tracked
2577 * frontend counters and return its previous value into temp integer.
2578 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2579 */
2580static int
2581smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2582{
2583 struct stkctr tmpstkctr;
2584 struct stkctr *stkctr;
2585
2586 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2587 if (!stkctr)
2588 return 0;
2589
2590 smp->flags = SMP_F_VOL_TEST;
2591 smp->data.type = SMP_T_SINT;
2592 smp->data.u.sint = 0;
2593
2594 if (!stkctr_entry(stkctr))
2595 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2596
2597 if (stkctr && stkctr_entry(stkctr)) {
2598 void *ptr;
2599
2600 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2601 if (!ptr) {
2602 if (stkctr == &tmpstkctr)
2603 stktable_release(stkctr->table, stkctr_entry(stkctr));
2604 return 0; /* parameter not stored */
2605 }
2606
2607 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2608
2609 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2610 stktable_data_cast(ptr, gpc1) = 0;
2611
2612 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2613
2614 /* If data was modified, we need to touch to re-schedule sync */
2615 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2616 }
2617 return 1;
2618}
2619
Willy Tarreau7d562212016-11-25 16:10:05 +01002620/* set <smp> to the cumulated number of connections from the stream's tracked
2621 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2622 * "src_conn_cnt" only.
2623 */
2624static int
2625smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2626{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002627 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002628 struct stkctr *stkctr;
2629
Emeric Brun819fc6f2017-06-13 19:37:32 +02002630 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002631 if (!stkctr)
2632 return 0;
2633
2634 smp->flags = SMP_F_VOL_TEST;
2635 smp->data.type = SMP_T_SINT;
2636 smp->data.u.sint = 0;
2637 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002638 void *ptr;
2639
2640 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2641 if (!ptr) {
2642 if (stkctr == &tmpstkctr)
2643 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002644 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002645 }
2646
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002647 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002648
Willy Tarreau7d562212016-11-25 16:10:05 +01002649 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002650
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002651 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002652
2653 if (stkctr == &tmpstkctr)
2654 stktable_release(stkctr->table, stkctr_entry(stkctr));
2655
2656
Willy Tarreau7d562212016-11-25 16:10:05 +01002657 }
2658 return 1;
2659}
2660
2661/* set <smp> to the connection rate from the stream's tracked frontend
2662 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2663 * only.
2664 */
2665static int
2666smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2667{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002668 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002669 struct stkctr *stkctr;
2670
Emeric Brun819fc6f2017-06-13 19:37:32 +02002671 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002672 if (!stkctr)
2673 return 0;
2674
2675 smp->flags = SMP_F_VOL_TEST;
2676 smp->data.type = SMP_T_SINT;
2677 smp->data.u.sint = 0;
2678 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002679 void *ptr;
2680
2681 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2682 if (!ptr) {
2683 if (stkctr == &tmpstkctr)
2684 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002685 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002686 }
2687
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002688 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002689
Willy Tarreau7d562212016-11-25 16:10:05 +01002690 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2691 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002692
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002693 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002694
2695 if (stkctr == &tmpstkctr)
2696 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002697 }
2698 return 1;
2699}
2700
2701/* set temp integer to the number of connections from the stream's source address
2702 * in the table pointed to by expr, after updating it.
2703 * Accepts exactly 1 argument of type table.
2704 */
2705static int
2706smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2707{
2708 struct connection *conn = objt_conn(smp->sess->origin);
2709 struct stksess *ts;
2710 struct stktable_key *key;
2711 void *ptr;
2712 struct proxy *px;
2713
2714 if (!conn)
2715 return 0;
2716
Joseph Herlant5662fa42018-11-15 13:43:28 -08002717 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002718 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2719 return 0;
2720
2721 /* Converts into key. */
2722 key = smp_to_stkey(smp, &args->data.prx->table);
2723 if (!key)
2724 return 0;
2725
2726 px = args->data.prx;
2727
Emeric Brun819fc6f2017-06-13 19:37:32 +02002728 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002729 /* entry does not exist and could not be created */
2730 return 0;
2731
2732 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002733 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002734 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002735 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002736
2737 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002738
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002739 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002740
Willy Tarreau7d562212016-11-25 16:10:05 +01002741 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002742
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002743 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002744
Willy Tarreau7d562212016-11-25 16:10:05 +01002745 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746
2747 stktable_touch_local(&px->table, ts, 1);
2748
2749 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002750 return 1;
2751}
2752
2753/* set <smp> to the number of concurrent connections from the stream's tracked
2754 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2755 * "src_conn_cur" only.
2756 */
2757static int
2758smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2759{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002760 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002761 struct stkctr *stkctr;
2762
Emeric Brun819fc6f2017-06-13 19:37:32 +02002763 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002764 if (!stkctr)
2765 return 0;
2766
2767 smp->flags = SMP_F_VOL_TEST;
2768 smp->data.type = SMP_T_SINT;
2769 smp->data.u.sint = 0;
2770 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771 void *ptr;
2772
2773 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2774 if (!ptr) {
2775 if (stkctr == &tmpstkctr)
2776 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002777 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002778 }
2779
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002780 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002781
Willy Tarreau7d562212016-11-25 16:10:05 +01002782 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002783
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002784 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002785
2786 if (stkctr == &tmpstkctr)
2787 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002788 }
2789 return 1;
2790}
2791
2792/* set <smp> to the cumulated number of streams from the stream's tracked
2793 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2794 * "src_sess_cnt" only.
2795 */
2796static int
2797smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2798{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002799 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002800 struct stkctr *stkctr;
2801
Emeric Brun819fc6f2017-06-13 19:37:32 +02002802 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002803 if (!stkctr)
2804 return 0;
2805
2806 smp->flags = SMP_F_VOL_TEST;
2807 smp->data.type = SMP_T_SINT;
2808 smp->data.u.sint = 0;
2809 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002810 void *ptr;
2811
2812 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2813 if (!ptr) {
2814 if (stkctr == &tmpstkctr)
2815 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002816 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002817 }
2818
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002819 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002820
Willy Tarreau7d562212016-11-25 16:10:05 +01002821 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002822
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002823 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002824
2825 if (stkctr == &tmpstkctr)
2826 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002827 }
2828 return 1;
2829}
2830
2831/* set <smp> to the stream rate from the stream's tracked frontend counters.
2832 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2833 */
2834static int
2835smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2836{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002837 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002838 struct stkctr *stkctr;
2839
Emeric Brun819fc6f2017-06-13 19:37:32 +02002840 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002841 if (!stkctr)
2842 return 0;
2843
2844 smp->flags = SMP_F_VOL_TEST;
2845 smp->data.type = SMP_T_SINT;
2846 smp->data.u.sint = 0;
2847 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002848 void *ptr;
2849
2850 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2851 if (!ptr) {
2852 if (stkctr == &tmpstkctr)
2853 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002854 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002855 }
2856
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002857 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002858
Willy Tarreau7d562212016-11-25 16:10:05 +01002859 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2860 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002861
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002862 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002863
2864 if (stkctr == &tmpstkctr)
2865 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002866 }
2867 return 1;
2868}
2869
2870/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2871 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2872 * "src_http_req_cnt" only.
2873 */
2874static int
2875smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2876{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002878 struct stkctr *stkctr;
2879
Emeric Brun819fc6f2017-06-13 19:37:32 +02002880 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002881 if (!stkctr)
2882 return 0;
2883
2884 smp->flags = SMP_F_VOL_TEST;
2885 smp->data.type = SMP_T_SINT;
2886 smp->data.u.sint = 0;
2887 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002888 void *ptr;
2889
2890 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2891 if (!ptr) {
2892 if (stkctr == &tmpstkctr)
2893 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002895 }
2896
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002897 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002898
Willy Tarreau7d562212016-11-25 16:10:05 +01002899 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002900
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002901 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002902
2903 if (stkctr == &tmpstkctr)
2904 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002905 }
2906 return 1;
2907}
2908
2909/* set <smp> to the HTTP request rate from the stream's tracked frontend
2910 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2911 * "src_http_req_rate" only.
2912 */
2913static int
2914smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2915{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 struct stkctr *stkctr;
2918
Emeric Brun819fc6f2017-06-13 19:37:32 +02002919 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002920 if (!stkctr)
2921 return 0;
2922
2923 smp->flags = SMP_F_VOL_TEST;
2924 smp->data.type = SMP_T_SINT;
2925 smp->data.u.sint = 0;
2926 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002927 void *ptr;
2928
2929 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2930 if (!ptr) {
2931 if (stkctr == &tmpstkctr)
2932 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934 }
2935
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002936 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002937
Willy Tarreau7d562212016-11-25 16:10:05 +01002938 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2939 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002940
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002941 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002942
2943 if (stkctr == &tmpstkctr)
2944 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 }
2946 return 1;
2947}
2948
2949/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2950 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2951 * "src_http_err_cnt" only.
2952 */
2953static int
2954smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2955{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 struct stkctr *stkctr;
2958
Emeric Brun819fc6f2017-06-13 19:37:32 +02002959 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002960 if (!stkctr)
2961 return 0;
2962
2963 smp->flags = SMP_F_VOL_TEST;
2964 smp->data.type = SMP_T_SINT;
2965 smp->data.u.sint = 0;
2966 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002967 void *ptr;
2968
2969 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2970 if (!ptr) {
2971 if (stkctr == &tmpstkctr)
2972 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002973 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002974 }
2975
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002976 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002977
Willy Tarreau7d562212016-11-25 16:10:05 +01002978 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002979
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002980 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981
2982 if (stkctr == &tmpstkctr)
2983 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002984 }
2985 return 1;
2986}
2987
2988/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2989 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2990 * "src_http_err_rate" only.
2991 */
2992static int
2993smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2994{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002996 struct stkctr *stkctr;
2997
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 if (!stkctr)
3000 return 0;
3001
3002 smp->flags = SMP_F_VOL_TEST;
3003 smp->data.type = SMP_T_SINT;
3004 smp->data.u.sint = 0;
3005 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003006 void *ptr;
3007
3008 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
3009 if (!ptr) {
3010 if (stkctr == &tmpstkctr)
3011 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003012 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003013 }
3014
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003015 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003016
Willy Tarreau7d562212016-11-25 16:10:05 +01003017 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
3018 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003019
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003020 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003021
3022 if (stkctr == &tmpstkctr)
3023 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003024 }
3025 return 1;
3026}
3027
3028/* set <smp> to the number of kbytes received from clients, as found in the
3029 * stream's tracked frontend counters. Supports being called as
3030 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
3031 */
3032static int
3033smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
3034{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003035 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003036 struct stkctr *stkctr;
3037
Emeric Brun819fc6f2017-06-13 19:37:32 +02003038 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003039 if (!stkctr)
3040 return 0;
3041
3042 smp->flags = SMP_F_VOL_TEST;
3043 smp->data.type = SMP_T_SINT;
3044 smp->data.u.sint = 0;
3045 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003046 void *ptr;
3047
3048 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
3049 if (!ptr) {
3050 if (stkctr == &tmpstkctr)
3051 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003052 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003053 }
3054
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003055 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003056
Willy Tarreau7d562212016-11-25 16:10:05 +01003057 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003058
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003059 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003060
3061 if (stkctr == &tmpstkctr)
3062 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003063 }
3064 return 1;
3065}
3066
3067/* set <smp> to the data rate received from clients in bytes/s, as found
3068 * in the stream's tracked frontend counters. Supports being called as
3069 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
3070 */
3071static int
3072smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3073{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003074 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003075 struct stkctr *stkctr;
3076
Emeric Brun819fc6f2017-06-13 19:37:32 +02003077 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003078 if (!stkctr)
3079 return 0;
3080
3081 smp->flags = SMP_F_VOL_TEST;
3082 smp->data.type = SMP_T_SINT;
3083 smp->data.u.sint = 0;
3084 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003085 void *ptr;
3086
3087 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
3088 if (!ptr) {
3089 if (stkctr == &tmpstkctr)
3090 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003091 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003092 }
3093
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003094 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003095
Willy Tarreau7d562212016-11-25 16:10:05 +01003096 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
3097 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003098
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003099 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003100
3101 if (stkctr == &tmpstkctr)
3102 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003103 }
3104 return 1;
3105}
3106
3107/* set <smp> to the number of kbytes sent to clients, as found in the
3108 * stream's tracked frontend counters. Supports being called as
3109 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
3110 */
3111static int
3112smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
3113{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003114 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003115 struct stkctr *stkctr;
3116
Emeric Brun819fc6f2017-06-13 19:37:32 +02003117 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003118 if (!stkctr)
3119 return 0;
3120
3121 smp->flags = SMP_F_VOL_TEST;
3122 smp->data.type = SMP_T_SINT;
3123 smp->data.u.sint = 0;
3124 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003125 void *ptr;
3126
3127 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
3128 if (!ptr) {
3129 if (stkctr == &tmpstkctr)
3130 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003131 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003132 }
3133
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003134 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003135
Willy Tarreau7d562212016-11-25 16:10:05 +01003136 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003137
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003138 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003139
3140 if (stkctr == &tmpstkctr)
3141 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003142 }
3143 return 1;
3144}
3145
3146/* set <smp> to the data rate sent to clients in bytes/s, as found in the
3147 * stream's tracked frontend counters. Supports being called as
3148 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
3149 */
3150static int
3151smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
3152{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003153 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003154 struct stkctr *stkctr;
3155
Emeric Brun819fc6f2017-06-13 19:37:32 +02003156 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003157 if (!stkctr)
3158 return 0;
3159
3160 smp->flags = SMP_F_VOL_TEST;
3161 smp->data.type = SMP_T_SINT;
3162 smp->data.u.sint = 0;
3163 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003164 void *ptr;
3165
3166 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
3167 if (!ptr) {
3168 if (stkctr == &tmpstkctr)
3169 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003170 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003171 }
3172
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003173 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003174
Willy Tarreau7d562212016-11-25 16:10:05 +01003175 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
3176 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003177
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003178 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003179
3180 if (stkctr == &tmpstkctr)
3181 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01003182 }
3183 return 1;
3184}
3185
3186/* set <smp> to the number of active trackers on the SC entry in the stream's
3187 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
3188 */
3189static int
3190smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
3191{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003192 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003193 struct stkctr *stkctr;
3194
Emeric Brun819fc6f2017-06-13 19:37:32 +02003195 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003196 if (!stkctr)
3197 return 0;
3198
3199 smp->flags = SMP_F_VOL_TEST;
3200 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003201 if (stkctr == &tmpstkctr) {
3202 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3203 stktable_release(stkctr->table, stkctr_entry(stkctr));
3204 }
3205 else {
3206 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3207 }
3208
Willy Tarreau7d562212016-11-25 16:10:05 +01003209 return 1;
3210}
3211
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003212
3213/* The functions below are used to manipulate table contents from the CLI.
3214 * There are 3 main actions, "clear", "set" and "show". The code is shared
3215 * between all actions, and the action is encoded in the void *private in
3216 * the appctx as well as in the keyword registration, among one of the
3217 * following values.
3218 */
3219
3220enum {
3221 STK_CLI_ACT_CLR,
3222 STK_CLI_ACT_SET,
3223 STK_CLI_ACT_SHOW,
3224};
3225
3226/* Dump the status of a table to a stream interface's
3227 * read buffer. It returns 0 if the output buffer is full
3228 * and needs to be called again, otherwise non-zero.
3229 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003230static int table_dump_head_to_buffer(struct buffer *msg,
3231 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003232 struct proxy *proxy, struct proxy *target)
3233{
3234 struct stream *s = si_strm(si);
3235
3236 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3237 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3238
3239 /* any other information should be dumped here */
3240
William Lallemand07a62f72017-05-24 00:57:40 +02003241 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003242 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3243
Willy Tarreau06d80a92017-10-19 14:32:15 +02003244 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003245 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003246 return 0;
3247 }
3248
3249 return 1;
3250}
3251
3252/* Dump a table entry to a stream interface's
3253 * read buffer. It returns 0 if the output buffer is full
3254 * and needs to be called again, otherwise non-zero.
3255 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003256static int table_dump_entry_to_buffer(struct buffer *msg,
3257 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003258 struct proxy *proxy, struct stksess *entry)
3259{
3260 int dt;
3261
3262 chunk_appendf(msg, "%p:", entry);
3263
3264 if (proxy->table.type == SMP_T_IPV4) {
3265 char addr[INET_ADDRSTRLEN];
3266 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3267 chunk_appendf(msg, " key=%s", addr);
3268 }
3269 else if (proxy->table.type == SMP_T_IPV6) {
3270 char addr[INET6_ADDRSTRLEN];
3271 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3272 chunk_appendf(msg, " key=%s", addr);
3273 }
3274 else if (proxy->table.type == SMP_T_SINT) {
3275 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3276 }
3277 else if (proxy->table.type == SMP_T_STR) {
3278 chunk_appendf(msg, " key=");
3279 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3280 }
3281 else {
3282 chunk_appendf(msg, " key=");
3283 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3284 }
3285
3286 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3287
3288 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3289 void *ptr;
3290
3291 if (proxy->table.data_ofs[dt] == 0)
3292 continue;
3293 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3294 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3295 else
3296 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3297
3298 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3299 switch (stktable_data_types[dt].std_type) {
3300 case STD_T_SINT:
3301 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3302 break;
3303 case STD_T_UINT:
3304 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3305 break;
3306 case STD_T_ULL:
3307 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3308 break;
3309 case STD_T_FRQP:
3310 chunk_appendf(msg, "%d",
3311 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3312 proxy->table.data_arg[dt].u));
3313 break;
3314 }
3315 }
3316 chunk_appendf(msg, "\n");
3317
Willy Tarreau06d80a92017-10-19 14:32:15 +02003318 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003319 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003320 return 0;
3321 }
3322
3323 return 1;
3324}
3325
3326
3327/* Processes a single table entry matching a specific key passed in argument.
3328 * returns 0 if wants to be called again, 1 if has ended processing.
3329 */
3330static int table_process_entry_per_key(struct appctx *appctx, char **args)
3331{
3332 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003333 struct proxy *px = appctx->ctx.table.target;
3334 struct stksess *ts;
3335 uint32_t uint32_key;
3336 unsigned char ip6_key[sizeof(struct in6_addr)];
3337 long long value;
3338 int data_type;
3339 int cur_arg;
3340 void *ptr;
3341 struct freq_ctr_period *frqp;
3342
3343 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003344 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003345 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003346 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003347 return 1;
3348 }
3349
3350 switch (px->table.type) {
3351 case SMP_T_IPV4:
3352 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003353 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003354 break;
3355 case SMP_T_IPV6:
3356 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003357 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003358 break;
3359 case SMP_T_SINT:
3360 {
3361 char *endptr;
3362 unsigned long val;
3363 errno = 0;
3364 val = strtoul(args[4], &endptr, 10);
3365 if ((errno == ERANGE && val == ULONG_MAX) ||
3366 (errno != 0 && val == 0) || endptr == args[4] ||
3367 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003368 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003369 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003370 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003371 return 1;
3372 }
3373 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003374 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003375 break;
3376 }
3377 break;
3378 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003379 static_table_key.key = args[4];
3380 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003381 break;
3382 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003383 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003384 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003385 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003386 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3387 break;
3388 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003389 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003390 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3391 break;
3392 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003393 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003394 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3395 break;
3396 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003397 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003398 appctx->ctx.cli.msg = "Unknown action\n";
3399 break;
3400 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003401 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003402 return 1;
3403 }
3404
3405 /* check permissions */
3406 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3407 return 1;
3408
Willy Tarreaua24bc782016-12-14 15:50:35 +01003409 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003410 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003411 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003412 if (!ts)
3413 return 1;
3414 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003415 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3416 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003417 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003418 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003419 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003420 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003421 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003422 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003423 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003424 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003425 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003426 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003427 break;
3428
3429 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003430 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003431 if (!ts)
3432 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003433
3434 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003435 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003436 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003437 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003438 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003439 return 1;
3440 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003441
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003442 break;
3443
3444 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003445 ts = stktable_get_entry(&px->table, &static_table_key);
3446 if (!ts) {
3447 /* don't delete an entry which is currently referenced */
3448 appctx->ctx.cli.severity = LOG_ERR;
3449 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3450 appctx->st0 = CLI_ST_PRINT;
3451 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003452 }
3453
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003454 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003455 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3456 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003457 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003458 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003459 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003460 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003461 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003462 return 1;
3463 }
3464
3465 data_type = stktable_get_data_type(args[cur_arg] + 5);
3466 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003467 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003468 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003469 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003470 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003471 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003472 return 1;
3473 }
3474
3475 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003476 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003477 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003478 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003479 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003480 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003481 return 1;
3482 }
3483
3484 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003485 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003486 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003487 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003488 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003489 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003490 return 1;
3491 }
3492
3493 ptr = stktable_data_ptr(&px->table, ts, data_type);
3494
3495 switch (stktable_data_types[data_type].std_type) {
3496 case STD_T_SINT:
3497 stktable_data_cast(ptr, std_t_sint) = value;
3498 break;
3499 case STD_T_UINT:
3500 stktable_data_cast(ptr, std_t_uint) = value;
3501 break;
3502 case STD_T_ULL:
3503 stktable_data_cast(ptr, std_t_ull) = value;
3504 break;
3505 case STD_T_FRQP:
3506 /* We set both the current and previous values. That way
3507 * the reported frequency is stable during all the period
3508 * then slowly fades out. This allows external tools to
3509 * push measures without having to update them too often.
3510 */
3511 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003512 /* First bit is reserved for the freq_ctr_period lock
3513 Note: here we're still protected by the stksess lock
3514 so we don't need to update the update the freq_ctr_period
3515 using its internal lock */
3516 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003517 frqp->prev_ctr = 0;
3518 frqp->curr_ctr = value;
3519 break;
3520 }
3521 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003522 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003523 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003524 break;
3525
3526 default:
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 = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003529 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003530 break;
3531 }
3532 return 1;
3533}
3534
3535/* Prepares the appctx fields with the data-based filters from the command line.
3536 * Returns 0 if the dump can proceed, 1 if has ended processing.
3537 */
3538static int table_prepare_data_request(struct appctx *appctx, char **args)
3539{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003540 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003541 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003542 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003543 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003544 return 1;
3545 }
3546
3547 /* condition on stored data value */
3548 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3549 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003550 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003551 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003552 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003553 return 1;
3554 }
3555
3556 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003557 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003558 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003559 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003560 return 1;
3561 }
3562
3563 appctx->ctx.table.data_op = get_std_op(args[4]);
3564 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003565 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003566 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003567 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003568 return 1;
3569 }
3570
3571 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003572 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003573 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003574 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003575 return 1;
3576 }
3577
3578 /* OK we're done, all the fields are set */
3579 return 0;
3580}
3581
3582/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003583static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003584{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003585 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003586 appctx->ctx.table.target = NULL;
3587 appctx->ctx.table.proxy = NULL;
3588 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003589 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003590
3591 if (*args[2]) {
3592 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3593 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003594 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003595 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003596 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597 return 1;
3598 }
3599 }
3600 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003601 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003602 goto err_args;
3603 return 0;
3604 }
3605
3606 if (strcmp(args[3], "key") == 0)
3607 return table_process_entry_per_key(appctx, args);
3608 else if (strncmp(args[3], "data.", 5) == 0)
3609 return table_prepare_data_request(appctx, args);
3610 else if (*args[3])
3611 goto err_args;
3612
3613 return 0;
3614
3615err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003616 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003617 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003618 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003619 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3620 break;
3621 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003622 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003623 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3624 break;
3625 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003626 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003627 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3628 break;
3629 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003630 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003631 appctx->ctx.cli.msg = "Unknown action\n";
3632 break;
3633 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003634 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003635 return 1;
3636}
3637
3638/* This function is used to deal with table operations (dump or clear depending
3639 * on the action stored in appctx->private). It returns 0 if the output buffer is
3640 * full and it needs to be called again, otherwise non-zero.
3641 */
3642static int cli_io_handler_table(struct appctx *appctx)
3643{
3644 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003645 struct stream *s = si_strm(si);
3646 struct ebmb_node *eb;
3647 int dt;
3648 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003649 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003650
3651 /*
3652 * We have 3 possible states in appctx->st2 :
3653 * - STAT_ST_INIT : the first call
3654 * - STAT_ST_INFO : the proxy pointer points to the next table to
3655 * dump, the entry pointer is NULL ;
3656 * - STAT_ST_LIST : the proxy pointer points to the current table
3657 * and the entry pointer points to the next entry to be dumped,
3658 * and the refcount on the next entry is held ;
3659 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3660 * data though.
3661 */
3662
3663 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3664 /* in case of abort, remove any refcount we might have set on an entry */
3665 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003666 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003667 }
3668 return 1;
3669 }
3670
3671 chunk_reset(&trash);
3672
3673 while (appctx->st2 != STAT_ST_FIN) {
3674 switch (appctx->st2) {
3675 case STAT_ST_INIT:
3676 appctx->ctx.table.proxy = appctx->ctx.table.target;
3677 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003678 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003679
3680 appctx->ctx.table.entry = NULL;
3681 appctx->st2 = STAT_ST_INFO;
3682 break;
3683
3684 case STAT_ST_INFO:
3685 if (!appctx->ctx.table.proxy ||
3686 (appctx->ctx.table.target &&
3687 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3688 appctx->st2 = STAT_ST_END;
3689 break;
3690 }
3691
3692 if (appctx->ctx.table.proxy->table.size) {
3693 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3694 return 0;
3695
3696 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003697 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003698 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003699 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003700 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3701 if (eb) {
3702 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3703 appctx->ctx.table.entry->ref_cnt++;
3704 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003705 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003706 break;
3707 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003708 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003709 }
3710 }
3711 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3712 break;
3713
3714 case STAT_ST_LIST:
3715 skip_entry = 0;
3716
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003717 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003718
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003719 if (appctx->ctx.table.data_type >= 0) {
3720 /* we're filtering on some data contents */
3721 void *ptr;
3722 long long data;
3723
Emeric Brun819fc6f2017-06-13 19:37:32 +02003724
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003725 dt = appctx->ctx.table.data_type;
3726 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3727 appctx->ctx.table.entry,
3728 dt);
3729
3730 data = 0;
3731 switch (stktable_data_types[dt].std_type) {
3732 case STD_T_SINT:
3733 data = stktable_data_cast(ptr, std_t_sint);
3734 break;
3735 case STD_T_UINT:
3736 data = stktable_data_cast(ptr, std_t_uint);
3737 break;
3738 case STD_T_ULL:
3739 data = stktable_data_cast(ptr, std_t_ull);
3740 break;
3741 case STD_T_FRQP:
3742 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3743 appctx->ctx.table.proxy->table.data_arg[dt].u);
3744 break;
3745 }
3746
3747 /* skip the entry if the data does not match the test and the value */
3748 if ((data < appctx->ctx.table.value &&
3749 (appctx->ctx.table.data_op == STD_OP_EQ ||
3750 appctx->ctx.table.data_op == STD_OP_GT ||
3751 appctx->ctx.table.data_op == STD_OP_GE)) ||
3752 (data == appctx->ctx.table.value &&
3753 (appctx->ctx.table.data_op == STD_OP_NE ||
3754 appctx->ctx.table.data_op == STD_OP_GT ||
3755 appctx->ctx.table.data_op == STD_OP_LT)) ||
3756 (data > appctx->ctx.table.value &&
3757 (appctx->ctx.table.data_op == STD_OP_EQ ||
3758 appctx->ctx.table.data_op == STD_OP_LT ||
3759 appctx->ctx.table.data_op == STD_OP_LE)))
3760 skip_entry = 1;
3761 }
3762
3763 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003764 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003765 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003766 return 0;
3767 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003768
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003769 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003770
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003771 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003772 appctx->ctx.table.entry->ref_cnt--;
3773
3774 eb = ebmb_next(&appctx->ctx.table.entry->key);
3775 if (eb) {
3776 struct stksess *old = appctx->ctx.table.entry;
3777 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3778 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003779 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003780 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003781 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003782 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003783 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003784 break;
3785 }
3786
3787
3788 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003789 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003790 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003791 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3792
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003793 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003794
3795 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3796 appctx->st2 = STAT_ST_INFO;
3797 break;
3798
3799 case STAT_ST_END:
3800 appctx->st2 = STAT_ST_FIN;
3801 break;
3802 }
3803 }
3804 return 1;
3805}
3806
3807static void cli_release_show_table(struct appctx *appctx)
3808{
3809 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003810 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003811 }
3812}
3813
3814/* register cli keywords */
3815static struct cli_kw_list cli_kws = {{ },{
3816 { { "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 },
3817 { { "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 },
3818 { { "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 },
3819 {{},}
3820}};
3821
Willy Tarreau0108d902018-11-25 19:14:37 +01003822INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003823
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003824static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003825 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003826 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003827 { "sc-set-gpt0", parse_set_gpt0, 1 },
3828 { /* END */ }
3829}};
3830
Willy Tarreau0108d902018-11-25 19:14:37 +01003831INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3832
Willy Tarreau620408f2016-10-21 16:37:51 +02003833static struct action_kw_list tcp_sess_kws = { { }, {
3834 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003835 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003836 { "sc-set-gpt0", parse_set_gpt0, 1 },
3837 { /* END */ }
3838}};
3839
Willy Tarreau0108d902018-11-25 19:14:37 +01003840INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3841
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003842static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003843 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003844 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003845 { "sc-set-gpt0", parse_set_gpt0, 1 },
3846 { /* END */ }
3847}};
3848
Willy Tarreau0108d902018-11-25 19:14:37 +01003849INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3850
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003851static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003852 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003853 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003854 { "sc-set-gpt0", parse_set_gpt0, 1 },
3855 { /* END */ }
3856}};
3857
Willy Tarreau0108d902018-11-25 19:14:37 +01003858INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3859
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003860static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003861 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003862 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003863 { "sc-set-gpt0", parse_set_gpt0, 1 },
3864 { /* END */ }
3865}};
3866
Willy Tarreau0108d902018-11-25 19:14:37 +01003867INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3868
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003869static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003870 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003871 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003872 { "sc-set-gpt0", parse_set_gpt0, 1 },
3873 { /* END */ }
3874}};
3875
Willy Tarreau0108d902018-11-25 19:14:37 +01003876INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3877
Willy Tarreau7d562212016-11-25 16:10:05 +01003878///* Note: must not be declared <const> as its list will be overwritten.
3879// * Please take care of keeping this list alphabetically sorted.
3880// */
3881//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3882// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3883// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3884// { /* END */ },
3885//}};
3886/* Note: must not be declared <const> as its list will be overwritten.
3887 * Please take care of keeping this list alphabetically sorted.
3888 */
3889static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3890 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3891 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3892 { "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 +01003893 { "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 +01003894 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3895 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3896 { "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 +01003897 { "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 +01003898 { "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 +01003899 { "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 +01003900 { "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 +01003901 { "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 +01003902 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3903 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3904 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3905 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3906 { "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 +01003907 { "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 +01003908 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3909 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3910 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3911 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3912 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3913 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3914 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3915 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3916 { "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 +01003917 { "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 +01003918 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3919 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3920 { "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 +01003921 { "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 +01003922 { "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 +01003923 { "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 +01003924 { "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 +01003925 { "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 +01003926 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3927 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3928 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3929 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3930 { "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 +01003931 { "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 +01003932 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3933 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3934 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3935 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3936 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3937 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3938 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3939 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3940 { "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 +01003941 { "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 +01003942 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3943 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3944 { "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 +01003945 { "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 +01003946 { "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 +01003947 { "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 +01003948 { "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 +01003949 { "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 +01003950 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3951 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3952 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3953 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3954 { "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 +01003955 { "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 +01003956 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3957 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3958 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3959 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3960 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3961 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3962 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3963 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3964 { "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 +01003965 { "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 +01003966 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3967 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3968 { "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 +01003969 { "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 +01003970 { "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 +01003971 { "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 +01003972 { "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 +01003973 { "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 +01003974 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3975 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3976 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3977 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3978 { "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 +01003979 { "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 +01003980 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3981 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3982 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3983 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3984 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3985 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3986 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3987 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3988 { "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 +01003989 { "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 +01003990 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3991 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3992 { "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 +01003993 { "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 +01003994 { "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 +01003995 { "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 +01003996 { "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 +01003997 { "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 +01003998 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3999 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4000 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4001 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4002 { "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 +01004003 { "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 +01004004 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4005 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4006 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4007 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4008 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
4009 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4010 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
4011 { /* END */ },
4012}};
4013
Willy Tarreau0108d902018-11-25 19:14:37 +01004014INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01004015
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004016/* Note: must not be declared <const> as its list will be overwritten */
4017static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02004018 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
4019 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4020 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4021 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4022 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4023 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4024 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4025 { "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 +01004026 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02004027 { "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 +01004028 { "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 +02004029 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4030 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4031 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4032 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4033 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4034 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4035 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4036 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4037 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
4038 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02004039 { /* END */ },
4040}};
4041
Willy Tarreau0108d902018-11-25 19:14:37 +01004042INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);