blob: 5e55b7a9b90ebf99348c70a3c4093c2dee964090 [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>
18#include <common/memory.h>
19#include <common/mini-clist.h>
20#include <common/standard.h>
21#include <common/time.h>
22
23#include <ebmbtree.h>
24#include <ebsttree.h>
25
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010026#include <types/cli.h>
Willy Tarreau39713102016-11-25 15:49:32 +010027#include <types/global.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010028#include <types/stats.h>
29
Willy Tarreaud9f316a2014-07-10 14:03:38 +020030#include <proto/arg.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010031#include <proto/cli.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020032#include <proto/http_rules.h>
Andjelko Iharosc3680ec2017-07-20 16:49:14 +020033#include <proto/log.h>
Thierry FOURNIER236657b2015-08-19 08:25:14 +020034#include <proto/proto_http.h>
Willy Tarreau7d562212016-11-25 16:10:05 +010035#include <proto/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010036#include <proto/proxy.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020037#include <proto/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020038#include <proto/stream.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010039#include <proto/stream_interface.h>
Willy Tarreau68129b92010-06-06 16:06:52 +020040#include <proto/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010041#include <proto/task.h>
Emeric Brun32da3c42010-09-23 18:39:19 +020042#include <proto/peers.h>
Willy Tarreau39713102016-11-25 15:49:32 +010043#include <proto/tcp_rules.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010044
Willy Tarreau12785782012-04-27 21:37:17 +020045/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020046static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020047
Olivier Houchard52dabbc2018-11-14 17:54:36 +010048#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +010049/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020050 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
51 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010052 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020053void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010054{
55 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010056 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010057}
58
59/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020060 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
61 * in table <t>.
62 * This function locks the table
63 */
64void stksess_free(struct stktable *t, struct stksess *ts)
65{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010066 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020067 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010068 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020069}
70
71/*
Willy Tarreauf6efda12010-08-03 20:34:06 +020072 * Kill an stksess (only if its ref_cnt is zero).
73 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020074int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +020075{
76 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +020077 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +020078
79 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +020080 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +020081 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +020082 __stksess_free(t, ts);
83 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +020084}
85
86/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020087 * Decrease the refcount if decrefcnt is not 0.
88 * and try to kill the stksess
89 * This function locks the table
90 */
91int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
92{
93 int ret;
94
Christopher Faulet2a944ee2017-11-07 10:42:54 +010095 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020096 if (decrefcnt)
97 ts->ref_cnt--;
98 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010099 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200100
101 return ret;
102}
103
104/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200105 * Initialize or update the key in the sticky session <ts> present in table <t>
106 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100107 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200108void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100109{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200110 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200111 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100112 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200113 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
114 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100115 }
116}
117
118
119/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200120 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
121 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100122 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200123static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100124{
Willy Tarreau393379c2010-06-06 12:11:37 +0200125 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200126 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200127 ts->key.node.leaf_p = NULL;
128 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200129 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200130 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100131 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100132 return ts;
133}
134
135/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200136 * Trash oldest <to_batch> sticky sessions from table <t>
137 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100138 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200139int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100140{
141 struct stksess *ts;
142 struct eb32_node *eb;
143 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200144 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100145
146 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
147
148 while (batched < to_batch) {
149
150 if (unlikely(!eb)) {
151 /* we might have reached the end of the tree, typically because
152 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200153 * half. Let's loop back to the beginning of the tree now if we
154 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100155 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200156 if (looped)
157 break;
158 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100159 eb = eb32_first(&t->exps);
160 if (likely(!eb))
161 break;
162 }
163
164 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200165 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100166 eb = eb32_next(eb);
167
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200168 /* don't delete an entry which is currently referenced */
169 if (ts->ref_cnt)
170 continue;
171
Willy Tarreau86257dc2010-06-06 12:57:10 +0200172 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100173
Willy Tarreau86257dc2010-06-06 12:57:10 +0200174 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100175 if (!tick_isset(ts->expire))
176 continue;
177
Willy Tarreau86257dc2010-06-06 12:57:10 +0200178 ts->exp.key = ts->expire;
179 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100180
Willy Tarreau86257dc2010-06-06 12:57:10 +0200181 if (!eb || eb->key > ts->exp.key)
182 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100183
184 continue;
185 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100186
Willy Tarreauaea940e2010-06-06 11:56:36 +0200187 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200188 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200189 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200190 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100191 batched++;
192 }
193
194 return batched;
195}
196
197/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200198 * Trash oldest <to_batch> sticky sessions from table <t>
199 * Returns number of trashed sticky sessions.
200 * This function locks the table
201 */
202int stktable_trash_oldest(struct stktable *t, int to_batch)
203{
204 int ret;
205
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100206 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200207 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100208 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200209
210 return ret;
211}
212/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200213 * Allocate and initialise a new sticky session.
214 * The new sticky session is returned or NULL in case of lack of memory.
215 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200216 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
217 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100218 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200219struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100220{
221 struct stksess *ts;
222
223 if (unlikely(t->current == t->size)) {
224 if ( t->nopurge )
225 return NULL;
226
Emeric Brun819fc6f2017-06-13 19:37:32 +0200227 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100228 return NULL;
229 }
230
Willy Tarreaubafbe012017-11-24 17:34:44 +0100231 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100232 if (ts) {
233 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100234 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200235 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200236 if (key)
237 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100238 }
239
240 return ts;
241}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200242/*
243 * Allocate and initialise a new sticky session.
244 * The new sticky session is returned or NULL in case of lack of memory.
245 * Sticky sessions should only be allocated this way, and must be freed using
246 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
247 * is not NULL, it is assigned to the new session.
248 * This function locks the table
249 */
250struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
251{
252 struct stksess *ts;
253
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100254 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200255 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100256 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200257
258 return ts;
259}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100260
261/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200262 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200263 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200265struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100266{
267 struct ebmb_node *eb;
268
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200269 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200270 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 +0100271 else
272 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
273
274 if (unlikely(!eb)) {
275 /* no session found */
276 return NULL;
277 }
278
Willy Tarreau86257dc2010-06-06 12:57:10 +0200279 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100280}
281
Emeric Brun819fc6f2017-06-13 19:37:32 +0200282/*
283 * Looks in table <t> for a sticky session matching key <key>.
284 * Returns pointer on requested sticky session or NULL if none was found.
285 * The refcount of the found entry is increased and this function
286 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200287 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200288struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200289{
290 struct stksess *ts;
291
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100292 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200293 ts = __stktable_lookup_key(t, key);
294 if (ts)
295 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100296 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200297
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200298 return ts;
299}
300
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200301/*
302 * Looks in table <t> for a sticky session with same key as <ts>.
303 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100304 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200305struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100306{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100307 struct ebmb_node *eb;
308
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200309 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200310 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100311 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200312 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100313
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200314 if (unlikely(!eb))
315 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100316
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200317 return ebmb_entry(eb, struct stksess, key);
318}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100319
Emeric Brun819fc6f2017-06-13 19:37:32 +0200320/*
321 * Looks in table <t> for a sticky session with same key as <ts>.
322 * Returns pointer on requested sticky session or NULL if none was found.
323 * The refcount of the found entry is increased and this function
324 * is protected using the table lock
325 */
326struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
327{
328 struct stksess *lts;
329
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100330 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200331 lts = __stktable_lookup(t, ts);
332 if (lts)
333 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100334 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200335
336 return lts;
337}
338
Willy Tarreaucb183642010-06-06 17:58:34 +0200339/* Update the expiration timer for <ts> but do not touch its expiration node.
340 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200341 * The node will be also inserted into the update tree if needed, at a position
342 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200343 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200344void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200345{
Emeric Brun85e77c72010-09-23 18:16:52 +0200346 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200347 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200348 if (t->expire) {
349 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
350 task_queue(t->exp_task);
351 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200352
Emeric Brun819fc6f2017-06-13 19:37:32 +0200353 /* If sync is enabled */
354 if (t->sync_task) {
355 if (local) {
356 /* If this entry is not in the tree
357 or not scheduled for at least one peer */
358 if (!ts->upd.node.leaf_p
359 || (int)(t->commitupdate - ts->upd.key) >= 0
360 || (int)(ts->upd.key - t->localupdate) >= 0) {
361 ts->upd.key = ++t->update;
362 t->localupdate = t->update;
363 eb32_delete(&ts->upd);
364 eb = eb32_insert(&t->updates, &ts->upd);
365 if (eb != &ts->upd) {
366 eb32_delete(eb);
367 eb32_insert(&t->updates, &ts->upd);
368 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200369 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200370 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200371 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200372 else {
373 /* If this entry is not in the tree */
374 if (!ts->upd.node.leaf_p) {
375 ts->upd.key= (++t->update)+(2147483648U);
376 eb = eb32_insert(&t->updates, &ts->upd);
377 if (eb != &ts->upd) {
378 eb32_delete(eb);
379 eb32_insert(&t->updates, &ts->upd);
380 }
381 }
382 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200383 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200384}
385
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200386/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200387 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200388 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200389 * The node will be also inserted into the update tree if needed, at a position
390 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200391 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200392void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
393{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100394 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200395 __stktable_touch_with_exp(t, ts, 0, ts->expire);
396 if (decrefcnt)
397 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100398 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200399}
400
401/* Update the expiration timer for <ts> but do not touch its expiration node.
402 * The table's expiration timer is updated using the date of expiration coming from
403 * <t> stick-table configuration.
404 * The node will be also inserted into the update tree if needed, at a position
405 * considering the update was made locally
406 */
407void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200408{
409 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
410
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100411 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200412 __stktable_touch_with_exp(t, ts, 1, expire);
413 if (decrefcnt)
414 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100415 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200416}
Willy Tarreau43e90352018-06-27 06:25:57 +0200417/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
418static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200419{
Willy Tarreau43e90352018-06-27 06:25:57 +0200420 if (!ts)
421 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100422 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200423 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100424 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200425}
426
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200427/* Insert new sticky session <ts> in the table. It is assumed that it does not
428 * yet exist (the caller must check this). The table's timeout is updated if it
429 * is set. <ts> is returned.
430 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200431void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200432{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100433
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200434 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200435 ts->exp.key = ts->expire;
436 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200437 if (t->expire) {
438 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
439 task_queue(t->exp_task);
440 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200441}
442
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200443/* Returns a valid or initialized stksess for the specified stktable_key in the
444 * specified table, or NULL if the key was NULL, or if no entry was found nor
445 * could be created. The entry's expiration is updated.
446 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200447struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200448{
449 struct stksess *ts;
450
451 if (!key)
452 return NULL;
453
Emeric Brun819fc6f2017-06-13 19:37:32 +0200454 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200455 if (ts == NULL) {
456 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200457 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200458 if (!ts)
459 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200461 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200462 return ts;
463}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200464/* Returns a valid or initialized stksess for the specified stktable_key in the
465 * specified table, or NULL if the key was NULL, or if no entry was found nor
466 * could be created. The entry's expiration is updated.
467 * This function locks the table, and the refcount of the entry is increased.
468 */
469struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
470{
471 struct stksess *ts;
472
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100473 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200474 ts = __stktable_get_entry(table, key);
475 if (ts)
476 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100477 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200478
479 return ts;
480}
481
482/* Lookup for an entry with the same key and store the submitted
483 * stksess if not found.
484 */
485struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
486{
487 struct stksess *ts;
488
489 ts = __stktable_lookup(table, nts);
490 if (ts == NULL) {
491 ts = nts;
492 __stktable_store(table, ts);
493 }
494 return ts;
495}
496
497/* Lookup for an entry with the same key and store the submitted
498 * stksess if not found.
499 * This function locks the table, and the refcount of the entry is increased.
500 */
501struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
502{
503 struct stksess *ts;
504
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100505 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200506 ts = __stktable_set_entry(table, nts);
507 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100508 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200509
Emeric Brun819fc6f2017-06-13 19:37:32 +0200510 return ts;
511}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100512/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200513 * Trash expired sticky sessions from table <t>. The next expiration date is
514 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100515 */
516static int stktable_trash_expired(struct stktable *t)
517{
518 struct stksess *ts;
519 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200520 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100521
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100522 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100523 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
524
525 while (1) {
526 if (unlikely(!eb)) {
527 /* we might have reached the end of the tree, typically because
528 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200529 * half. Let's loop back to the beginning of the tree now if we
530 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100531 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200532 if (looped)
533 break;
534 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100535 eb = eb32_first(&t->exps);
536 if (likely(!eb))
537 break;
538 }
539
540 if (likely(tick_is_lt(now_ms, eb->key))) {
541 /* timer not expired yet, revisit it later */
542 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100543 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100544 }
545
546 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200547 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100548 eb = eb32_next(eb);
549
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200550 /* don't delete an entry which is currently referenced */
551 if (ts->ref_cnt)
552 continue;
553
Willy Tarreau86257dc2010-06-06 12:57:10 +0200554 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100555
556 if (!tick_is_expired(ts->expire, now_ms)) {
557 if (!tick_isset(ts->expire))
558 continue;
559
Willy Tarreau86257dc2010-06-06 12:57:10 +0200560 ts->exp.key = ts->expire;
561 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100562
Willy Tarreau86257dc2010-06-06 12:57:10 +0200563 if (!eb || eb->key > ts->exp.key)
564 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100565 continue;
566 }
567
568 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200569 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200570 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200571 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100572 }
573
574 /* We have found no task to expire in any tree */
575 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100576out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100577 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100578 return t->exp_next;
579}
580
581/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200582 * Task processing function to trash expired sticky sessions. A pointer to the
583 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100584 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200585static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100586{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200587 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100588
589 task->expire = stktable_trash_expired(t);
590 return task;
591}
592
Willy Tarreauaea940e2010-06-06 11:56:36 +0200593/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100594int stktable_init(struct stktable *t)
595{
596 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200597 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100598 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100599 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100600 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100601
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100602 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 +0100603
604 t->exp_next = TICK_ETERNITY;
605 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200606 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200607 if (!t->exp_task)
608 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100610 t->exp_task->context = (void *)t;
611 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200612 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200613 peers_register_table(t->peers.p, t);
614 }
615
Emeric Brun3bd697e2010-01-04 15:23:48 +0100616 return t->pool != NULL;
617 }
618 return 1;
619}
620
621/*
622 * Configuration keywords of known table types
623 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200624struct stktable_type stktable_types[SMP_TYPES] = {
625 [SMP_T_SINT] = { "integer", 0, 4 },
626 [SMP_T_IPV4] = { "ip", 0, 4 },
627 [SMP_T_IPV6] = { "ipv6", 0, 16 },
628 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
629 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
630};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100631
632/*
633 * Parse table type configuration.
634 * Returns 0 on successful parsing, else 1.
635 * <myidx> is set at next configuration <args> index.
636 */
637int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
638{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200639 for (*type = 0; *type < SMP_TYPES; (*type)++) {
640 if (!stktable_types[*type].kw)
641 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100642 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
643 continue;
644
645 *key_size = stktable_types[*type].default_size;
646 (*myidx)++;
647
Willy Tarreauaea940e2010-06-06 11:56:36 +0200648 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100649 if (strcmp("len", args[*myidx]) == 0) {
650 (*myidx)++;
651 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200652 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100653 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200654 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200655 /* null terminated string needs +1 for '\0'. */
656 (*key_size)++;
657 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100658 (*myidx)++;
659 }
660 }
661 return 0;
662 }
663 return 1;
664}
665
Willy Tarreau8fed9032014-07-03 17:02:46 +0200666/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200667 * Note that the sample *is* modified and that the returned key may point
668 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200669 * Returns NULL if the sample could not be converted (eg: no matching type),
670 * otherwise a pointer to the static stktable_key filled with what is needed
671 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200672 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200673struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200674{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200675 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200676 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200677 return NULL;
678
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200679 /* Fill static_table_key. */
680 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200681
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200682 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200683 static_table_key.key = &smp->data.u.ipv4;
684 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200685 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200686
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200687 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200688 static_table_key.key = &smp->data.u.ipv6;
689 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200690 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200691
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200692 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200693 /* The stick table require a 32bit unsigned int, "sint" is a
694 * signed 64 it, so we can convert it inplace.
695 */
696 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200697 static_table_key.key = &smp->data.u.sint;
698 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200699 break;
700
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200701 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200702 if (!smp_make_safe(smp))
703 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200704 static_table_key.key = smp->data.u.str.area;
705 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200706 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200707
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200708 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200709 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200710 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200711 if (!smp_make_rw(smp))
712 return NULL;
713
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200714 if (smp->data.u.str.size < t->key_size)
715 if (!smp_dup(smp))
716 return NULL;
717 if (smp->data.u.str.size < t->key_size)
718 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200719 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
720 t->key_size - smp->data.u.str.data);
721 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200722 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200723 static_table_key.key = smp->data.u.str.area;
724 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200725 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200726
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200727 default: /* impossible case. */
728 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200729 }
730
Christopher Fauletca20d022017-08-29 15:30:31 +0200731 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200732}
733
734/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200735 * Process a fetch + format conversion as defined by the sample expression <expr>
736 * on request or response considering the <opt> parameter. Returns either NULL if
737 * no key could be extracted, or a pointer to the converted result stored in
738 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
739 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200740 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
741 * without SMP_OPT_FINAL). The output will be usable like this :
742 *
743 * return MAY_CHANGE FINAL Meaning for the sample
744 * NULL 0 * Not present and will never be (eg: header)
745 * NULL 1 0 Not present or unstable, could change (eg: req_len)
746 * NULL 1 1 Not present, will not change anymore
747 * smp 0 * Present and will not change (eg: header)
748 * smp 1 0 not possible
749 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200750 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200751struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200752 unsigned int opt, struct sample_expr *expr, struct sample *smp)
753{
754 if (smp)
755 memset(smp, 0, sizeof(*smp));
756
Willy Tarreau192252e2015-04-04 01:47:55 +0200757 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200758 if (!smp)
759 return NULL;
760
761 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
762 return NULL; /* we can only use stable samples */
763
764 return smp_to_stkey(smp, t);
765}
766
767/*
Willy Tarreau12785782012-04-27 21:37:17 +0200768 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200769 * type <table_type>, otherwise zero. Used in configuration check.
770 */
Willy Tarreau12785782012-04-27 21:37:17 +0200771int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200772{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100773 int out_type;
774
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200775 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200776 return 0;
777
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100778 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200779
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200780 /* Convert sample. */
781 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100782 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200783
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200784 return 1;
785}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100786
Willy Tarreauedee1d62014-07-15 16:44:27 +0200787/* Extra data types processing : after the last one, some room may remain
788 * before STKTABLE_DATA_TYPES that may be used to register extra data types
789 * at run time.
790 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200791struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200792 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200793 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200794 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200795 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200796 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
797 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
798 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
799 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
800 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
801 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
802 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
803 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
804 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
805 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
806 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
807 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
808 [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 +0100809 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
810 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +0200811};
812
Willy Tarreauedee1d62014-07-15 16:44:27 +0200813/* Registers stick-table extra data type with index <idx>, name <name>, type
814 * <std_type> and arg type <arg_type>. If the index is negative, the next free
815 * index is automatically allocated. The allocated index is returned, or -1 if
816 * no free index was found or <name> was already registered. The <name> is used
817 * directly as a pointer, so if it's not stable, the caller must allocate it.
818 */
819int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
820{
821 if (idx < 0) {
822 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
823 if (!stktable_data_types[idx].name)
824 break;
825
826 if (strcmp(stktable_data_types[idx].name, name) == 0)
827 return -1;
828 }
829 }
830
831 if (idx >= STKTABLE_DATA_TYPES)
832 return -1;
833
834 if (stktable_data_types[idx].name != NULL)
835 return -1;
836
837 stktable_data_types[idx].name = name;
838 stktable_data_types[idx].std_type = std_type;
839 stktable_data_types[idx].arg_type = arg_type;
840 return idx;
841}
842
Willy Tarreau08d5f982010-06-06 13:34:54 +0200843/*
844 * Returns the data type number for the stktable_data_type whose name is <name>,
845 * or <0 if not found.
846 */
847int stktable_get_data_type(char *name)
848{
849 int type;
850
851 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +0200852 if (!stktable_data_types[type].name)
853 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +0200854 if (strcmp(name, stktable_data_types[type].name) == 0)
855 return type;
856 }
857 return -1;
858}
859
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200860/* Casts sample <smp> to the type of the table specified in arg(0), and looks
861 * it up into this table. Returns true if found, false otherwise. The input
862 * type is STR so that input samples are converted to string (since all types
863 * can be converted to strings), then the function casts the string again into
864 * the table's type. This is a double conversion, but in the future we might
865 * support automatic input types to perform the cast on the fly.
866 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200867static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200868{
869 struct stktable *t;
870 struct stktable_key *key;
871 struct stksess *ts;
872
873 t = &arg_p[0].data.prx->table;
874
875 key = smp_to_stkey(smp, t);
876 if (!key)
877 return 0;
878
879 ts = stktable_lookup_key(t, key);
880
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200881 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200882 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200883 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +0200884 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200885 return 1;
886}
887
888/* Casts sample <smp> to the type of the table specified in arg(0), and looks
889 * it up into this table. Returns the data rate received from clients in bytes/s
890 * if the key is present in the table, otherwise zero, so that comparisons can
891 * be easily performed. If the inspected parameter is not stored in the table,
892 * <not found> is returned.
893 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200894static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200895{
896 struct stktable *t;
897 struct stktable_key *key;
898 struct stksess *ts;
899 void *ptr;
900
901 t = &arg_p[0].data.prx->table;
902
903 key = smp_to_stkey(smp, t);
904 if (!key)
905 return 0;
906
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200907 ts = stktable_lookup_key(t, key);
908
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200909 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200910 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200911 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200912
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200913 if (!ts) /* key not present */
914 return 1;
915
916 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400917 if (ptr)
918 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
919 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200920
Daniel Corbett3e60b112018-05-27 09:47:12 -0400921 stktable_release(t, ts);
922 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200923}
924
925/* Casts sample <smp> to the type of the table specified in arg(0), and looks
926 * it up into this table. Returns the cumulated number of connections for the key
927 * if the key is present in the table, otherwise zero, so that comparisons can
928 * be easily performed. If the inspected parameter is not stored in the table,
929 * <not found> is returned.
930 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200931static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200932{
933 struct stktable *t;
934 struct stktable_key *key;
935 struct stksess *ts;
936 void *ptr;
937
938 t = &arg_p[0].data.prx->table;
939
940 key = smp_to_stkey(smp, t);
941 if (!key)
942 return 0;
943
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200944 ts = stktable_lookup_key(t, key);
945
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200946 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200947 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200948 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200949
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200950 if (!ts) /* key not present */
951 return 1;
952
953 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400954 if (ptr)
955 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200956
Daniel Corbett3e60b112018-05-27 09:47:12 -0400957 stktable_release(t, ts);
958 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200959}
960
961/* Casts sample <smp> to the type of the table specified in arg(0), and looks
962 * it up into this table. Returns the number of concurrent connections for the
963 * key if the key is present in the table, otherwise zero, so that comparisons
964 * can be easily performed. If the inspected parameter is not stored in the
965 * table, <not found> is returned.
966 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200967static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200968{
969 struct stktable *t;
970 struct stktable_key *key;
971 struct stksess *ts;
972 void *ptr;
973
974 t = &arg_p[0].data.prx->table;
975
976 key = smp_to_stkey(smp, t);
977 if (!key)
978 return 0;
979
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200980 ts = stktable_lookup_key(t, key);
981
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200982 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200983 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200984 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200985
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200986 if (!ts) /* key not present */
987 return 1;
988
989 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400990 if (ptr)
991 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200992
Daniel Corbett3e60b112018-05-27 09:47:12 -0400993 stktable_release(t, ts);
994 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200995}
996
997/* Casts sample <smp> to the type of the table specified in arg(0), and looks
998 * it up into this table. Returns the rate of incoming connections from the key
999 * if the key is present in the table, otherwise zero, so that comparisons can
1000 * be easily performed. If the inspected parameter is not stored in the table,
1001 * <not found> is returned.
1002 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001003static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001004{
1005 struct stktable *t;
1006 struct stktable_key *key;
1007 struct stksess *ts;
1008 void *ptr;
1009
1010 t = &arg_p[0].data.prx->table;
1011
1012 key = smp_to_stkey(smp, t);
1013 if (!key)
1014 return 0;
1015
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001016 ts = stktable_lookup_key(t, key);
1017
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001018 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001019 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001020 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001021
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001022 if (!ts) /* key not present */
1023 return 1;
1024
1025 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001026 if (ptr)
1027 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1028 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001029
Daniel Corbett3e60b112018-05-27 09:47:12 -04001030 stktable_release(t, ts);
1031 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001032}
1033
1034/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1035 * it up into this table. Returns the data rate sent to clients in bytes/s
1036 * if the key is present in the table, otherwise zero, so that comparisons can
1037 * be easily performed. If the inspected parameter is not stored in the table,
1038 * <not found> is returned.
1039 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001040static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001041{
1042 struct stktable *t;
1043 struct stktable_key *key;
1044 struct stksess *ts;
1045 void *ptr;
1046
1047 t = &arg_p[0].data.prx->table;
1048
1049 key = smp_to_stkey(smp, t);
1050 if (!key)
1051 return 0;
1052
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001053 ts = stktable_lookup_key(t, key);
1054
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001055 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001056 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001057 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001058
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001059 if (!ts) /* key not present */
1060 return 1;
1061
1062 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001063 if (ptr)
1064 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1065 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001066
Daniel Corbett3e60b112018-05-27 09:47:12 -04001067 stktable_release(t, ts);
1068 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001069}
1070
1071/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001072 * it up into this table. Returns the value of the GPT0 tag for the key
1073 * if the key is present in the table, otherwise false, so that comparisons can
1074 * be easily performed. If the inspected parameter is not stored in the table,
1075 * <not found> is returned.
1076 */
1077static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1078{
1079 struct stktable *t;
1080 struct stktable_key *key;
1081 struct stksess *ts;
1082 void *ptr;
1083
1084 t = &arg_p[0].data.prx->table;
1085
1086 key = smp_to_stkey(smp, t);
1087 if (!key)
1088 return 0;
1089
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001090 ts = stktable_lookup_key(t, key);
1091
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001092 smp->flags = SMP_F_VOL_TEST;
1093 smp->data.type = SMP_T_SINT;
1094 smp->data.u.sint = 0;
1095
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001096 if (!ts) /* key not present */
1097 return 1;
1098
1099 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001100 if (ptr)
1101 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001102
Daniel Corbett3e60b112018-05-27 09:47:12 -04001103 stktable_release(t, ts);
1104 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001105}
1106
1107/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001108 * it up into this table. Returns the value of the GPC0 counter for the key
1109 * if the key is present in the table, otherwise zero, so that comparisons can
1110 * be easily performed. If the inspected parameter is not stored in the table,
1111 * <not found> is returned.
1112 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001113static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001114{
1115 struct stktable *t;
1116 struct stktable_key *key;
1117 struct stksess *ts;
1118 void *ptr;
1119
1120 t = &arg_p[0].data.prx->table;
1121
1122 key = smp_to_stkey(smp, t);
1123 if (!key)
1124 return 0;
1125
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001126 ts = stktable_lookup_key(t, key);
1127
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001128 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001129 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001130 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001131
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001132 if (!ts) /* key not present */
1133 return 1;
1134
1135 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001136 if (ptr)
1137 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001138
Daniel Corbett3e60b112018-05-27 09:47:12 -04001139 stktable_release(t, ts);
1140 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001141}
1142
1143/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1144 * it up into this table. Returns the event rate of the GPC0 counter for the key
1145 * if the key is present in the table, otherwise zero, so that comparisons can
1146 * be easily performed. If the inspected parameter is not stored in the table,
1147 * <not found> is returned.
1148 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001149static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001150{
1151 struct stktable *t;
1152 struct stktable_key *key;
1153 struct stksess *ts;
1154 void *ptr;
1155
1156 t = &arg_p[0].data.prx->table;
1157
1158 key = smp_to_stkey(smp, t);
1159 if (!key)
1160 return 0;
1161
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001162 ts = stktable_lookup_key(t, key);
1163
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001164 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001165 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001166 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001167
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001168 if (!ts) /* key not present */
1169 return 1;
1170
1171 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001172 if (ptr)
1173 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1174 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001175
Daniel Corbett3e60b112018-05-27 09:47:12 -04001176 stktable_release(t, ts);
1177 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001178}
1179
1180/* 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 +01001181 * it up into this table. Returns the value of the GPC1 counter for the key
1182 * if the key is present in the table, otherwise zero, so that comparisons can
1183 * be easily performed. If the inspected parameter is not stored in the table,
1184 * <not found> is returned.
1185 */
1186static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1187{
1188 struct stktable *t;
1189 struct stktable_key *key;
1190 struct stksess *ts;
1191 void *ptr;
1192
1193 t = &arg_p[0].data.prx->table;
1194
1195 key = smp_to_stkey(smp, t);
1196 if (!key)
1197 return 0;
1198
1199 ts = stktable_lookup_key(t, key);
1200
1201 smp->flags = SMP_F_VOL_TEST;
1202 smp->data.type = SMP_T_SINT;
1203 smp->data.u.sint = 0;
1204
1205 if (!ts) /* key not present */
1206 return 1;
1207
1208 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001209 if (ptr)
1210 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001211
Daniel Corbett3e60b112018-05-27 09:47:12 -04001212 stktable_release(t, ts);
1213 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001214}
1215
1216/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1217 * it up into this table. Returns the event rate of the GPC1 counter for the key
1218 * if the key is present in the table, otherwise zero, so that comparisons can
1219 * be easily performed. If the inspected parameter is not stored in the table,
1220 * <not found> is returned.
1221 */
1222static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1223{
1224 struct stktable *t;
1225 struct stktable_key *key;
1226 struct stksess *ts;
1227 void *ptr;
1228
1229 t = &arg_p[0].data.prx->table;
1230
1231 key = smp_to_stkey(smp, t);
1232 if (!key)
1233 return 0;
1234
1235 ts = stktable_lookup_key(t, key);
1236
1237 smp->flags = SMP_F_VOL_TEST;
1238 smp->data.type = SMP_T_SINT;
1239 smp->data.u.sint = 0;
1240
1241 if (!ts) /* key not present */
1242 return 1;
1243
1244 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001245 if (ptr)
1246 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1247 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001248
Daniel Corbett3e60b112018-05-27 09:47:12 -04001249 stktable_release(t, ts);
1250 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001251}
1252
1253/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254 * it up into this table. Returns the cumulated number of HTTP request errors
1255 * for the key if the key is present in the table, otherwise zero, so that
1256 * comparisons can be easily performed. If the inspected parameter is not stored
1257 * in the table, <not found> is returned.
1258 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001259static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001260{
1261 struct stktable *t;
1262 struct stktable_key *key;
1263 struct stksess *ts;
1264 void *ptr;
1265
1266 t = &arg_p[0].data.prx->table;
1267
1268 key = smp_to_stkey(smp, t);
1269 if (!key)
1270 return 0;
1271
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001272 ts = stktable_lookup_key(t, key);
1273
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001274 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001275 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001276 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001277
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001278 if (!ts) /* key not present */
1279 return 1;
1280
1281 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001282 if (ptr)
1283 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001284
Daniel Corbett3e60b112018-05-27 09:47:12 -04001285 stktable_release(t, ts);
1286 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001287}
1288
1289/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1290 * it up into this table. Returns the HTTP request error rate the key
1291 * if the key is present in the table, otherwise zero, so that comparisons can
1292 * be easily performed. If the inspected parameter is not stored in the table,
1293 * <not found> is returned.
1294 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001295static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001296{
1297 struct stktable *t;
1298 struct stktable_key *key;
1299 struct stksess *ts;
1300 void *ptr;
1301
1302 t = &arg_p[0].data.prx->table;
1303
1304 key = smp_to_stkey(smp, t);
1305 if (!key)
1306 return 0;
1307
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001308 ts = stktable_lookup_key(t, key);
1309
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001311 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001312 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001313
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001314 if (!ts) /* key not present */
1315 return 1;
1316
1317 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001318 if (ptr)
1319 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1320 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001321
Daniel Corbett3e60b112018-05-27 09:47:12 -04001322 stktable_release(t, ts);
1323 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001324}
1325
1326/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1327 * it up into this table. Returns the cumulated number of HTTP request for the
1328 * key if the key is present in the table, otherwise zero, so that comparisons
1329 * can be easily performed. If the inspected parameter is not stored in the
1330 * table, <not found> is returned.
1331 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001332static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001333{
1334 struct stktable *t;
1335 struct stktable_key *key;
1336 struct stksess *ts;
1337 void *ptr;
1338
1339 t = &arg_p[0].data.prx->table;
1340
1341 key = smp_to_stkey(smp, t);
1342 if (!key)
1343 return 0;
1344
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001345 ts = stktable_lookup_key(t, key);
1346
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001348 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001349 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351 if (!ts) /* key not present */
1352 return 1;
1353
1354 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001355 if (ptr)
1356 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357
Daniel Corbett3e60b112018-05-27 09:47:12 -04001358 stktable_release(t, ts);
1359 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360}
1361
1362/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1363 * it up into this table. Returns the HTTP request rate the key if the key is
1364 * present in the table, otherwise zero, so that comparisons can be easily
1365 * performed. If the inspected parameter is not stored in the table, <not found>
1366 * is returned.
1367 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001368static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001369{
1370 struct stktable *t;
1371 struct stktable_key *key;
1372 struct stksess *ts;
1373 void *ptr;
1374
1375 t = &arg_p[0].data.prx->table;
1376
1377 key = smp_to_stkey(smp, t);
1378 if (!key)
1379 return 0;
1380
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001381 ts = stktable_lookup_key(t, key);
1382
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001383 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001384 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001385 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001387 if (!ts) /* key not present */
1388 return 1;
1389
1390 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001391 if (ptr)
1392 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1393 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001394
Daniel Corbett3e60b112018-05-27 09:47:12 -04001395 stktable_release(t, ts);
1396 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001397}
1398
1399/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1400 * it up into this table. Returns the volume of datareceived from clients in kbytes
1401 * if the key is present in the table, otherwise zero, so that comparisons can
1402 * be easily performed. If the inspected parameter is not stored in the table,
1403 * <not found> is returned.
1404 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001405static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001406{
1407 struct stktable *t;
1408 struct stktable_key *key;
1409 struct stksess *ts;
1410 void *ptr;
1411
1412 t = &arg_p[0].data.prx->table;
1413
1414 key = smp_to_stkey(smp, t);
1415 if (!key)
1416 return 0;
1417
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001418 ts = stktable_lookup_key(t, key);
1419
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001421 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001422 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001423
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001424 if (!ts) /* key not present */
1425 return 1;
1426
1427 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001428 if (ptr)
1429 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001430
Daniel Corbett3e60b112018-05-27 09:47:12 -04001431 stktable_release(t, ts);
1432 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001433}
1434
1435/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1436 * it up into this table. Returns the volume of data sent to clients in kbytes
1437 * if the key is present in the table, otherwise zero, so that comparisons can
1438 * be easily performed. If the inspected parameter is not stored in the table,
1439 * <not found> is returned.
1440 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001441static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001442{
1443 struct stktable *t;
1444 struct stktable_key *key;
1445 struct stksess *ts;
1446 void *ptr;
1447
1448 t = &arg_p[0].data.prx->table;
1449
1450 key = smp_to_stkey(smp, t);
1451 if (!key)
1452 return 0;
1453
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001454 ts = stktable_lookup_key(t, key);
1455
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001456 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001457 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001458 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001459
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001460 if (!ts) /* key not present */
1461 return 1;
1462
1463 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001464 if (ptr)
1465 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001466
Daniel Corbett3e60b112018-05-27 09:47:12 -04001467 stktable_release(t, ts);
1468 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001469}
1470
1471/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1472 * it up into this table. Returns the server ID associated with the key if the
1473 * key is present in the table, otherwise zero, so that comparisons can be
1474 * easily performed. If the inspected parameter is not stored in the table,
1475 * <not found> is returned.
1476 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001477static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001478{
1479 struct stktable *t;
1480 struct stktable_key *key;
1481 struct stksess *ts;
1482 void *ptr;
1483
1484 t = &arg_p[0].data.prx->table;
1485
1486 key = smp_to_stkey(smp, t);
1487 if (!key)
1488 return 0;
1489
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001490 ts = stktable_lookup_key(t, key);
1491
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001492 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001493 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001494 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001495
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496 if (!ts) /* key not present */
1497 return 1;
1498
1499 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001500 if (ptr)
1501 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001502
Daniel Corbett3e60b112018-05-27 09:47:12 -04001503 stktable_release(t, ts);
1504 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001505}
1506
1507/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1508 * it up into this table. Returns the cumulated number of sessions for the
1509 * key if the key is present in the table, otherwise zero, so that comparisons
1510 * can be easily performed. If the inspected parameter is not stored in the
1511 * table, <not found> is returned.
1512 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001513static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001514{
1515 struct stktable *t;
1516 struct stktable_key *key;
1517 struct stksess *ts;
1518 void *ptr;
1519
1520 t = &arg_p[0].data.prx->table;
1521
1522 key = smp_to_stkey(smp, t);
1523 if (!key)
1524 return 0;
1525
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001526 ts = stktable_lookup_key(t, key);
1527
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001528 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001529 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001530 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001531
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532 if (!ts) /* key not present */
1533 return 1;
1534
1535 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001536 if (ptr)
1537 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001538
Daniel Corbett3e60b112018-05-27 09:47:12 -04001539 stktable_release(t, ts);
1540 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001541}
1542
1543/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1544 * it up into this table. Returns the session rate the key if the key is
1545 * present in the table, otherwise zero, so that comparisons can be easily
1546 * performed. If the inspected parameter is not stored in the table, <not found>
1547 * is returned.
1548 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001549static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001550{
1551 struct stktable *t;
1552 struct stktable_key *key;
1553 struct stksess *ts;
1554 void *ptr;
1555
1556 t = &arg_p[0].data.prx->table;
1557
1558 key = smp_to_stkey(smp, t);
1559 if (!key)
1560 return 0;
1561
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001562 ts = stktable_lookup_key(t, key);
1563
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001564 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001565 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001566 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001567
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001568 if (!ts) /* key not present */
1569 return 1;
1570
1571 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001572 if (ptr)
1573 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1574 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001575
Daniel Corbett3e60b112018-05-27 09:47:12 -04001576 stktable_release(t, ts);
1577 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001578}
1579
1580/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1581 * it up into this table. Returns the amount of concurrent connections tracking
1582 * the same key if the key is present in the table, otherwise zero, so that
1583 * comparisons can be easily performed. If the inspected parameter is not
1584 * stored in the table, <not found> is returned.
1585 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001586static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001587{
1588 struct stktable *t;
1589 struct stktable_key *key;
1590 struct stksess *ts;
1591
1592 t = &arg_p[0].data.prx->table;
1593
1594 key = smp_to_stkey(smp, t);
1595 if (!key)
1596 return 0;
1597
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001598 ts = stktable_lookup_key(t, key);
1599
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001600 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001601 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001602 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001603
Tim Duesterhus65189c12018-06-26 15:57:29 +02001604 if (!ts)
1605 return 1;
1606
1607 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001608
Daniel Corbett3e60b112018-05-27 09:47:12 -04001609 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001610 return 1;
1611}
1612
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001613/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001614static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001615 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001616{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001617 struct stksess *ts;
1618 struct stkctr *stkctr;
1619
1620 /* Extract the stksess, return OK if no stksess available. */
1621 if (s)
1622 stkctr = &s->stkctr[rule->arg.gpc.sc];
1623 else
1624 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001625
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001626 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001627 if (ts) {
1628 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001629
Willy Tarreau79c1e912016-01-25 14:54:45 +01001630 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1631 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001632 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1633 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001634 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001635
1636 if (ptr1)
1637 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001638 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001639
Emeric Brun819fc6f2017-06-13 19:37:32 +02001640 if (ptr2)
1641 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001642
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001643 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001644
1645 /* If data was modified, we need to touch to re-schedule sync */
1646 stktable_touch_local(stkctr->table, ts, 0);
1647 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001648 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001649 return ACT_RET_CONT;
1650}
1651
1652/* This function is a common parser for using variables. It understands
1653 * the formats:
1654 *
1655 * sc-inc-gpc0(<stick-table ID>)
1656 *
1657 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1658 * it returns 1 and the variable <expr> is filled with the pointer to the
1659 * expression to execute.
1660 */
1661static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1662 struct act_rule *rule, char **err)
1663{
1664 const char *cmd_name = args[*arg-1];
1665 char *error;
1666
1667 cmd_name += strlen("sc-inc-gpc0");
1668 if (*cmd_name == '\0') {
1669 /* default stick table id. */
1670 rule->arg.gpc.sc = 0;
1671 } else {
1672 /* parse the stick table id. */
1673 if (*cmd_name != '(') {
1674 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1675 return ACT_RET_PRS_ERR;
1676 }
1677 cmd_name++; /* jump the '(' */
1678 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1679 if (*error != ')') {
1680 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1681 return ACT_RET_PRS_ERR;
1682 }
1683
1684 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1685 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1686 ACT_ACTION_TRK_SCMAX-1);
1687 return ACT_RET_PRS_ERR;
1688 }
1689 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001690 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001691 rule->action_ptr = action_inc_gpc0;
1692 return ACT_RET_PRS_OK;
1693}
1694
1695/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001696static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1697 struct session *sess, struct stream *s, int flags)
1698{
1699 struct stksess *ts;
1700 struct stkctr *stkctr;
1701
1702 /* Extract the stksess, return OK if no stksess available. */
1703 if (s)
1704 stkctr = &s->stkctr[rule->arg.gpc.sc];
1705 else
1706 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1707
1708 ts = stkctr_entry(stkctr);
1709 if (ts) {
1710 void *ptr1, *ptr2;
1711
1712 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1713 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1714 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1715 if (ptr1 || ptr2) {
1716 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1717
1718 if (ptr1)
1719 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1720 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1721
1722 if (ptr2)
1723 stktable_data_cast(ptr2, gpc1)++;
1724
1725 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1726
1727 /* If data was modified, we need to touch to re-schedule sync */
1728 stktable_touch_local(stkctr->table, ts, 0);
1729 }
1730 }
1731 return ACT_RET_CONT;
1732}
1733
1734/* This function is a common parser for using variables. It understands
1735 * the formats:
1736 *
1737 * sc-inc-gpc1(<stick-table ID>)
1738 *
1739 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1740 * it returns 1 and the variable <expr> is filled with the pointer to the
1741 * expression to execute.
1742 */
1743static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1744 struct act_rule *rule, char **err)
1745{
1746 const char *cmd_name = args[*arg-1];
1747 char *error;
1748
1749 cmd_name += strlen("sc-inc-gpc1");
1750 if (*cmd_name == '\0') {
1751 /* default stick table id. */
1752 rule->arg.gpc.sc = 0;
1753 } else {
1754 /* parse the stick table id. */
1755 if (*cmd_name != '(') {
1756 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1757 return ACT_RET_PRS_ERR;
1758 }
1759 cmd_name++; /* jump the '(' */
1760 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1761 if (*error != ')') {
1762 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1763 return ACT_RET_PRS_ERR;
1764 }
1765
1766 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1767 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1768 ACT_ACTION_TRK_SCMAX-1);
1769 return ACT_RET_PRS_ERR;
1770 }
1771 }
1772 rule->action = ACT_CUSTOM;
1773 rule->action_ptr = action_inc_gpc1;
1774 return ACT_RET_PRS_OK;
1775}
1776
1777/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001778static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001779 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001780{
1781 void *ptr;
1782 struct stksess *ts;
1783 struct stkctr *stkctr;
1784
1785 /* Extract the stksess, return OK if no stksess available. */
1786 if (s)
1787 stkctr = &s->stkctr[rule->arg.gpt.sc];
1788 else
1789 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001790
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001791 ts = stkctr_entry(stkctr);
1792 if (!ts)
1793 return ACT_RET_CONT;
1794
1795 /* Store the sample in the required sc, and ignore errors. */
1796 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001797 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001798 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001799
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001800 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001801
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001802 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001803
1804 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001805 }
1806
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001807 return ACT_RET_CONT;
1808}
1809
1810/* This function is a common parser for using variables. It understands
1811 * the format:
1812 *
1813 * set-gpt0(<stick-table ID>) <expression>
1814 *
1815 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1816 * it returns 1 and the variable <expr> is filled with the pointer to the
1817 * expression to execute.
1818 */
1819static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1820 struct act_rule *rule, char **err)
1821
1822
1823{
1824 const char *cmd_name = args[*arg-1];
1825 char *error;
1826
1827 cmd_name += strlen("sc-set-gpt0");
1828 if (*cmd_name == '\0') {
1829 /* default stick table id. */
1830 rule->arg.gpt.sc = 0;
1831 } else {
1832 /* parse the stick table id. */
1833 if (*cmd_name != '(') {
1834 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1835 return ACT_RET_PRS_ERR;
1836 }
1837 cmd_name++; /* jump the '(' */
1838 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1839 if (*error != ')') {
1840 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1841 return ACT_RET_PRS_ERR;
1842 }
1843
1844 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1845 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1846 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1847 return ACT_RET_PRS_ERR;
1848 }
1849 }
1850
1851 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1852 if (*error != '\0') {
1853 memprintf(err, "invalid integer value '%s'", args[*arg]);
1854 return ACT_RET_PRS_ERR;
1855 }
1856 (*arg)++;
1857
Thierry FOURNIER42148732015-09-02 17:17:33 +02001858 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001859 rule->action_ptr = action_set_gpt0;
1860
1861 return ACT_RET_PRS_OK;
1862}
1863
Willy Tarreau7d562212016-11-25 16:10:05 +01001864/* set temp integer to the number of used entries in the table pointed to by expr.
1865 * Accepts exactly 1 argument of type table.
1866 */
1867static int
1868smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1869{
1870 smp->flags = SMP_F_VOL_TEST;
1871 smp->data.type = SMP_T_SINT;
1872 smp->data.u.sint = args->data.prx->table.current;
1873 return 1;
1874}
1875
1876/* set temp integer to the number of free entries in the table pointed to by expr.
1877 * Accepts exactly 1 argument of type table.
1878 */
1879static int
1880smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1881{
1882 struct proxy *px;
1883
1884 px = args->data.prx;
1885 smp->flags = SMP_F_VOL_TEST;
1886 smp->data.type = SMP_T_SINT;
1887 smp->data.u.sint = px->table.size - px->table.current;
1888 return 1;
1889}
1890
1891/* Returns a pointer to a stkctr depending on the fetch keyword name.
1892 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1893 * sc[0-9]_* will return a pointer to the respective field in the
1894 * stream <l4>. sc_* requires an UINT argument specifying the stick
1895 * counter number. src_* will fill a locally allocated structure with
1896 * the table and entry corresponding to what is specified with src_*.
1897 * NULL may be returned if the designated stkctr is not tracked. For
1898 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1899 * passed. When present, the currently tracked key is then looked up
1900 * in the specified table instead of the current table. The purpose is
1901 * to be able to convery multiple values per key (eg: have gpc0 from
1902 * multiple tables). <strm> is allowed to be NULL, in which case only
1903 * the session will be consulted.
1904 */
1905struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001906smp_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 +01001907{
Willy Tarreau7d562212016-11-25 16:10:05 +01001908 struct stkctr *stkptr;
1909 struct stksess *stksess;
1910 unsigned int num = kw[2] - '0';
1911 int arg = 0;
1912
1913 if (num == '_' - '0') {
1914 /* sc_* variant, args[0] = ctr# (mandatory) */
1915 num = args[arg++].data.sint;
1916 if (num >= MAX_SESS_STKCTR)
1917 return NULL;
1918 }
1919 else if (num > 9) { /* src_* variant, args[0] = table */
1920 struct stktable_key *key;
1921 struct connection *conn = objt_conn(sess->origin);
1922 struct sample smp;
1923
1924 if (!conn)
1925 return NULL;
1926
1927 /* Fetch source adress in a sample. */
1928 smp.px = NULL;
1929 smp.sess = sess;
1930 smp.strm = strm;
1931 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1932 return NULL;
1933
1934 /* Converts into key. */
1935 key = smp_to_stkey(&smp, &args->data.prx->table);
1936 if (!key)
1937 return NULL;
1938
Emeric Brun819fc6f2017-06-13 19:37:32 +02001939 stkctr->table = &args->data.prx->table;
1940 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1941 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001942 }
1943
1944 /* Here, <num> contains the counter number from 0 to 9 for
1945 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1946 * args[arg] is the first optional argument. We first lookup the
1947 * ctr form the stream, then from the session if it was not there.
1948 */
1949
1950 if (strm)
1951 stkptr = &strm->stkctr[num];
1952 if (!strm || !stkctr_entry(stkptr)) {
1953 stkptr = &sess->stkctr[num];
1954 if (!stkctr_entry(stkptr))
1955 return NULL;
1956 }
1957
1958 stksess = stkctr_entry(stkptr);
1959 if (!stksess)
1960 return NULL;
1961
1962 if (unlikely(args[arg].type == ARGT_TAB)) {
1963 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001964 stkctr->table = &args[arg].data.prx->table;
1965 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1966 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001967 }
1968 return stkptr;
1969}
1970
1971/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1972 * the entry if it doesn't exist yet. This is needed for a few fetch
1973 * functions which need to create an entry, such as src_inc_gpc* and
1974 * src_clr_gpc*.
1975 */
1976struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001977smp_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 +01001978{
Willy Tarreau7d562212016-11-25 16:10:05 +01001979 struct stktable_key *key;
1980 struct connection *conn = objt_conn(sess->origin);
1981 struct sample smp;
1982
1983 if (strncmp(kw, "src_", 4) != 0)
1984 return NULL;
1985
1986 if (!conn)
1987 return NULL;
1988
1989 /* Fetch source adress in a sample. */
1990 smp.px = NULL;
1991 smp.sess = sess;
1992 smp.strm = strm;
1993 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1994 return NULL;
1995
1996 /* Converts into key. */
1997 key = smp_to_stkey(&smp, &args->data.prx->table);
1998 if (!key)
1999 return NULL;
2000
Emeric Brun819fc6f2017-06-13 19:37:32 +02002001 stkctr->table = &args->data.prx->table;
2002 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2003 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002004}
2005
2006/* set return a boolean indicating if the requested stream counter is
2007 * currently being tracked or not.
2008 * Supports being called as "sc[0-9]_tracked" only.
2009 */
2010static int
2011smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2012{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002013 struct stkctr tmpstkctr;
2014 struct stkctr *stkctr;
2015
Willy Tarreau7d562212016-11-25 16:10:05 +01002016 smp->flags = SMP_F_VOL_TEST;
2017 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002018 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2019 smp->data.u.sint = !!stkctr;
2020
2021 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002022 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002023 stktable_release(stkctr->table, stkctr_entry(stkctr));
2024
Willy Tarreau7d562212016-11-25 16:10:05 +01002025 return 1;
2026}
2027
2028/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2029 * frontend counters or from the src.
2030 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2031 * zero is returned if the key is new.
2032 */
2033static int
2034smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2035{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002036 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002037 struct stkctr *stkctr;
2038
Emeric Brun819fc6f2017-06-13 19:37:32 +02002039 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002040 if (!stkctr)
2041 return 0;
2042
2043 smp->flags = SMP_F_VOL_TEST;
2044 smp->data.type = SMP_T_SINT;
2045 smp->data.u.sint = 0;
2046
Emeric Brun819fc6f2017-06-13 19:37:32 +02002047 if (stkctr_entry(stkctr)) {
2048 void *ptr;
2049
2050 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2051 if (!ptr) {
2052 if (stkctr == &tmpstkctr)
2053 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002054 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002055 }
2056
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002057 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002058
Willy Tarreau7d562212016-11-25 16:10:05 +01002059 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002060
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002061 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002062
2063 if (stkctr == &tmpstkctr)
2064 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002065 }
2066 return 1;
2067}
2068
2069/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2070 * frontend counters or from the src.
2071 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2072 * zero is returned if the key is new.
2073 */
2074static int
2075smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2076{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002077 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002078 struct stkctr *stkctr;
2079
Emeric Brun819fc6f2017-06-13 19:37:32 +02002080 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002081 if (!stkctr)
2082 return 0;
2083
2084 smp->flags = SMP_F_VOL_TEST;
2085 smp->data.type = SMP_T_SINT;
2086 smp->data.u.sint = 0;
2087
2088 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002089 void *ptr;
2090
2091 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2092 if (!ptr) {
2093 if (stkctr == &tmpstkctr)
2094 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002095 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002096 }
2097
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002098 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002099
Willy Tarreau7d562212016-11-25 16:10:05 +01002100 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002101
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002102 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002103
2104 if (stkctr == &tmpstkctr)
2105 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002106 }
2107 return 1;
2108}
2109
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002110/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2111 * frontend counters or from the src.
2112 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2113 * zero is returned if the key is new.
2114 */
2115static int
2116smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2117{
2118 struct stkctr tmpstkctr;
2119 struct stkctr *stkctr;
2120
2121 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2122 if (!stkctr)
2123 return 0;
2124
2125 smp->flags = SMP_F_VOL_TEST;
2126 smp->data.type = SMP_T_SINT;
2127 smp->data.u.sint = 0;
2128
2129 if (stkctr_entry(stkctr) != NULL) {
2130 void *ptr;
2131
2132 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2133 if (!ptr) {
2134 if (stkctr == &tmpstkctr)
2135 stktable_release(stkctr->table, stkctr_entry(stkctr));
2136 return 0; /* parameter not stored */
2137 }
2138
2139 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2140
2141 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2142
2143 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2144
2145 if (stkctr == &tmpstkctr)
2146 stktable_release(stkctr->table, stkctr_entry(stkctr));
2147 }
2148 return 1;
2149}
2150
Willy Tarreau7d562212016-11-25 16:10:05 +01002151/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2152 * tracked frontend counters or from the src.
2153 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2154 * Value zero is returned if the key is new.
2155 */
2156static int
2157smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2158{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002159 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002160 struct stkctr *stkctr;
2161
Emeric Brun819fc6f2017-06-13 19:37:32 +02002162 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002163 if (!stkctr)
2164 return 0;
2165
2166 smp->flags = SMP_F_VOL_TEST;
2167 smp->data.type = SMP_T_SINT;
2168 smp->data.u.sint = 0;
2169 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002170 void *ptr;
2171
2172 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2173 if (!ptr) {
2174 if (stkctr == &tmpstkctr)
2175 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002176 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002177 }
2178
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002179 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002180
Willy Tarreau7d562212016-11-25 16:10:05 +01002181 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2182 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002183
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002184 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002185
2186 if (stkctr == &tmpstkctr)
2187 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002188 }
2189 return 1;
2190}
2191
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002192/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2193 * tracked frontend counters or from the src.
2194 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2195 * Value zero is returned if the key is new.
2196 */
2197static int
2198smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2199{
2200 struct stkctr tmpstkctr;
2201 struct stkctr *stkctr;
2202
2203 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2204 if (!stkctr)
2205 return 0;
2206
2207 smp->flags = SMP_F_VOL_TEST;
2208 smp->data.type = SMP_T_SINT;
2209 smp->data.u.sint = 0;
2210 if (stkctr_entry(stkctr) != NULL) {
2211 void *ptr;
2212
2213 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2214 if (!ptr) {
2215 if (stkctr == &tmpstkctr)
2216 stktable_release(stkctr->table, stkctr_entry(stkctr));
2217 return 0; /* parameter not stored */
2218 }
2219
2220 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2221
2222 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2223 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2224
2225 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2226
2227 if (stkctr == &tmpstkctr)
2228 stktable_release(stkctr->table, stkctr_entry(stkctr));
2229 }
2230 return 1;
2231}
2232
Willy Tarreau7d562212016-11-25 16:10:05 +01002233/* Increment the General Purpose Counter 0 value from the stream's tracked
2234 * frontend counters and return it into temp integer.
2235 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2236 */
2237static int
2238smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2239{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002240 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002241 struct stkctr *stkctr;
2242
Emeric Brun819fc6f2017-06-13 19:37:32 +02002243 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002244 if (!stkctr)
2245 return 0;
2246
2247 smp->flags = SMP_F_VOL_TEST;
2248 smp->data.type = SMP_T_SINT;
2249 smp->data.u.sint = 0;
2250
Emeric Brun819fc6f2017-06-13 19:37:32 +02002251 if (!stkctr_entry(stkctr))
2252 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002253
2254 if (stkctr && stkctr_entry(stkctr)) {
2255 void *ptr1,*ptr2;
2256
Emeric Brun819fc6f2017-06-13 19:37:32 +02002257
Willy Tarreau7d562212016-11-25 16:10:05 +01002258 /* First, update gpc0_rate if it's tracked. Second, update its
2259 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2260 */
2261 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002262 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002263 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002264 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002265
Emeric Brun819fc6f2017-06-13 19:37:32 +02002266 if (ptr1) {
2267 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2268 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2269 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2270 }
2271
2272 if (ptr2)
2273 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2274
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002275 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002276
2277 /* If data was modified, we need to touch to re-schedule sync */
2278 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2279 }
2280 else if (stkctr == &tmpstkctr)
2281 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002282 }
2283 return 1;
2284}
2285
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002286/* Increment the General Purpose Counter 1 value from the stream's tracked
2287 * frontend counters and return it into temp integer.
2288 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2289 */
2290static int
2291smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2292{
2293 struct stkctr tmpstkctr;
2294 struct stkctr *stkctr;
2295
2296 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2297 if (!stkctr)
2298 return 0;
2299
2300 smp->flags = SMP_F_VOL_TEST;
2301 smp->data.type = SMP_T_SINT;
2302 smp->data.u.sint = 0;
2303
2304 if (!stkctr_entry(stkctr))
2305 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2306
2307 if (stkctr && stkctr_entry(stkctr)) {
2308 void *ptr1,*ptr2;
2309
2310
2311 /* First, update gpc1_rate if it's tracked. Second, update its
2312 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2313 */
2314 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2315 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2316 if (ptr1 || ptr2) {
2317 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2318
2319 if (ptr1) {
2320 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2321 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2322 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2323 }
2324
2325 if (ptr2)
2326 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2327
2328 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2329
2330 /* If data was modified, we need to touch to re-schedule sync */
2331 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2332 }
2333 else if (stkctr == &tmpstkctr)
2334 stktable_release(stkctr->table, stkctr_entry(stkctr));
2335 }
2336 return 1;
2337}
2338
Willy Tarreau7d562212016-11-25 16:10:05 +01002339/* Clear the General Purpose Counter 0 value from the stream's tracked
2340 * frontend counters and return its previous value into temp integer.
2341 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2342 */
2343static int
2344smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2345{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002346 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002347 struct stkctr *stkctr;
2348
Emeric Brun819fc6f2017-06-13 19:37:32 +02002349 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002350 if (!stkctr)
2351 return 0;
2352
2353 smp->flags = SMP_F_VOL_TEST;
2354 smp->data.type = SMP_T_SINT;
2355 smp->data.u.sint = 0;
2356
Emeric Brun819fc6f2017-06-13 19:37:32 +02002357 if (!stkctr_entry(stkctr))
2358 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002359
Emeric Brun819fc6f2017-06-13 19:37:32 +02002360 if (stkctr && stkctr_entry(stkctr)) {
2361 void *ptr;
2362
2363 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2364 if (!ptr) {
2365 if (stkctr == &tmpstkctr)
2366 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002367 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002368 }
2369
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002370 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002371
Willy Tarreau7d562212016-11-25 16:10:05 +01002372 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2373 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002374
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002375 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002376
Willy Tarreau7d562212016-11-25 16:10:05 +01002377 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002378 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002379 }
2380 return 1;
2381}
2382
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002383/* Clear the General Purpose Counter 1 value from the stream's tracked
2384 * frontend counters and return its previous value into temp integer.
2385 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2386 */
2387static int
2388smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2389{
2390 struct stkctr tmpstkctr;
2391 struct stkctr *stkctr;
2392
2393 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2394 if (!stkctr)
2395 return 0;
2396
2397 smp->flags = SMP_F_VOL_TEST;
2398 smp->data.type = SMP_T_SINT;
2399 smp->data.u.sint = 0;
2400
2401 if (!stkctr_entry(stkctr))
2402 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2403
2404 if (stkctr && stkctr_entry(stkctr)) {
2405 void *ptr;
2406
2407 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2408 if (!ptr) {
2409 if (stkctr == &tmpstkctr)
2410 stktable_release(stkctr->table, stkctr_entry(stkctr));
2411 return 0; /* parameter not stored */
2412 }
2413
2414 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2415
2416 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2417 stktable_data_cast(ptr, gpc1) = 0;
2418
2419 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2420
2421 /* If data was modified, we need to touch to re-schedule sync */
2422 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2423 }
2424 return 1;
2425}
2426
Willy Tarreau7d562212016-11-25 16:10:05 +01002427/* set <smp> to the cumulated number of connections from the stream's tracked
2428 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2429 * "src_conn_cnt" only.
2430 */
2431static int
2432smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2433{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002434 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002435 struct stkctr *stkctr;
2436
Emeric Brun819fc6f2017-06-13 19:37:32 +02002437 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002438 if (!stkctr)
2439 return 0;
2440
2441 smp->flags = SMP_F_VOL_TEST;
2442 smp->data.type = SMP_T_SINT;
2443 smp->data.u.sint = 0;
2444 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002445 void *ptr;
2446
2447 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2448 if (!ptr) {
2449 if (stkctr == &tmpstkctr)
2450 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002451 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002452 }
2453
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002454 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002455
Willy Tarreau7d562212016-11-25 16:10:05 +01002456 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002457
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002458 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002459
2460 if (stkctr == &tmpstkctr)
2461 stktable_release(stkctr->table, stkctr_entry(stkctr));
2462
2463
Willy Tarreau7d562212016-11-25 16:10:05 +01002464 }
2465 return 1;
2466}
2467
2468/* set <smp> to the connection rate from the stream's tracked frontend
2469 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2470 * only.
2471 */
2472static int
2473smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2474{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002475 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002476 struct stkctr *stkctr;
2477
Emeric Brun819fc6f2017-06-13 19:37:32 +02002478 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002479 if (!stkctr)
2480 return 0;
2481
2482 smp->flags = SMP_F_VOL_TEST;
2483 smp->data.type = SMP_T_SINT;
2484 smp->data.u.sint = 0;
2485 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002486 void *ptr;
2487
2488 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2489 if (!ptr) {
2490 if (stkctr == &tmpstkctr)
2491 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002492 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002493 }
2494
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002495 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002496
Willy Tarreau7d562212016-11-25 16:10:05 +01002497 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2498 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002499
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002500 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002501
2502 if (stkctr == &tmpstkctr)
2503 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002504 }
2505 return 1;
2506}
2507
2508/* set temp integer to the number of connections from the stream's source address
2509 * in the table pointed to by expr, after updating it.
2510 * Accepts exactly 1 argument of type table.
2511 */
2512static int
2513smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2514{
2515 struct connection *conn = objt_conn(smp->sess->origin);
2516 struct stksess *ts;
2517 struct stktable_key *key;
2518 void *ptr;
2519 struct proxy *px;
2520
2521 if (!conn)
2522 return 0;
2523
2524 /* Fetch source adress in a sample. */
2525 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2526 return 0;
2527
2528 /* Converts into key. */
2529 key = smp_to_stkey(smp, &args->data.prx->table);
2530 if (!key)
2531 return 0;
2532
2533 px = args->data.prx;
2534
Emeric Brun819fc6f2017-06-13 19:37:32 +02002535 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002536 /* entry does not exist and could not be created */
2537 return 0;
2538
2539 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002540 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002541 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002542 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002543
2544 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002545
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002546 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002547
Willy Tarreau7d562212016-11-25 16:10:05 +01002548 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002549
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002550 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002551
Willy Tarreau7d562212016-11-25 16:10:05 +01002552 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553
2554 stktable_touch_local(&px->table, ts, 1);
2555
2556 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002557 return 1;
2558}
2559
2560/* set <smp> to the number of concurrent connections from the stream's tracked
2561 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2562 * "src_conn_cur" only.
2563 */
2564static int
2565smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2566{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002567 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002568 struct stkctr *stkctr;
2569
Emeric Brun819fc6f2017-06-13 19:37:32 +02002570 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002571 if (!stkctr)
2572 return 0;
2573
2574 smp->flags = SMP_F_VOL_TEST;
2575 smp->data.type = SMP_T_SINT;
2576 smp->data.u.sint = 0;
2577 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002578 void *ptr;
2579
2580 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2581 if (!ptr) {
2582 if (stkctr == &tmpstkctr)
2583 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002584 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002585 }
2586
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002587 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002588
Willy Tarreau7d562212016-11-25 16:10:05 +01002589 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002590
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002591 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002592
2593 if (stkctr == &tmpstkctr)
2594 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002595 }
2596 return 1;
2597}
2598
2599/* set <smp> to the cumulated number of streams from the stream's tracked
2600 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2601 * "src_sess_cnt" only.
2602 */
2603static int
2604smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2605{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002606 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002607 struct stkctr *stkctr;
2608
Emeric Brun819fc6f2017-06-13 19:37:32 +02002609 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002610 if (!stkctr)
2611 return 0;
2612
2613 smp->flags = SMP_F_VOL_TEST;
2614 smp->data.type = SMP_T_SINT;
2615 smp->data.u.sint = 0;
2616 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002617 void *ptr;
2618
2619 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2620 if (!ptr) {
2621 if (stkctr == &tmpstkctr)
2622 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002623 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002624 }
2625
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002626 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002627
Willy Tarreau7d562212016-11-25 16:10:05 +01002628 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002629
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002630 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002631
2632 if (stkctr == &tmpstkctr)
2633 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002634 }
2635 return 1;
2636}
2637
2638/* set <smp> to the stream rate from the stream's tracked frontend counters.
2639 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2640 */
2641static int
2642smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2643{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002644 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002645 struct stkctr *stkctr;
2646
Emeric Brun819fc6f2017-06-13 19:37:32 +02002647 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002648 if (!stkctr)
2649 return 0;
2650
2651 smp->flags = SMP_F_VOL_TEST;
2652 smp->data.type = SMP_T_SINT;
2653 smp->data.u.sint = 0;
2654 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002655 void *ptr;
2656
2657 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2658 if (!ptr) {
2659 if (stkctr == &tmpstkctr)
2660 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002661 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662 }
2663
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002664 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002665
Willy Tarreau7d562212016-11-25 16:10:05 +01002666 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2667 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002668
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002669 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002670
2671 if (stkctr == &tmpstkctr)
2672 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002673 }
2674 return 1;
2675}
2676
2677/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2678 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2679 * "src_http_req_cnt" only.
2680 */
2681static int
2682smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2683{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002684 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002685 struct stkctr *stkctr;
2686
Emeric Brun819fc6f2017-06-13 19:37:32 +02002687 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002688 if (!stkctr)
2689 return 0;
2690
2691 smp->flags = SMP_F_VOL_TEST;
2692 smp->data.type = SMP_T_SINT;
2693 smp->data.u.sint = 0;
2694 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002695 void *ptr;
2696
2697 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2698 if (!ptr) {
2699 if (stkctr == &tmpstkctr)
2700 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002701 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002702 }
2703
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002704 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002705
Willy Tarreau7d562212016-11-25 16:10:05 +01002706 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002707
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002708 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002709
2710 if (stkctr == &tmpstkctr)
2711 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002712 }
2713 return 1;
2714}
2715
2716/* set <smp> to the HTTP request rate from the stream's tracked frontend
2717 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2718 * "src_http_req_rate" only.
2719 */
2720static int
2721smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2722{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002723 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002724 struct stkctr *stkctr;
2725
Emeric Brun819fc6f2017-06-13 19:37:32 +02002726 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002727 if (!stkctr)
2728 return 0;
2729
2730 smp->flags = SMP_F_VOL_TEST;
2731 smp->data.type = SMP_T_SINT;
2732 smp->data.u.sint = 0;
2733 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002734 void *ptr;
2735
2736 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2737 if (!ptr) {
2738 if (stkctr == &tmpstkctr)
2739 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002740 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002741 }
2742
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002743 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002744
Willy Tarreau7d562212016-11-25 16:10:05 +01002745 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2746 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002747
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002748 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002749
2750 if (stkctr == &tmpstkctr)
2751 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002752 }
2753 return 1;
2754}
2755
2756/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2757 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2758 * "src_http_err_cnt" only.
2759 */
2760static int
2761smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2762{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002763 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002764 struct stkctr *stkctr;
2765
Emeric Brun819fc6f2017-06-13 19:37:32 +02002766 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002767 if (!stkctr)
2768 return 0;
2769
2770 smp->flags = SMP_F_VOL_TEST;
2771 smp->data.type = SMP_T_SINT;
2772 smp->data.u.sint = 0;
2773 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002774 void *ptr;
2775
2776 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2777 if (!ptr) {
2778 if (stkctr == &tmpstkctr)
2779 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002780 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002781 }
2782
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002783 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002784
Willy Tarreau7d562212016-11-25 16:10:05 +01002785 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002786
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002787 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002788
2789 if (stkctr == &tmpstkctr)
2790 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002791 }
2792 return 1;
2793}
2794
2795/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2796 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2797 * "src_http_err_rate" only.
2798 */
2799static int
2800smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2801{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002802 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002803 struct stkctr *stkctr;
2804
Emeric Brun819fc6f2017-06-13 19:37:32 +02002805 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002806 if (!stkctr)
2807 return 0;
2808
2809 smp->flags = SMP_F_VOL_TEST;
2810 smp->data.type = SMP_T_SINT;
2811 smp->data.u.sint = 0;
2812 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002813 void *ptr;
2814
2815 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2816 if (!ptr) {
2817 if (stkctr == &tmpstkctr)
2818 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002819 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002820 }
2821
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002822 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002823
Willy Tarreau7d562212016-11-25 16:10:05 +01002824 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2825 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002826
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002827 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002828
2829 if (stkctr == &tmpstkctr)
2830 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002831 }
2832 return 1;
2833}
2834
2835/* set <smp> to the number of kbytes received from clients, as found in the
2836 * stream's tracked frontend counters. Supports being called as
2837 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2838 */
2839static int
2840smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2841{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002842 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002843 struct stkctr *stkctr;
2844
Emeric Brun819fc6f2017-06-13 19:37:32 +02002845 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002846 if (!stkctr)
2847 return 0;
2848
2849 smp->flags = SMP_F_VOL_TEST;
2850 smp->data.type = SMP_T_SINT;
2851 smp->data.u.sint = 0;
2852 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002853 void *ptr;
2854
2855 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2856 if (!ptr) {
2857 if (stkctr == &tmpstkctr)
2858 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002859 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002860 }
2861
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002862 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002863
Willy Tarreau7d562212016-11-25 16:10:05 +01002864 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002865
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002866 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002867
2868 if (stkctr == &tmpstkctr)
2869 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002870 }
2871 return 1;
2872}
2873
2874/* set <smp> to the data rate received from clients in bytes/s, as found
2875 * in the stream's tracked frontend counters. Supports being called as
2876 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2877 */
2878static int
2879smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2880{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002881 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002882 struct stkctr *stkctr;
2883
Emeric Brun819fc6f2017-06-13 19:37:32 +02002884 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002885 if (!stkctr)
2886 return 0;
2887
2888 smp->flags = SMP_F_VOL_TEST;
2889 smp->data.type = SMP_T_SINT;
2890 smp->data.u.sint = 0;
2891 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892 void *ptr;
2893
2894 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2895 if (!ptr) {
2896 if (stkctr == &tmpstkctr)
2897 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002898 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002899 }
2900
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002901 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002902
Willy Tarreau7d562212016-11-25 16:10:05 +01002903 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2904 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002905
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002906 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002907
2908 if (stkctr == &tmpstkctr)
2909 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002910 }
2911 return 1;
2912}
2913
2914/* set <smp> to the number of kbytes sent to clients, as found in the
2915 * stream's tracked frontend counters. Supports being called as
2916 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2917 */
2918static int
2919smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2920{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002921 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002922 struct stkctr *stkctr;
2923
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002925 if (!stkctr)
2926 return 0;
2927
2928 smp->flags = SMP_F_VOL_TEST;
2929 smp->data.type = SMP_T_SINT;
2930 smp->data.u.sint = 0;
2931 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002932 void *ptr;
2933
2934 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2935 if (!ptr) {
2936 if (stkctr == &tmpstkctr)
2937 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002938 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002939 }
2940
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002941 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002942
Willy Tarreau7d562212016-11-25 16:10:05 +01002943 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002944
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002945 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002946
2947 if (stkctr == &tmpstkctr)
2948 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002949 }
2950 return 1;
2951}
2952
2953/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2954 * stream's tracked frontend counters. Supports being called as
2955 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2956 */
2957static int
2958smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2959{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002960 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002961 struct stkctr *stkctr;
2962
Emeric Brun819fc6f2017-06-13 19:37:32 +02002963 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002964 if (!stkctr)
2965 return 0;
2966
2967 smp->flags = SMP_F_VOL_TEST;
2968 smp->data.type = SMP_T_SINT;
2969 smp->data.u.sint = 0;
2970 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002971 void *ptr;
2972
2973 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2974 if (!ptr) {
2975 if (stkctr == &tmpstkctr)
2976 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002977 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978 }
2979
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002980 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981
Willy Tarreau7d562212016-11-25 16:10:05 +01002982 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2983 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002984
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002985 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002986
2987 if (stkctr == &tmpstkctr)
2988 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002989 }
2990 return 1;
2991}
2992
2993/* set <smp> to the number of active trackers on the SC entry in the stream's
2994 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2995 */
2996static int
2997smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2998{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002999 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003000 struct stkctr *stkctr;
3001
Emeric Brun819fc6f2017-06-13 19:37:32 +02003002 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003003 if (!stkctr)
3004 return 0;
3005
3006 smp->flags = SMP_F_VOL_TEST;
3007 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003008 if (stkctr == &tmpstkctr) {
3009 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3010 stktable_release(stkctr->table, stkctr_entry(stkctr));
3011 }
3012 else {
3013 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3014 }
3015
Willy Tarreau7d562212016-11-25 16:10:05 +01003016 return 1;
3017}
3018
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003019
3020/* The functions below are used to manipulate table contents from the CLI.
3021 * There are 3 main actions, "clear", "set" and "show". The code is shared
3022 * between all actions, and the action is encoded in the void *private in
3023 * the appctx as well as in the keyword registration, among one of the
3024 * following values.
3025 */
3026
3027enum {
3028 STK_CLI_ACT_CLR,
3029 STK_CLI_ACT_SET,
3030 STK_CLI_ACT_SHOW,
3031};
3032
3033/* Dump the status of a table to a stream interface's
3034 * read buffer. It returns 0 if the output buffer is full
3035 * and needs to be called again, otherwise non-zero.
3036 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003037static int table_dump_head_to_buffer(struct buffer *msg,
3038 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003039 struct proxy *proxy, struct proxy *target)
3040{
3041 struct stream *s = si_strm(si);
3042
3043 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3044 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3045
3046 /* any other information should be dumped here */
3047
William Lallemand07a62f72017-05-24 00:57:40 +02003048 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003049 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3050
Willy Tarreau06d80a92017-10-19 14:32:15 +02003051 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003052 si_cant_put(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003053 return 0;
3054 }
3055
3056 return 1;
3057}
3058
3059/* Dump a table entry to a stream interface's
3060 * read buffer. It returns 0 if the output buffer is full
3061 * and needs to be called again, otherwise non-zero.
3062 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003063static int table_dump_entry_to_buffer(struct buffer *msg,
3064 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003065 struct proxy *proxy, struct stksess *entry)
3066{
3067 int dt;
3068
3069 chunk_appendf(msg, "%p:", entry);
3070
3071 if (proxy->table.type == SMP_T_IPV4) {
3072 char addr[INET_ADDRSTRLEN];
3073 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3074 chunk_appendf(msg, " key=%s", addr);
3075 }
3076 else if (proxy->table.type == SMP_T_IPV6) {
3077 char addr[INET6_ADDRSTRLEN];
3078 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3079 chunk_appendf(msg, " key=%s", addr);
3080 }
3081 else if (proxy->table.type == SMP_T_SINT) {
3082 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3083 }
3084 else if (proxy->table.type == SMP_T_STR) {
3085 chunk_appendf(msg, " key=");
3086 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3087 }
3088 else {
3089 chunk_appendf(msg, " key=");
3090 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3091 }
3092
3093 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3094
3095 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3096 void *ptr;
3097
3098 if (proxy->table.data_ofs[dt] == 0)
3099 continue;
3100 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3101 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3102 else
3103 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3104
3105 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3106 switch (stktable_data_types[dt].std_type) {
3107 case STD_T_SINT:
3108 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3109 break;
3110 case STD_T_UINT:
3111 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3112 break;
3113 case STD_T_ULL:
3114 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3115 break;
3116 case STD_T_FRQP:
3117 chunk_appendf(msg, "%d",
3118 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3119 proxy->table.data_arg[dt].u));
3120 break;
3121 }
3122 }
3123 chunk_appendf(msg, "\n");
3124
Willy Tarreau06d80a92017-10-19 14:32:15 +02003125 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003126 si_cant_put(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003127 return 0;
3128 }
3129
3130 return 1;
3131}
3132
3133
3134/* Processes a single table entry matching a specific key passed in argument.
3135 * returns 0 if wants to be called again, 1 if has ended processing.
3136 */
3137static int table_process_entry_per_key(struct appctx *appctx, char **args)
3138{
3139 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003140 struct proxy *px = appctx->ctx.table.target;
3141 struct stksess *ts;
3142 uint32_t uint32_key;
3143 unsigned char ip6_key[sizeof(struct in6_addr)];
3144 long long value;
3145 int data_type;
3146 int cur_arg;
3147 void *ptr;
3148 struct freq_ctr_period *frqp;
3149
3150 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003151 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003152 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003153 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003154 return 1;
3155 }
3156
3157 switch (px->table.type) {
3158 case SMP_T_IPV4:
3159 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003160 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003161 break;
3162 case SMP_T_IPV6:
3163 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003164 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003165 break;
3166 case SMP_T_SINT:
3167 {
3168 char *endptr;
3169 unsigned long val;
3170 errno = 0;
3171 val = strtoul(args[4], &endptr, 10);
3172 if ((errno == ERANGE && val == ULONG_MAX) ||
3173 (errno != 0 && val == 0) || endptr == args[4] ||
3174 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003175 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003176 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003177 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003178 return 1;
3179 }
3180 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003181 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003182 break;
3183 }
3184 break;
3185 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003186 static_table_key.key = args[4];
3187 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003188 break;
3189 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003190 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003191 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003192 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003193 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3194 break;
3195 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003196 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003197 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3198 break;
3199 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003200 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003201 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3202 break;
3203 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003204 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003205 appctx->ctx.cli.msg = "Unknown action\n";
3206 break;
3207 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003208 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003209 return 1;
3210 }
3211
3212 /* check permissions */
3213 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3214 return 1;
3215
Willy Tarreaua24bc782016-12-14 15:50:35 +01003216 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003217 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003218 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003219 if (!ts)
3220 return 1;
3221 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003222 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3223 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003224 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003226 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003228 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003229 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003230 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003231 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003232 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003233 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003234 break;
3235
3236 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003237 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003238 if (!ts)
3239 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003240
3241 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003242 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003243 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003244 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003245 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003246 return 1;
3247 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003248
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003249 break;
3250
3251 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003252 ts = stktable_get_entry(&px->table, &static_table_key);
3253 if (!ts) {
3254 /* don't delete an entry which is currently referenced */
3255 appctx->ctx.cli.severity = LOG_ERR;
3256 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3257 appctx->st0 = CLI_ST_PRINT;
3258 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003259 }
3260
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003261 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003262 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3263 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003264 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003265 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003266 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003267 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003268 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003269 return 1;
3270 }
3271
3272 data_type = stktable_get_data_type(args[cur_arg] + 5);
3273 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003274 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003275 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003276 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003277 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003278 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003279 return 1;
3280 }
3281
3282 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003283 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003284 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003285 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003286 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003287 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003288 return 1;
3289 }
3290
3291 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003292 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003293 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003294 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003295 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003296 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003297 return 1;
3298 }
3299
3300 ptr = stktable_data_ptr(&px->table, ts, data_type);
3301
3302 switch (stktable_data_types[data_type].std_type) {
3303 case STD_T_SINT:
3304 stktable_data_cast(ptr, std_t_sint) = value;
3305 break;
3306 case STD_T_UINT:
3307 stktable_data_cast(ptr, std_t_uint) = value;
3308 break;
3309 case STD_T_ULL:
3310 stktable_data_cast(ptr, std_t_ull) = value;
3311 break;
3312 case STD_T_FRQP:
3313 /* We set both the current and previous values. That way
3314 * the reported frequency is stable during all the period
3315 * then slowly fades out. This allows external tools to
3316 * push measures without having to update them too often.
3317 */
3318 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003319 /* First bit is reserved for the freq_ctr_period lock
3320 Note: here we're still protected by the stksess lock
3321 so we don't need to update the update the freq_ctr_period
3322 using its internal lock */
3323 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003324 frqp->prev_ctr = 0;
3325 frqp->curr_ctr = value;
3326 break;
3327 }
3328 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003329 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003330 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003331 break;
3332
3333 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003334 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003335 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003336 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003337 break;
3338 }
3339 return 1;
3340}
3341
3342/* Prepares the appctx fields with the data-based filters from the command line.
3343 * Returns 0 if the dump can proceed, 1 if has ended processing.
3344 */
3345static int table_prepare_data_request(struct appctx *appctx, char **args)
3346{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003347 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003348 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003349 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003350 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003351 return 1;
3352 }
3353
3354 /* condition on stored data value */
3355 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3356 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003357 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003358 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003359 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003360 return 1;
3361 }
3362
3363 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003364 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003365 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003366 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003367 return 1;
3368 }
3369
3370 appctx->ctx.table.data_op = get_std_op(args[4]);
3371 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003372 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003373 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003374 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003375 return 1;
3376 }
3377
3378 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003379 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003380 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003381 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003382 return 1;
3383 }
3384
3385 /* OK we're done, all the fields are set */
3386 return 0;
3387}
3388
3389/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003390static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003391{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003392 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003393 appctx->ctx.table.target = NULL;
3394 appctx->ctx.table.proxy = NULL;
3395 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003396 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003397
3398 if (*args[2]) {
3399 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3400 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003401 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003402 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003403 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003404 return 1;
3405 }
3406 }
3407 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003408 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003409 goto err_args;
3410 return 0;
3411 }
3412
3413 if (strcmp(args[3], "key") == 0)
3414 return table_process_entry_per_key(appctx, args);
3415 else if (strncmp(args[3], "data.", 5) == 0)
3416 return table_prepare_data_request(appctx, args);
3417 else if (*args[3])
3418 goto err_args;
3419
3420 return 0;
3421
3422err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003423 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003424 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003425 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003426 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3427 break;
3428 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003429 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003430 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3431 break;
3432 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003433 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003434 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3435 break;
3436 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003437 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003438 appctx->ctx.cli.msg = "Unknown action\n";
3439 break;
3440 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003441 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003442 return 1;
3443}
3444
3445/* This function is used to deal with table operations (dump or clear depending
3446 * on the action stored in appctx->private). It returns 0 if the output buffer is
3447 * full and it needs to be called again, otherwise non-zero.
3448 */
3449static int cli_io_handler_table(struct appctx *appctx)
3450{
3451 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003452 struct stream *s = si_strm(si);
3453 struct ebmb_node *eb;
3454 int dt;
3455 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003456 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003457
3458 /*
3459 * We have 3 possible states in appctx->st2 :
3460 * - STAT_ST_INIT : the first call
3461 * - STAT_ST_INFO : the proxy pointer points to the next table to
3462 * dump, the entry pointer is NULL ;
3463 * - STAT_ST_LIST : the proxy pointer points to the current table
3464 * and the entry pointer points to the next entry to be dumped,
3465 * and the refcount on the next entry is held ;
3466 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3467 * data though.
3468 */
3469
3470 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3471 /* in case of abort, remove any refcount we might have set on an entry */
3472 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003473 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003474 }
3475 return 1;
3476 }
3477
3478 chunk_reset(&trash);
3479
3480 while (appctx->st2 != STAT_ST_FIN) {
3481 switch (appctx->st2) {
3482 case STAT_ST_INIT:
3483 appctx->ctx.table.proxy = appctx->ctx.table.target;
3484 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003485 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003486
3487 appctx->ctx.table.entry = NULL;
3488 appctx->st2 = STAT_ST_INFO;
3489 break;
3490
3491 case STAT_ST_INFO:
3492 if (!appctx->ctx.table.proxy ||
3493 (appctx->ctx.table.target &&
3494 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3495 appctx->st2 = STAT_ST_END;
3496 break;
3497 }
3498
3499 if (appctx->ctx.table.proxy->table.size) {
3500 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3501 return 0;
3502
3503 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003504 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003505 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003506 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003507 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3508 if (eb) {
3509 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3510 appctx->ctx.table.entry->ref_cnt++;
3511 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003512 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003513 break;
3514 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003515 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003516 }
3517 }
3518 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3519 break;
3520
3521 case STAT_ST_LIST:
3522 skip_entry = 0;
3523
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003524 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003525
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003526 if (appctx->ctx.table.data_type >= 0) {
3527 /* we're filtering on some data contents */
3528 void *ptr;
3529 long long data;
3530
Emeric Brun819fc6f2017-06-13 19:37:32 +02003531
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003532 dt = appctx->ctx.table.data_type;
3533 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3534 appctx->ctx.table.entry,
3535 dt);
3536
3537 data = 0;
3538 switch (stktable_data_types[dt].std_type) {
3539 case STD_T_SINT:
3540 data = stktable_data_cast(ptr, std_t_sint);
3541 break;
3542 case STD_T_UINT:
3543 data = stktable_data_cast(ptr, std_t_uint);
3544 break;
3545 case STD_T_ULL:
3546 data = stktable_data_cast(ptr, std_t_ull);
3547 break;
3548 case STD_T_FRQP:
3549 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3550 appctx->ctx.table.proxy->table.data_arg[dt].u);
3551 break;
3552 }
3553
3554 /* skip the entry if the data does not match the test and the value */
3555 if ((data < appctx->ctx.table.value &&
3556 (appctx->ctx.table.data_op == STD_OP_EQ ||
3557 appctx->ctx.table.data_op == STD_OP_GT ||
3558 appctx->ctx.table.data_op == STD_OP_GE)) ||
3559 (data == appctx->ctx.table.value &&
3560 (appctx->ctx.table.data_op == STD_OP_NE ||
3561 appctx->ctx.table.data_op == STD_OP_GT ||
3562 appctx->ctx.table.data_op == STD_OP_LT)) ||
3563 (data > appctx->ctx.table.value &&
3564 (appctx->ctx.table.data_op == STD_OP_EQ ||
3565 appctx->ctx.table.data_op == STD_OP_LT ||
3566 appctx->ctx.table.data_op == STD_OP_LE)))
3567 skip_entry = 1;
3568 }
3569
3570 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003571 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003572 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003573 return 0;
3574 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003575
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003576 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003577
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003578 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003579 appctx->ctx.table.entry->ref_cnt--;
3580
3581 eb = ebmb_next(&appctx->ctx.table.entry->key);
3582 if (eb) {
3583 struct stksess *old = appctx->ctx.table.entry;
3584 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3585 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003586 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003587 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003588 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003589 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003590 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003591 break;
3592 }
3593
3594
3595 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003596 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003598 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3599
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003600 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003601
3602 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3603 appctx->st2 = STAT_ST_INFO;
3604 break;
3605
3606 case STAT_ST_END:
3607 appctx->st2 = STAT_ST_FIN;
3608 break;
3609 }
3610 }
3611 return 1;
3612}
3613
3614static void cli_release_show_table(struct appctx *appctx)
3615{
3616 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003617 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003618 }
3619}
3620
3621/* register cli keywords */
3622static struct cli_kw_list cli_kws = {{ },{
3623 { { "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 },
3624 { { "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 },
3625 { { "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 },
3626 {{},}
3627}};
3628
3629
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003630static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003631 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003632 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003633 { "sc-set-gpt0", parse_set_gpt0, 1 },
3634 { /* END */ }
3635}};
3636
Willy Tarreau620408f2016-10-21 16:37:51 +02003637static struct action_kw_list tcp_sess_kws = { { }, {
3638 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003639 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003640 { "sc-set-gpt0", parse_set_gpt0, 1 },
3641 { /* END */ }
3642}};
3643
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003644static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003645 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003646 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003647 { "sc-set-gpt0", parse_set_gpt0, 1 },
3648 { /* END */ }
3649}};
3650
3651static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003652 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003653 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003654 { "sc-set-gpt0", parse_set_gpt0, 1 },
3655 { /* END */ }
3656}};
3657
3658static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003659 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003660 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003661 { "sc-set-gpt0", parse_set_gpt0, 1 },
3662 { /* END */ }
3663}};
3664
3665static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003666 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003667 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003668 { "sc-set-gpt0", parse_set_gpt0, 1 },
3669 { /* END */ }
3670}};
3671
Willy Tarreau7d562212016-11-25 16:10:05 +01003672///* Note: must not be declared <const> as its list will be overwritten.
3673// * Please take care of keeping this list alphabetically sorted.
3674// */
3675//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3676// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3677// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3678// { /* END */ },
3679//}};
3680/* Note: must not be declared <const> as its list will be overwritten.
3681 * Please take care of keeping this list alphabetically sorted.
3682 */
3683static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3684 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3685 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3686 { "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 +01003687 { "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 +01003688 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3689 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3690 { "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 +01003691 { "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 +01003692 { "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 +01003693 { "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 +01003694 { "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 +01003695 { "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 +01003696 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3697 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3698 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3699 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3700 { "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 +01003701 { "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 +01003702 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3703 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3704 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3705 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3706 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3707 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3708 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3709 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3710 { "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 +01003711 { "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 +01003712 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3713 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3714 { "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 +01003715 { "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 +01003716 { "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 +01003717 { "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 +01003718 { "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 +01003719 { "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 +01003720 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3721 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3722 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3723 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3724 { "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 +01003725 { "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 +01003726 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3727 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3728 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3729 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3730 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3731 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3732 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3733 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3734 { "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 +01003735 { "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 +01003736 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3737 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3738 { "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 +01003739 { "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 +01003740 { "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 +01003741 { "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 +01003742 { "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 +01003743 { "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 +01003744 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3745 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3746 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3747 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3748 { "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 +01003749 { "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 +01003750 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3751 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3752 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3753 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3754 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3755 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3756 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3757 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3758 { "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 +01003759 { "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 +01003760 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3761 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3762 { "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 +01003763 { "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 +01003764 { "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 +01003765 { "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 +01003766 { "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 +01003767 { "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 +01003768 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3769 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3770 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3771 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3772 { "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 +01003773 { "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 +01003774 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3775 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3776 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3777 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3778 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3779 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3780 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3781 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3782 { "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 +01003783 { "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 +01003784 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3785 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3786 { "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 +01003787 { "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 +01003788 { "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 +01003789 { "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 +01003790 { "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 +01003791 { "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 +01003792 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3793 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3794 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3795 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3796 { "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 +01003797 { "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 +01003798 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3799 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3800 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3801 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3802 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3803 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3804 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3805 { /* END */ },
3806}};
3807
3808
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003809/* Note: must not be declared <const> as its list will be overwritten */
3810static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003811 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3812 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3813 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3814 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3815 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3816 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3817 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3818 { "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 +01003819 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003820 { "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 +01003821 { "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 +02003822 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3823 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3824 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3825 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3826 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3827 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3828 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3829 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3830 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3831 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003832 { /* END */ },
3833}};
3834
3835__attribute__((constructor))
3836static void __stick_table_init(void)
3837{
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003838 /* register som action keywords. */
3839 tcp_req_conn_keywords_register(&tcp_conn_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +02003840 tcp_req_sess_keywords_register(&tcp_sess_kws);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003841 tcp_req_cont_keywords_register(&tcp_req_kws);
3842 tcp_res_cont_keywords_register(&tcp_res_kws);
3843 http_req_keywords_register(&http_req_kws);
3844 http_res_keywords_register(&http_res_kws);
3845
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003846 /* register sample fetch and format conversion keywords */
Willy Tarreau7d562212016-11-25 16:10:05 +01003847 sample_register_fetches(&smp_fetch_keywords);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003848 sample_register_convs(&sample_conv_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003849 cli_register_kw(&cli_kws);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003850}