blob: e24ef65b6ffd754f99dc6473e07279ad5c3e547d [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>
Willy Tarreau0108d902018-11-25 19:14:37 +010018#include <common/initcall.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010019#include <common/memory.h>
20#include <common/mini-clist.h>
21#include <common/standard.h>
22#include <common/time.h>
23
24#include <ebmbtree.h>
25#include <ebsttree.h>
26
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010027#include <types/cli.h>
Willy Tarreau39713102016-11-25 15:49:32 +010028#include <types/global.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010029#include <types/stats.h>
30
Willy Tarreaud9f316a2014-07-10 14:03:38 +020031#include <proto/arg.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010032#include <proto/cli.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020033#include <proto/http_rules.h>
Andjelko Iharosc3680ec2017-07-20 16:49:14 +020034#include <proto/log.h>
Thierry FOURNIER236657b2015-08-19 08:25:14 +020035#include <proto/proto_http.h>
Willy Tarreau7d562212016-11-25 16:10:05 +010036#include <proto/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010037#include <proto/proxy.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020038#include <proto/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020039#include <proto/stream.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010040#include <proto/stream_interface.h>
Willy Tarreau68129b92010-06-06 16:06:52 +020041#include <proto/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010042#include <proto/task.h>
Emeric Brun32da3c42010-09-23 18:39:19 +020043#include <proto/peers.h>
Willy Tarreau39713102016-11-25 15:49:32 +010044#include <proto/tcp_rules.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010045
Willy Tarreau12785782012-04-27 21:37:17 +020046/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020047static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020048
Olivier Houchard52dabbc2018-11-14 17:54:36 +010049#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +010050/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020051 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
52 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010053 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020054void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010055{
56 t->current--;
Olivier Houchard52dabbc2018-11-14 17:54:36 +010057 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
Emeric Brun3bd697e2010-01-04 15:23:48 +010058}
59
60/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020061 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
62 * in table <t>.
63 * This function locks the table
64 */
65void stksess_free(struct stktable *t, struct stksess *ts)
66{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010067 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020068 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010069 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020070}
71
72/*
Willy Tarreauf6efda12010-08-03 20:34:06 +020073 * Kill an stksess (only if its ref_cnt is zero).
74 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020075int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +020076{
77 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +020078 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +020079
80 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +020081 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +020082 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +020083 __stksess_free(t, ts);
84 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +020085}
86
87/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020088 * Decrease the refcount if decrefcnt is not 0.
89 * and try to kill the stksess
90 * This function locks the table
91 */
92int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
93{
94 int ret;
95
Christopher Faulet2a944ee2017-11-07 10:42:54 +010096 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020097 if (decrefcnt)
98 ts->ref_cnt--;
99 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100100 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200101
102 return ret;
103}
104
105/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200106 * Initialize or update the key in the sticky session <ts> present in table <t>
107 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100108 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200109void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100110{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200111 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200112 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100113 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200114 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
115 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100116 }
117}
118
119
120/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200121 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
122 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100123 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200124static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100125{
Willy Tarreau393379c2010-06-06 12:11:37 +0200126 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200127 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200128 ts->key.node.leaf_p = NULL;
129 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200130 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200131 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100132 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100133 return ts;
134}
135
136/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200137 * Trash oldest <to_batch> sticky sessions from table <t>
138 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100139 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200140int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100141{
142 struct stksess *ts;
143 struct eb32_node *eb;
144 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200145 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100146
147 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
148
149 while (batched < to_batch) {
150
151 if (unlikely(!eb)) {
152 /* we might have reached the end of the tree, typically because
153 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200154 * half. Let's loop back to the beginning of the tree now if we
155 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100156 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200157 if (looped)
158 break;
159 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100160 eb = eb32_first(&t->exps);
161 if (likely(!eb))
162 break;
163 }
164
165 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200166 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100167 eb = eb32_next(eb);
168
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200169 /* don't delete an entry which is currently referenced */
170 if (ts->ref_cnt)
171 continue;
172
Willy Tarreau86257dc2010-06-06 12:57:10 +0200173 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100174
Willy Tarreau86257dc2010-06-06 12:57:10 +0200175 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100176 if (!tick_isset(ts->expire))
177 continue;
178
Willy Tarreau86257dc2010-06-06 12:57:10 +0200179 ts->exp.key = ts->expire;
180 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100181
Willy Tarreau86257dc2010-06-06 12:57:10 +0200182 if (!eb || eb->key > ts->exp.key)
183 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184
185 continue;
186 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100187
Willy Tarreauaea940e2010-06-06 11:56:36 +0200188 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200189 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200190 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200191 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100192 batched++;
193 }
194
195 return batched;
196}
197
198/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200199 * Trash oldest <to_batch> sticky sessions from table <t>
200 * Returns number of trashed sticky sessions.
201 * This function locks the table
202 */
203int stktable_trash_oldest(struct stktable *t, int to_batch)
204{
205 int ret;
206
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100207 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200208 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100209 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200210
211 return ret;
212}
213/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200214 * Allocate and initialise a new sticky session.
215 * The new sticky session is returned or NULL in case of lack of memory.
216 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200217 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
218 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200220struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100221{
222 struct stksess *ts;
223
224 if (unlikely(t->current == t->size)) {
225 if ( t->nopurge )
226 return NULL;
227
Emeric Brun819fc6f2017-06-13 19:37:32 +0200228 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100229 return NULL;
230 }
231
Willy Tarreaubafbe012017-11-24 17:34:44 +0100232 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100233 if (ts) {
234 t->current++;
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100235 ts = (void *)ts + round_ptr_size(t->data_size);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200236 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200237 if (key)
238 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100239 }
240
241 return ts;
242}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200243/*
244 * Allocate and initialise a new sticky session.
245 * The new sticky session is returned or NULL in case of lack of memory.
246 * Sticky sessions should only be allocated this way, and must be freed using
247 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
248 * is not NULL, it is assigned to the new session.
249 * This function locks the table
250 */
251struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
252{
253 struct stksess *ts;
254
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100255 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200256 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100257 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200258
259 return ts;
260}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100261
262/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200263 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200264 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200266struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100267{
268 struct ebmb_node *eb;
269
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200270 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200271 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 +0100272 else
273 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
274
275 if (unlikely(!eb)) {
276 /* no session found */
277 return NULL;
278 }
279
Willy Tarreau86257dc2010-06-06 12:57:10 +0200280 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100281}
282
Emeric Brun819fc6f2017-06-13 19:37:32 +0200283/*
284 * Looks in table <t> for a sticky session matching key <key>.
285 * Returns pointer on requested sticky session or NULL if none was found.
286 * The refcount of the found entry is increased and this function
287 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200288 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200289struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200290{
291 struct stksess *ts;
292
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100293 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200294 ts = __stktable_lookup_key(t, key);
295 if (ts)
296 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100297 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200298
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200299 return ts;
300}
301
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200302/*
303 * Looks in table <t> for a sticky session with same key as <ts>.
304 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100305 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200306struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100307{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100308 struct ebmb_node *eb;
309
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200310 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200311 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100312 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200313 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100314
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200315 if (unlikely(!eb))
316 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100317
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200318 return ebmb_entry(eb, struct stksess, key);
319}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100320
Emeric Brun819fc6f2017-06-13 19:37:32 +0200321/*
322 * Looks in table <t> for a sticky session with same key as <ts>.
323 * Returns pointer on requested sticky session or NULL if none was found.
324 * The refcount of the found entry is increased and this function
325 * is protected using the table lock
326 */
327struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
328{
329 struct stksess *lts;
330
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100331 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200332 lts = __stktable_lookup(t, ts);
333 if (lts)
334 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100335 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200336
337 return lts;
338}
339
Willy Tarreaucb183642010-06-06 17:58:34 +0200340/* Update the expiration timer for <ts> but do not touch its expiration node.
341 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200342 * The node will be also inserted into the update tree if needed, at a position
343 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200344 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200345void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200346{
Emeric Brun85e77c72010-09-23 18:16:52 +0200347 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200348 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200349 if (t->expire) {
350 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
351 task_queue(t->exp_task);
352 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200353
Emeric Brun819fc6f2017-06-13 19:37:32 +0200354 /* If sync is enabled */
355 if (t->sync_task) {
356 if (local) {
357 /* If this entry is not in the tree
358 or not scheduled for at least one peer */
359 if (!ts->upd.node.leaf_p
360 || (int)(t->commitupdate - ts->upd.key) >= 0
361 || (int)(ts->upd.key - t->localupdate) >= 0) {
362 ts->upd.key = ++t->update;
363 t->localupdate = t->update;
364 eb32_delete(&ts->upd);
365 eb = eb32_insert(&t->updates, &ts->upd);
366 if (eb != &ts->upd) {
367 eb32_delete(eb);
368 eb32_insert(&t->updates, &ts->upd);
369 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200370 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200371 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200372 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200373 else {
374 /* If this entry is not in the tree */
375 if (!ts->upd.node.leaf_p) {
376 ts->upd.key= (++t->update)+(2147483648U);
377 eb = eb32_insert(&t->updates, &ts->upd);
378 if (eb != &ts->upd) {
379 eb32_delete(eb);
380 eb32_insert(&t->updates, &ts->upd);
381 }
382 }
383 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200384 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200385}
386
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200387/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200388 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200389 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200390 * The node will be also inserted into the update tree if needed, at a position
391 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200392 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200393void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
394{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100395 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200396 __stktable_touch_with_exp(t, ts, 0, ts->expire);
397 if (decrefcnt)
398 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100399 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200400}
401
402/* Update the expiration timer for <ts> but do not touch its expiration node.
403 * The table's expiration timer is updated using the date of expiration coming from
404 * <t> stick-table configuration.
405 * The node will be also inserted into the update tree if needed, at a position
406 * considering the update was made locally
407 */
408void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200409{
410 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
411
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100412 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200413 __stktable_touch_with_exp(t, ts, 1, expire);
414 if (decrefcnt)
415 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100416 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417}
Willy Tarreau43e90352018-06-27 06:25:57 +0200418/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
419static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200420{
Willy Tarreau43e90352018-06-27 06:25:57 +0200421 if (!ts)
422 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100423 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200424 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100425 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200426}
427
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200428/* Insert new sticky session <ts> in the table. It is assumed that it does not
429 * yet exist (the caller must check this). The table's timeout is updated if it
430 * is set. <ts> is returned.
431 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200432void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200433{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100434
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200435 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200436 ts->exp.key = ts->expire;
437 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200438 if (t->expire) {
439 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
440 task_queue(t->exp_task);
441 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200442}
443
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200444/* Returns a valid or initialized stksess for the specified stktable_key in the
445 * specified table, or NULL if the key was NULL, or if no entry was found nor
446 * could be created. The entry's expiration is updated.
447 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200448struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200449{
450 struct stksess *ts;
451
452 if (!key)
453 return NULL;
454
Emeric Brun819fc6f2017-06-13 19:37:32 +0200455 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200456 if (ts == NULL) {
457 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200458 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200459 if (!ts)
460 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200461 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200462 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200463 return ts;
464}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200465/* Returns a valid or initialized stksess for the specified stktable_key in the
466 * specified table, or NULL if the key was NULL, or if no entry was found nor
467 * could be created. The entry's expiration is updated.
468 * This function locks the table, and the refcount of the entry is increased.
469 */
470struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
471{
472 struct stksess *ts;
473
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100474 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200475 ts = __stktable_get_entry(table, key);
476 if (ts)
477 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100478 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200479
480 return ts;
481}
482
483/* Lookup for an entry with the same key and store the submitted
484 * stksess if not found.
485 */
486struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
487{
488 struct stksess *ts;
489
490 ts = __stktable_lookup(table, nts);
491 if (ts == NULL) {
492 ts = nts;
493 __stktable_store(table, ts);
494 }
495 return ts;
496}
497
498/* Lookup for an entry with the same key and store the submitted
499 * stksess if not found.
500 * This function locks the table, and the refcount of the entry is increased.
501 */
502struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
503{
504 struct stksess *ts;
505
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100506 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200507 ts = __stktable_set_entry(table, nts);
508 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100509 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200510
Emeric Brun819fc6f2017-06-13 19:37:32 +0200511 return ts;
512}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100513/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200514 * Trash expired sticky sessions from table <t>. The next expiration date is
515 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100516 */
517static int stktable_trash_expired(struct stktable *t)
518{
519 struct stksess *ts;
520 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200521 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100522
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100523 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100524 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
525
526 while (1) {
527 if (unlikely(!eb)) {
528 /* we might have reached the end of the tree, typically because
529 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200530 * half. Let's loop back to the beginning of the tree now if we
531 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100532 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200533 if (looped)
534 break;
535 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100536 eb = eb32_first(&t->exps);
537 if (likely(!eb))
538 break;
539 }
540
541 if (likely(tick_is_lt(now_ms, eb->key))) {
542 /* timer not expired yet, revisit it later */
543 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100544 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100545 }
546
547 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200548 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100549 eb = eb32_next(eb);
550
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200551 /* don't delete an entry which is currently referenced */
552 if (ts->ref_cnt)
553 continue;
554
Willy Tarreau86257dc2010-06-06 12:57:10 +0200555 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100556
557 if (!tick_is_expired(ts->expire, now_ms)) {
558 if (!tick_isset(ts->expire))
559 continue;
560
Willy Tarreau86257dc2010-06-06 12:57:10 +0200561 ts->exp.key = ts->expire;
562 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100563
Willy Tarreau86257dc2010-06-06 12:57:10 +0200564 if (!eb || eb->key > ts->exp.key)
565 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100566 continue;
567 }
568
569 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200570 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200571 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200572 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100573 }
574
575 /* We have found no task to expire in any tree */
576 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100577out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100578 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100579 return t->exp_next;
580}
581
582/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200583 * Task processing function to trash expired sticky sessions. A pointer to the
584 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100585 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200586static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100587{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200588 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100589
590 task->expire = stktable_trash_expired(t);
591 return task;
592}
593
Willy Tarreauaea940e2010-06-06 11:56:36 +0200594/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100595int stktable_init(struct stktable *t)
596{
597 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200598 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100600 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100601 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100602
Olivier Houchard52dabbc2018-11-14 17:54:36 +0100603 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 +0100604
605 t->exp_next = TICK_ETERNITY;
606 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200607 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200608 if (!t->exp_task)
609 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100610 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100611 t->exp_task->context = (void *)t;
612 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200613 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200614 peers_register_table(t->peers.p, t);
615 }
616
Emeric Brun3bd697e2010-01-04 15:23:48 +0100617 return t->pool != NULL;
618 }
619 return 1;
620}
621
622/*
623 * Configuration keywords of known table types
624 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200625struct stktable_type stktable_types[SMP_TYPES] = {
626 [SMP_T_SINT] = { "integer", 0, 4 },
627 [SMP_T_IPV4] = { "ip", 0, 4 },
628 [SMP_T_IPV6] = { "ipv6", 0, 16 },
629 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
630 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
631};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100632
633/*
634 * Parse table type configuration.
635 * Returns 0 on successful parsing, else 1.
636 * <myidx> is set at next configuration <args> index.
637 */
638int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
639{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200640 for (*type = 0; *type < SMP_TYPES; (*type)++) {
641 if (!stktable_types[*type].kw)
642 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
644 continue;
645
646 *key_size = stktable_types[*type].default_size;
647 (*myidx)++;
648
Willy Tarreauaea940e2010-06-06 11:56:36 +0200649 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100650 if (strcmp("len", args[*myidx]) == 0) {
651 (*myidx)++;
652 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200653 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200655 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200656 /* null terminated string needs +1 for '\0'. */
657 (*key_size)++;
658 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100659 (*myidx)++;
660 }
661 }
662 return 0;
663 }
664 return 1;
665}
666
Willy Tarreau8fed9032014-07-03 17:02:46 +0200667/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200668 * Note that the sample *is* modified and that the returned key may point
669 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200670 * Returns NULL if the sample could not be converted (eg: no matching type),
671 * otherwise a pointer to the static stktable_key filled with what is needed
672 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200673 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200674struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200675{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200676 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200677 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200678 return NULL;
679
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200680 /* Fill static_table_key. */
681 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200682
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200683 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200684 static_table_key.key = &smp->data.u.ipv4;
685 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200686 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200687
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200688 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200689 static_table_key.key = &smp->data.u.ipv6;
690 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200691 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200692
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200693 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200694 /* The stick table require a 32bit unsigned int, "sint" is a
695 * signed 64 it, so we can convert it inplace.
696 */
697 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200698 static_table_key.key = &smp->data.u.sint;
699 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200700 break;
701
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200702 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200703 if (!smp_make_safe(smp))
704 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200705 static_table_key.key = smp->data.u.str.area;
706 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200707 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200708
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200709 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200710 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200711 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200712 if (!smp_make_rw(smp))
713 return NULL;
714
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200715 if (smp->data.u.str.size < t->key_size)
716 if (!smp_dup(smp))
717 return NULL;
718 if (smp->data.u.str.size < t->key_size)
719 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200720 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
721 t->key_size - smp->data.u.str.data);
722 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200723 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200724 static_table_key.key = smp->data.u.str.area;
725 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200726 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200727
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200728 default: /* impossible case. */
729 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200730 }
731
Christopher Fauletca20d022017-08-29 15:30:31 +0200732 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200733}
734
735/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200736 * Process a fetch + format conversion as defined by the sample expression <expr>
737 * on request or response considering the <opt> parameter. Returns either NULL if
738 * no key could be extracted, or a pointer to the converted result stored in
739 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
740 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200741 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
742 * without SMP_OPT_FINAL). The output will be usable like this :
743 *
744 * return MAY_CHANGE FINAL Meaning for the sample
745 * NULL 0 * Not present and will never be (eg: header)
746 * NULL 1 0 Not present or unstable, could change (eg: req_len)
747 * NULL 1 1 Not present, will not change anymore
748 * smp 0 * Present and will not change (eg: header)
749 * smp 1 0 not possible
750 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200751 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200752struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200753 unsigned int opt, struct sample_expr *expr, struct sample *smp)
754{
755 if (smp)
756 memset(smp, 0, sizeof(*smp));
757
Willy Tarreau192252e2015-04-04 01:47:55 +0200758 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200759 if (!smp)
760 return NULL;
761
762 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
763 return NULL; /* we can only use stable samples */
764
765 return smp_to_stkey(smp, t);
766}
767
768/*
Willy Tarreau12785782012-04-27 21:37:17 +0200769 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200770 * type <table_type>, otherwise zero. Used in configuration check.
771 */
Willy Tarreau12785782012-04-27 21:37:17 +0200772int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200773{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100774 int out_type;
775
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200776 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200777 return 0;
778
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100779 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200780
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200781 /* Convert sample. */
782 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100783 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200784
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200785 return 1;
786}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100787
Willy Tarreauedee1d62014-07-15 16:44:27 +0200788/* Extra data types processing : after the last one, some room may remain
789 * before STKTABLE_DATA_TYPES that may be used to register extra data types
790 * at run time.
791 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200792struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200793 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200794 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200795 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200796 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200797 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
798 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
799 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
800 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
801 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
802 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
803 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
804 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
805 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
806 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
807 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
808 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
809 [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 +0100810 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
811 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +0200812};
813
Willy Tarreauedee1d62014-07-15 16:44:27 +0200814/* Registers stick-table extra data type with index <idx>, name <name>, type
815 * <std_type> and arg type <arg_type>. If the index is negative, the next free
816 * index is automatically allocated. The allocated index is returned, or -1 if
817 * no free index was found or <name> was already registered. The <name> is used
818 * directly as a pointer, so if it's not stable, the caller must allocate it.
819 */
820int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
821{
822 if (idx < 0) {
823 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
824 if (!stktable_data_types[idx].name)
825 break;
826
827 if (strcmp(stktable_data_types[idx].name, name) == 0)
828 return -1;
829 }
830 }
831
832 if (idx >= STKTABLE_DATA_TYPES)
833 return -1;
834
835 if (stktable_data_types[idx].name != NULL)
836 return -1;
837
838 stktable_data_types[idx].name = name;
839 stktable_data_types[idx].std_type = std_type;
840 stktable_data_types[idx].arg_type = arg_type;
841 return idx;
842}
843
Willy Tarreau08d5f982010-06-06 13:34:54 +0200844/*
845 * Returns the data type number for the stktable_data_type whose name is <name>,
846 * or <0 if not found.
847 */
848int stktable_get_data_type(char *name)
849{
850 int type;
851
852 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +0200853 if (!stktable_data_types[type].name)
854 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +0200855 if (strcmp(name, stktable_data_types[type].name) == 0)
856 return type;
857 }
858 return -1;
859}
860
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200861/* Casts sample <smp> to the type of the table specified in arg(0), and looks
862 * it up into this table. Returns true if found, false otherwise. The input
863 * type is STR so that input samples are converted to string (since all types
864 * can be converted to strings), then the function casts the string again into
865 * the table's type. This is a double conversion, but in the future we might
866 * support automatic input types to perform the cast on the fly.
867 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200868static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200869{
870 struct stktable *t;
871 struct stktable_key *key;
872 struct stksess *ts;
873
874 t = &arg_p[0].data.prx->table;
875
876 key = smp_to_stkey(smp, t);
877 if (!key)
878 return 0;
879
880 ts = stktable_lookup_key(t, key);
881
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200882 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200883 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200884 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +0200885 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200886 return 1;
887}
888
889/* Casts sample <smp> to the type of the table specified in arg(0), and looks
890 * it up into this table. Returns the data rate received from clients in bytes/s
891 * if the key is present in the table, otherwise zero, so that comparisons can
892 * be easily performed. If the inspected parameter is not stored in the table,
893 * <not found> is returned.
894 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200895static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200896{
897 struct stktable *t;
898 struct stktable_key *key;
899 struct stksess *ts;
900 void *ptr;
901
902 t = &arg_p[0].data.prx->table;
903
904 key = smp_to_stkey(smp, t);
905 if (!key)
906 return 0;
907
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200908 ts = stktable_lookup_key(t, key);
909
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200910 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200911 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200912 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200913
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200914 if (!ts) /* key not present */
915 return 1;
916
917 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400918 if (ptr)
919 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
920 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200921
Daniel Corbett3e60b112018-05-27 09:47:12 -0400922 stktable_release(t, ts);
923 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200924}
925
926/* Casts sample <smp> to the type of the table specified in arg(0), and looks
927 * it up into this table. Returns the cumulated number of connections for the key
928 * if the key is present in the table, otherwise zero, so that comparisons can
929 * be easily performed. If the inspected parameter is not stored in the table,
930 * <not found> is returned.
931 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200932static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200933{
934 struct stktable *t;
935 struct stktable_key *key;
936 struct stksess *ts;
937 void *ptr;
938
939 t = &arg_p[0].data.prx->table;
940
941 key = smp_to_stkey(smp, t);
942 if (!key)
943 return 0;
944
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200945 ts = stktable_lookup_key(t, key);
946
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200947 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200948 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200949 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200950
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200951 if (!ts) /* key not present */
952 return 1;
953
954 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400955 if (ptr)
956 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200957
Daniel Corbett3e60b112018-05-27 09:47:12 -0400958 stktable_release(t, ts);
959 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200960}
961
962/* Casts sample <smp> to the type of the table specified in arg(0), and looks
963 * it up into this table. Returns the number of concurrent connections for the
964 * key if the key is present in the table, otherwise zero, so that comparisons
965 * can be easily performed. If the inspected parameter is not stored in the
966 * table, <not found> is returned.
967 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200968static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200969{
970 struct stktable *t;
971 struct stktable_key *key;
972 struct stksess *ts;
973 void *ptr;
974
975 t = &arg_p[0].data.prx->table;
976
977 key = smp_to_stkey(smp, t);
978 if (!key)
979 return 0;
980
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200981 ts = stktable_lookup_key(t, key);
982
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200983 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200984 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200985 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200986
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200987 if (!ts) /* key not present */
988 return 1;
989
990 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400991 if (ptr)
992 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200993
Daniel Corbett3e60b112018-05-27 09:47:12 -0400994 stktable_release(t, ts);
995 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200996}
997
998/* Casts sample <smp> to the type of the table specified in arg(0), and looks
999 * it up into this table. Returns the rate of incoming connections from the key
1000 * if the key is present in the table, otherwise zero, so that comparisons can
1001 * be easily performed. If the inspected parameter is not stored in the table,
1002 * <not found> is returned.
1003 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001004static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001005{
1006 struct stktable *t;
1007 struct stktable_key *key;
1008 struct stksess *ts;
1009 void *ptr;
1010
1011 t = &arg_p[0].data.prx->table;
1012
1013 key = smp_to_stkey(smp, t);
1014 if (!key)
1015 return 0;
1016
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001017 ts = stktable_lookup_key(t, key);
1018
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001019 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001020 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001021 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001022
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001023 if (!ts) /* key not present */
1024 return 1;
1025
1026 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001027 if (ptr)
1028 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1029 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001030
Daniel Corbett3e60b112018-05-27 09:47:12 -04001031 stktable_release(t, ts);
1032 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001033}
1034
1035/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1036 * it up into this table. Returns the data rate sent to clients in bytes/s
1037 * if the key is present in the table, otherwise zero, so that comparisons can
1038 * be easily performed. If the inspected parameter is not stored in the table,
1039 * <not found> is returned.
1040 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001041static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001042{
1043 struct stktable *t;
1044 struct stktable_key *key;
1045 struct stksess *ts;
1046 void *ptr;
1047
1048 t = &arg_p[0].data.prx->table;
1049
1050 key = smp_to_stkey(smp, t);
1051 if (!key)
1052 return 0;
1053
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001054 ts = stktable_lookup_key(t, key);
1055
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001056 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001057 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001058 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001059
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001060 if (!ts) /* key not present */
1061 return 1;
1062
1063 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001064 if (ptr)
1065 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1066 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001067
Daniel Corbett3e60b112018-05-27 09:47:12 -04001068 stktable_release(t, ts);
1069 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001070}
1071
1072/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001073 * it up into this table. Returns the value of the GPT0 tag for the key
1074 * if the key is present in the table, otherwise false, so that comparisons can
1075 * be easily performed. If the inspected parameter is not stored in the table,
1076 * <not found> is returned.
1077 */
1078static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1079{
1080 struct stktable *t;
1081 struct stktable_key *key;
1082 struct stksess *ts;
1083 void *ptr;
1084
1085 t = &arg_p[0].data.prx->table;
1086
1087 key = smp_to_stkey(smp, t);
1088 if (!key)
1089 return 0;
1090
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001091 ts = stktable_lookup_key(t, key);
1092
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001093 smp->flags = SMP_F_VOL_TEST;
1094 smp->data.type = SMP_T_SINT;
1095 smp->data.u.sint = 0;
1096
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001097 if (!ts) /* key not present */
1098 return 1;
1099
1100 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001101 if (ptr)
1102 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001103
Daniel Corbett3e60b112018-05-27 09:47:12 -04001104 stktable_release(t, ts);
1105 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001106}
1107
1108/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001109 * it up into this table. Returns the value of the GPC0 counter for the key
1110 * if the key is present in the table, otherwise zero, so that comparisons can
1111 * be easily performed. If the inspected parameter is not stored in the table,
1112 * <not found> is returned.
1113 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001114static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001115{
1116 struct stktable *t;
1117 struct stktable_key *key;
1118 struct stksess *ts;
1119 void *ptr;
1120
1121 t = &arg_p[0].data.prx->table;
1122
1123 key = smp_to_stkey(smp, t);
1124 if (!key)
1125 return 0;
1126
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001127 ts = stktable_lookup_key(t, key);
1128
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001129 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001130 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001131 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001132
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001133 if (!ts) /* key not present */
1134 return 1;
1135
1136 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001137 if (ptr)
1138 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001139
Daniel Corbett3e60b112018-05-27 09:47:12 -04001140 stktable_release(t, ts);
1141 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001142}
1143
1144/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1145 * it up into this table. Returns the event rate of the GPC0 counter for the key
1146 * if the key is present in the table, otherwise zero, so that comparisons can
1147 * be easily performed. If the inspected parameter is not stored in the table,
1148 * <not found> is returned.
1149 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001150static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001151{
1152 struct stktable *t;
1153 struct stktable_key *key;
1154 struct stksess *ts;
1155 void *ptr;
1156
1157 t = &arg_p[0].data.prx->table;
1158
1159 key = smp_to_stkey(smp, t);
1160 if (!key)
1161 return 0;
1162
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001163 ts = stktable_lookup_key(t, key);
1164
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001165 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001166 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001167 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001168
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001169 if (!ts) /* key not present */
1170 return 1;
1171
1172 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001173 if (ptr)
1174 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1175 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001176
Daniel Corbett3e60b112018-05-27 09:47:12 -04001177 stktable_release(t, ts);
1178 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001179}
1180
1181/* 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 +01001182 * it up into this table. Returns the value of the GPC1 counter for the key
1183 * if the key is present in the table, otherwise zero, so that comparisons can
1184 * be easily performed. If the inspected parameter is not stored in the table,
1185 * <not found> is returned.
1186 */
1187static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1188{
1189 struct stktable *t;
1190 struct stktable_key *key;
1191 struct stksess *ts;
1192 void *ptr;
1193
1194 t = &arg_p[0].data.prx->table;
1195
1196 key = smp_to_stkey(smp, t);
1197 if (!key)
1198 return 0;
1199
1200 ts = stktable_lookup_key(t, key);
1201
1202 smp->flags = SMP_F_VOL_TEST;
1203 smp->data.type = SMP_T_SINT;
1204 smp->data.u.sint = 0;
1205
1206 if (!ts) /* key not present */
1207 return 1;
1208
1209 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001210 if (ptr)
1211 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001212
Daniel Corbett3e60b112018-05-27 09:47:12 -04001213 stktable_release(t, ts);
1214 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001215}
1216
1217/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1218 * it up into this table. Returns the event rate of the GPC1 counter for the key
1219 * if the key is present in the table, otherwise zero, so that comparisons can
1220 * be easily performed. If the inspected parameter is not stored in the table,
1221 * <not found> is returned.
1222 */
1223static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1224{
1225 struct stktable *t;
1226 struct stktable_key *key;
1227 struct stksess *ts;
1228 void *ptr;
1229
1230 t = &arg_p[0].data.prx->table;
1231
1232 key = smp_to_stkey(smp, t);
1233 if (!key)
1234 return 0;
1235
1236 ts = stktable_lookup_key(t, key);
1237
1238 smp->flags = SMP_F_VOL_TEST;
1239 smp->data.type = SMP_T_SINT;
1240 smp->data.u.sint = 0;
1241
1242 if (!ts) /* key not present */
1243 return 1;
1244
1245 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001246 if (ptr)
1247 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1248 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001249
Daniel Corbett3e60b112018-05-27 09:47:12 -04001250 stktable_release(t, ts);
1251 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001252}
1253
1254/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001255 * it up into this table. Returns the cumulated number of HTTP request errors
1256 * for the key if the key is present in the table, otherwise zero, so that
1257 * comparisons can be easily performed. If the inspected parameter is not stored
1258 * in the table, <not found> is returned.
1259 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001260static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001261{
1262 struct stktable *t;
1263 struct stktable_key *key;
1264 struct stksess *ts;
1265 void *ptr;
1266
1267 t = &arg_p[0].data.prx->table;
1268
1269 key = smp_to_stkey(smp, t);
1270 if (!key)
1271 return 0;
1272
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001273 ts = stktable_lookup_key(t, key);
1274
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001276 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001277 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001278
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001279 if (!ts) /* key not present */
1280 return 1;
1281
1282 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001283 if (ptr)
1284 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001285
Daniel Corbett3e60b112018-05-27 09:47:12 -04001286 stktable_release(t, ts);
1287 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001288}
1289
1290/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1291 * it up into this table. Returns the HTTP request error rate the key
1292 * if the key is present in the table, otherwise zero, so that comparisons can
1293 * be easily performed. If the inspected parameter is not stored in the table,
1294 * <not found> is returned.
1295 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001296static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001297{
1298 struct stktable *t;
1299 struct stktable_key *key;
1300 struct stksess *ts;
1301 void *ptr;
1302
1303 t = &arg_p[0].data.prx->table;
1304
1305 key = smp_to_stkey(smp, t);
1306 if (!key)
1307 return 0;
1308
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001309 ts = stktable_lookup_key(t, key);
1310
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001312 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001313 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001314
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315 if (!ts) /* key not present */
1316 return 1;
1317
1318 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001319 if (ptr)
1320 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1321 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001322
Daniel Corbett3e60b112018-05-27 09:47:12 -04001323 stktable_release(t, ts);
1324 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001325}
1326
1327/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1328 * it up into this table. Returns the cumulated number of HTTP request for the
1329 * key if the key is present in the table, otherwise zero, so that comparisons
1330 * can be easily performed. If the inspected parameter is not stored in the
1331 * table, <not found> is returned.
1332 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001333static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001334{
1335 struct stktable *t;
1336 struct stktable_key *key;
1337 struct stksess *ts;
1338 void *ptr;
1339
1340 t = &arg_p[0].data.prx->table;
1341
1342 key = smp_to_stkey(smp, t);
1343 if (!key)
1344 return 0;
1345
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001346 ts = stktable_lookup_key(t, key);
1347
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001348 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001349 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001350 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001352 if (!ts) /* key not present */
1353 return 1;
1354
1355 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001356 if (ptr)
1357 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001358
Daniel Corbett3e60b112018-05-27 09:47:12 -04001359 stktable_release(t, ts);
1360 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001361}
1362
1363/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1364 * it up into this table. Returns the HTTP request rate the key if the key is
1365 * present in the table, otherwise zero, so that comparisons can be easily
1366 * performed. If the inspected parameter is not stored in the table, <not found>
1367 * is returned.
1368 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001369static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001370{
1371 struct stktable *t;
1372 struct stktable_key *key;
1373 struct stksess *ts;
1374 void *ptr;
1375
1376 t = &arg_p[0].data.prx->table;
1377
1378 key = smp_to_stkey(smp, t);
1379 if (!key)
1380 return 0;
1381
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001382 ts = stktable_lookup_key(t, key);
1383
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001385 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001386 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001387
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001388 if (!ts) /* key not present */
1389 return 1;
1390
1391 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001392 if (ptr)
1393 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1394 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001395
Daniel Corbett3e60b112018-05-27 09:47:12 -04001396 stktable_release(t, ts);
1397 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001398}
1399
1400/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1401 * it up into this table. Returns the volume of datareceived from clients in kbytes
1402 * if the key is present in the table, otherwise zero, so that comparisons can
1403 * be easily performed. If the inspected parameter is not stored in the table,
1404 * <not found> is returned.
1405 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001406static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001407{
1408 struct stktable *t;
1409 struct stktable_key *key;
1410 struct stksess *ts;
1411 void *ptr;
1412
1413 t = &arg_p[0].data.prx->table;
1414
1415 key = smp_to_stkey(smp, t);
1416 if (!key)
1417 return 0;
1418
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001419 ts = stktable_lookup_key(t, key);
1420
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001421 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001422 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001423 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001424
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001425 if (!ts) /* key not present */
1426 return 1;
1427
1428 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001429 if (ptr)
1430 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001431
Daniel Corbett3e60b112018-05-27 09:47:12 -04001432 stktable_release(t, ts);
1433 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001434}
1435
1436/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1437 * it up into this table. Returns the volume of data sent to clients in kbytes
1438 * if the key is present in the table, otherwise zero, so that comparisons can
1439 * be easily performed. If the inspected parameter is not stored in the table,
1440 * <not found> is returned.
1441 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001442static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001443{
1444 struct stktable *t;
1445 struct stktable_key *key;
1446 struct stksess *ts;
1447 void *ptr;
1448
1449 t = &arg_p[0].data.prx->table;
1450
1451 key = smp_to_stkey(smp, t);
1452 if (!key)
1453 return 0;
1454
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001455 ts = stktable_lookup_key(t, key);
1456
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001457 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001458 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001459 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001460
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001461 if (!ts) /* key not present */
1462 return 1;
1463
1464 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001465 if (ptr)
1466 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001467
Daniel Corbett3e60b112018-05-27 09:47:12 -04001468 stktable_release(t, ts);
1469 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001470}
1471
1472/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1473 * it up into this table. Returns the server ID associated with the key if the
1474 * key is present in the table, otherwise zero, so that comparisons can be
1475 * easily performed. If the inspected parameter is not stored in the table,
1476 * <not found> is returned.
1477 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001478static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001479{
1480 struct stktable *t;
1481 struct stktable_key *key;
1482 struct stksess *ts;
1483 void *ptr;
1484
1485 t = &arg_p[0].data.prx->table;
1486
1487 key = smp_to_stkey(smp, t);
1488 if (!key)
1489 return 0;
1490
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001491 ts = stktable_lookup_key(t, key);
1492
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001493 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001494 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001495 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001497 if (!ts) /* key not present */
1498 return 1;
1499
1500 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001501 if (ptr)
1502 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001503
Daniel Corbett3e60b112018-05-27 09:47:12 -04001504 stktable_release(t, ts);
1505 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001506}
1507
1508/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1509 * it up into this table. Returns the cumulated number of sessions for the
1510 * key if the key is present in the table, otherwise zero, so that comparisons
1511 * can be easily performed. If the inspected parameter is not stored in the
1512 * table, <not found> is returned.
1513 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001514static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001515{
1516 struct stktable *t;
1517 struct stktable_key *key;
1518 struct stksess *ts;
1519 void *ptr;
1520
1521 t = &arg_p[0].data.prx->table;
1522
1523 key = smp_to_stkey(smp, t);
1524 if (!key)
1525 return 0;
1526
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001527 ts = stktable_lookup_key(t, key);
1528
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001529 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001530 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001531 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001533 if (!ts) /* key not present */
1534 return 1;
1535
1536 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001537 if (ptr)
1538 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001539
Daniel Corbett3e60b112018-05-27 09:47:12 -04001540 stktable_release(t, ts);
1541 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001542}
1543
1544/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1545 * it up into this table. Returns the session rate the key if the key is
1546 * present in the table, otherwise zero, so that comparisons can be easily
1547 * performed. If the inspected parameter is not stored in the table, <not found>
1548 * is returned.
1549 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001550static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001551{
1552 struct stktable *t;
1553 struct stktable_key *key;
1554 struct stksess *ts;
1555 void *ptr;
1556
1557 t = &arg_p[0].data.prx->table;
1558
1559 key = smp_to_stkey(smp, t);
1560 if (!key)
1561 return 0;
1562
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001563 ts = stktable_lookup_key(t, key);
1564
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001565 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001566 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001567 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001568
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001569 if (!ts) /* key not present */
1570 return 1;
1571
1572 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001573 if (ptr)
1574 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1575 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001576
Daniel Corbett3e60b112018-05-27 09:47:12 -04001577 stktable_release(t, ts);
1578 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001579}
1580
1581/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1582 * it up into this table. Returns the amount of concurrent connections tracking
1583 * the same key if the key is present in the table, otherwise zero, so that
1584 * comparisons can be easily performed. If the inspected parameter is not
1585 * stored in the table, <not found> is returned.
1586 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001587static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001588{
1589 struct stktable *t;
1590 struct stktable_key *key;
1591 struct stksess *ts;
1592
1593 t = &arg_p[0].data.prx->table;
1594
1595 key = smp_to_stkey(smp, t);
1596 if (!key)
1597 return 0;
1598
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001599 ts = stktable_lookup_key(t, key);
1600
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001601 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001602 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001603 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001604
Tim Duesterhus65189c12018-06-26 15:57:29 +02001605 if (!ts)
1606 return 1;
1607
1608 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001609
Daniel Corbett3e60b112018-05-27 09:47:12 -04001610 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001611 return 1;
1612}
1613
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001614/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001615static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001616 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001617{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001618 struct stksess *ts;
1619 struct stkctr *stkctr;
1620
1621 /* Extract the stksess, return OK if no stksess available. */
1622 if (s)
1623 stkctr = &s->stkctr[rule->arg.gpc.sc];
1624 else
1625 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001626
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001627 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001628 if (ts) {
1629 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001630
Willy Tarreau79c1e912016-01-25 14:54:45 +01001631 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1632 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001633 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1634 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001635 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001636
1637 if (ptr1)
1638 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001639 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001640
Emeric Brun819fc6f2017-06-13 19:37:32 +02001641 if (ptr2)
1642 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001643
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001644 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001645
1646 /* If data was modified, we need to touch to re-schedule sync */
1647 stktable_touch_local(stkctr->table, ts, 0);
1648 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001649 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001650 return ACT_RET_CONT;
1651}
1652
1653/* This function is a common parser for using variables. It understands
1654 * the formats:
1655 *
1656 * sc-inc-gpc0(<stick-table ID>)
1657 *
1658 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1659 * it returns 1 and the variable <expr> is filled with the pointer to the
1660 * expression to execute.
1661 */
1662static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1663 struct act_rule *rule, char **err)
1664{
1665 const char *cmd_name = args[*arg-1];
1666 char *error;
1667
1668 cmd_name += strlen("sc-inc-gpc0");
1669 if (*cmd_name == '\0') {
1670 /* default stick table id. */
1671 rule->arg.gpc.sc = 0;
1672 } else {
1673 /* parse the stick table id. */
1674 if (*cmd_name != '(') {
1675 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1676 return ACT_RET_PRS_ERR;
1677 }
1678 cmd_name++; /* jump the '(' */
1679 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1680 if (*error != ')') {
1681 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1682 return ACT_RET_PRS_ERR;
1683 }
1684
1685 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1686 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1687 ACT_ACTION_TRK_SCMAX-1);
1688 return ACT_RET_PRS_ERR;
1689 }
1690 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001691 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001692 rule->action_ptr = action_inc_gpc0;
1693 return ACT_RET_PRS_OK;
1694}
1695
1696/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001697static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1698 struct session *sess, struct stream *s, int flags)
1699{
1700 struct stksess *ts;
1701 struct stkctr *stkctr;
1702
1703 /* Extract the stksess, return OK if no stksess available. */
1704 if (s)
1705 stkctr = &s->stkctr[rule->arg.gpc.sc];
1706 else
1707 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1708
1709 ts = stkctr_entry(stkctr);
1710 if (ts) {
1711 void *ptr1, *ptr2;
1712
1713 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1714 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1715 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1716 if (ptr1 || ptr2) {
1717 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1718
1719 if (ptr1)
1720 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1721 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1722
1723 if (ptr2)
1724 stktable_data_cast(ptr2, gpc1)++;
1725
1726 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1727
1728 /* If data was modified, we need to touch to re-schedule sync */
1729 stktable_touch_local(stkctr->table, ts, 0);
1730 }
1731 }
1732 return ACT_RET_CONT;
1733}
1734
1735/* This function is a common parser for using variables. It understands
1736 * the formats:
1737 *
1738 * sc-inc-gpc1(<stick-table ID>)
1739 *
1740 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1741 * it returns 1 and the variable <expr> is filled with the pointer to the
1742 * expression to execute.
1743 */
1744static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1745 struct act_rule *rule, char **err)
1746{
1747 const char *cmd_name = args[*arg-1];
1748 char *error;
1749
1750 cmd_name += strlen("sc-inc-gpc1");
1751 if (*cmd_name == '\0') {
1752 /* default stick table id. */
1753 rule->arg.gpc.sc = 0;
1754 } else {
1755 /* parse the stick table id. */
1756 if (*cmd_name != '(') {
1757 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1758 return ACT_RET_PRS_ERR;
1759 }
1760 cmd_name++; /* jump the '(' */
1761 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1762 if (*error != ')') {
1763 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1764 return ACT_RET_PRS_ERR;
1765 }
1766
1767 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1768 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1769 ACT_ACTION_TRK_SCMAX-1);
1770 return ACT_RET_PRS_ERR;
1771 }
1772 }
1773 rule->action = ACT_CUSTOM;
1774 rule->action_ptr = action_inc_gpc1;
1775 return ACT_RET_PRS_OK;
1776}
1777
1778/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001779static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001780 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001781{
1782 void *ptr;
1783 struct stksess *ts;
1784 struct stkctr *stkctr;
1785
1786 /* Extract the stksess, return OK if no stksess available. */
1787 if (s)
1788 stkctr = &s->stkctr[rule->arg.gpt.sc];
1789 else
1790 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001791
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001792 ts = stkctr_entry(stkctr);
1793 if (!ts)
1794 return ACT_RET_CONT;
1795
1796 /* Store the sample in the required sc, and ignore errors. */
1797 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001798 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001799 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001800
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001801 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001802
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001803 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001804
1805 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001806 }
1807
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001808 return ACT_RET_CONT;
1809}
1810
1811/* This function is a common parser for using variables. It understands
1812 * the format:
1813 *
1814 * set-gpt0(<stick-table ID>) <expression>
1815 *
1816 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1817 * it returns 1 and the variable <expr> is filled with the pointer to the
1818 * expression to execute.
1819 */
1820static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1821 struct act_rule *rule, char **err)
1822
1823
1824{
1825 const char *cmd_name = args[*arg-1];
1826 char *error;
1827
1828 cmd_name += strlen("sc-set-gpt0");
1829 if (*cmd_name == '\0') {
1830 /* default stick table id. */
1831 rule->arg.gpt.sc = 0;
1832 } else {
1833 /* parse the stick table id. */
1834 if (*cmd_name != '(') {
1835 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1836 return ACT_RET_PRS_ERR;
1837 }
1838 cmd_name++; /* jump the '(' */
1839 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1840 if (*error != ')') {
1841 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1842 return ACT_RET_PRS_ERR;
1843 }
1844
1845 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1846 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1847 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1848 return ACT_RET_PRS_ERR;
1849 }
1850 }
1851
1852 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1853 if (*error != '\0') {
1854 memprintf(err, "invalid integer value '%s'", args[*arg]);
1855 return ACT_RET_PRS_ERR;
1856 }
1857 (*arg)++;
1858
Thierry FOURNIER42148732015-09-02 17:17:33 +02001859 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001860 rule->action_ptr = action_set_gpt0;
1861
1862 return ACT_RET_PRS_OK;
1863}
1864
Willy Tarreau7d562212016-11-25 16:10:05 +01001865/* set temp integer to the number of used entries in the table pointed to by expr.
1866 * Accepts exactly 1 argument of type table.
1867 */
1868static int
1869smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1870{
1871 smp->flags = SMP_F_VOL_TEST;
1872 smp->data.type = SMP_T_SINT;
1873 smp->data.u.sint = args->data.prx->table.current;
1874 return 1;
1875}
1876
1877/* set temp integer to the number of free entries in the table pointed to by expr.
1878 * Accepts exactly 1 argument of type table.
1879 */
1880static int
1881smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1882{
1883 struct proxy *px;
1884
1885 px = args->data.prx;
1886 smp->flags = SMP_F_VOL_TEST;
1887 smp->data.type = SMP_T_SINT;
1888 smp->data.u.sint = px->table.size - px->table.current;
1889 return 1;
1890}
1891
1892/* Returns a pointer to a stkctr depending on the fetch keyword name.
1893 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1894 * sc[0-9]_* will return a pointer to the respective field in the
1895 * stream <l4>. sc_* requires an UINT argument specifying the stick
1896 * counter number. src_* will fill a locally allocated structure with
1897 * the table and entry corresponding to what is specified with src_*.
1898 * NULL may be returned if the designated stkctr is not tracked. For
1899 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1900 * passed. When present, the currently tracked key is then looked up
1901 * in the specified table instead of the current table. The purpose is
1902 * to be able to convery multiple values per key (eg: have gpc0 from
1903 * multiple tables). <strm> is allowed to be NULL, in which case only
1904 * the session will be consulted.
1905 */
1906struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001907smp_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 +01001908{
Willy Tarreau7d562212016-11-25 16:10:05 +01001909 struct stkctr *stkptr;
1910 struct stksess *stksess;
1911 unsigned int num = kw[2] - '0';
1912 int arg = 0;
1913
1914 if (num == '_' - '0') {
1915 /* sc_* variant, args[0] = ctr# (mandatory) */
1916 num = args[arg++].data.sint;
1917 if (num >= MAX_SESS_STKCTR)
1918 return NULL;
1919 }
1920 else if (num > 9) { /* src_* variant, args[0] = table */
1921 struct stktable_key *key;
1922 struct connection *conn = objt_conn(sess->origin);
1923 struct sample smp;
1924
1925 if (!conn)
1926 return NULL;
1927
Joseph Herlant5662fa42018-11-15 13:43:28 -08001928 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01001929 smp.px = NULL;
1930 smp.sess = sess;
1931 smp.strm = strm;
1932 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1933 return NULL;
1934
1935 /* Converts into key. */
1936 key = smp_to_stkey(&smp, &args->data.prx->table);
1937 if (!key)
1938 return NULL;
1939
Emeric Brun819fc6f2017-06-13 19:37:32 +02001940 stkctr->table = &args->data.prx->table;
1941 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1942 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001943 }
1944
1945 /* Here, <num> contains the counter number from 0 to 9 for
1946 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1947 * args[arg] is the first optional argument. We first lookup the
1948 * ctr form the stream, then from the session if it was not there.
1949 */
1950
1951 if (strm)
1952 stkptr = &strm->stkctr[num];
1953 if (!strm || !stkctr_entry(stkptr)) {
1954 stkptr = &sess->stkctr[num];
1955 if (!stkctr_entry(stkptr))
1956 return NULL;
1957 }
1958
1959 stksess = stkctr_entry(stkptr);
1960 if (!stksess)
1961 return NULL;
1962
1963 if (unlikely(args[arg].type == ARGT_TAB)) {
1964 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001965 stkctr->table = &args[arg].data.prx->table;
1966 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1967 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001968 }
1969 return stkptr;
1970}
1971
1972/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1973 * the entry if it doesn't exist yet. This is needed for a few fetch
1974 * functions which need to create an entry, such as src_inc_gpc* and
1975 * src_clr_gpc*.
1976 */
1977struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001978smp_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 +01001979{
Willy Tarreau7d562212016-11-25 16:10:05 +01001980 struct stktable_key *key;
1981 struct connection *conn = objt_conn(sess->origin);
1982 struct sample smp;
1983
1984 if (strncmp(kw, "src_", 4) != 0)
1985 return NULL;
1986
1987 if (!conn)
1988 return NULL;
1989
Joseph Herlant5662fa42018-11-15 13:43:28 -08001990 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01001991 smp.px = NULL;
1992 smp.sess = sess;
1993 smp.strm = strm;
1994 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1995 return NULL;
1996
1997 /* Converts into key. */
1998 key = smp_to_stkey(&smp, &args->data.prx->table);
1999 if (!key)
2000 return NULL;
2001
Emeric Brun819fc6f2017-06-13 19:37:32 +02002002 stkctr->table = &args->data.prx->table;
2003 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2004 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002005}
2006
2007/* set return a boolean indicating if the requested stream counter is
2008 * currently being tracked or not.
2009 * Supports being called as "sc[0-9]_tracked" only.
2010 */
2011static int
2012smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2013{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002014 struct stkctr tmpstkctr;
2015 struct stkctr *stkctr;
2016
Willy Tarreau7d562212016-11-25 16:10:05 +01002017 smp->flags = SMP_F_VOL_TEST;
2018 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002019 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2020 smp->data.u.sint = !!stkctr;
2021
2022 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002023 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002024 stktable_release(stkctr->table, stkctr_entry(stkctr));
2025
Willy Tarreau7d562212016-11-25 16:10:05 +01002026 return 1;
2027}
2028
2029/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2030 * frontend counters or from the src.
2031 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2032 * zero is returned if the key is new.
2033 */
2034static int
2035smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2036{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002037 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002038 struct stkctr *stkctr;
2039
Emeric Brun819fc6f2017-06-13 19:37:32 +02002040 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002041 if (!stkctr)
2042 return 0;
2043
2044 smp->flags = SMP_F_VOL_TEST;
2045 smp->data.type = SMP_T_SINT;
2046 smp->data.u.sint = 0;
2047
Emeric Brun819fc6f2017-06-13 19:37:32 +02002048 if (stkctr_entry(stkctr)) {
2049 void *ptr;
2050
2051 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2052 if (!ptr) {
2053 if (stkctr == &tmpstkctr)
2054 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002055 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002056 }
2057
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002058 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002059
Willy Tarreau7d562212016-11-25 16:10:05 +01002060 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002061
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002062 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002063
2064 if (stkctr == &tmpstkctr)
2065 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002066 }
2067 return 1;
2068}
2069
2070/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2071 * frontend counters or from the src.
2072 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2073 * zero is returned if the key is new.
2074 */
2075static int
2076smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2077{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002078 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002079 struct stkctr *stkctr;
2080
Emeric Brun819fc6f2017-06-13 19:37:32 +02002081 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002082 if (!stkctr)
2083 return 0;
2084
2085 smp->flags = SMP_F_VOL_TEST;
2086 smp->data.type = SMP_T_SINT;
2087 smp->data.u.sint = 0;
2088
2089 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002090 void *ptr;
2091
2092 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2093 if (!ptr) {
2094 if (stkctr == &tmpstkctr)
2095 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002096 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002097 }
2098
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002099 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002100
Willy Tarreau7d562212016-11-25 16:10:05 +01002101 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002102
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002103 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002104
2105 if (stkctr == &tmpstkctr)
2106 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002107 }
2108 return 1;
2109}
2110
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002111/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2112 * frontend counters or from the src.
2113 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2114 * zero is returned if the key is new.
2115 */
2116static int
2117smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2118{
2119 struct stkctr tmpstkctr;
2120 struct stkctr *stkctr;
2121
2122 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2123 if (!stkctr)
2124 return 0;
2125
2126 smp->flags = SMP_F_VOL_TEST;
2127 smp->data.type = SMP_T_SINT;
2128 smp->data.u.sint = 0;
2129
2130 if (stkctr_entry(stkctr) != NULL) {
2131 void *ptr;
2132
2133 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2134 if (!ptr) {
2135 if (stkctr == &tmpstkctr)
2136 stktable_release(stkctr->table, stkctr_entry(stkctr));
2137 return 0; /* parameter not stored */
2138 }
2139
2140 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2141
2142 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2143
2144 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2145
2146 if (stkctr == &tmpstkctr)
2147 stktable_release(stkctr->table, stkctr_entry(stkctr));
2148 }
2149 return 1;
2150}
2151
Willy Tarreau7d562212016-11-25 16:10:05 +01002152/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2153 * tracked frontend counters or from the src.
2154 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2155 * Value zero is returned if the key is new.
2156 */
2157static int
2158smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2159{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002160 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002161 struct stkctr *stkctr;
2162
Emeric Brun819fc6f2017-06-13 19:37:32 +02002163 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002164 if (!stkctr)
2165 return 0;
2166
2167 smp->flags = SMP_F_VOL_TEST;
2168 smp->data.type = SMP_T_SINT;
2169 smp->data.u.sint = 0;
2170 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002171 void *ptr;
2172
2173 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2174 if (!ptr) {
2175 if (stkctr == &tmpstkctr)
2176 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002177 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002178 }
2179
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002180 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002181
Willy Tarreau7d562212016-11-25 16:10:05 +01002182 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2183 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002184
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002185 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002186
2187 if (stkctr == &tmpstkctr)
2188 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002189 }
2190 return 1;
2191}
2192
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002193/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2194 * tracked frontend counters or from the src.
2195 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2196 * Value zero is returned if the key is new.
2197 */
2198static int
2199smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2200{
2201 struct stkctr tmpstkctr;
2202 struct stkctr *stkctr;
2203
2204 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2205 if (!stkctr)
2206 return 0;
2207
2208 smp->flags = SMP_F_VOL_TEST;
2209 smp->data.type = SMP_T_SINT;
2210 smp->data.u.sint = 0;
2211 if (stkctr_entry(stkctr) != NULL) {
2212 void *ptr;
2213
2214 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2215 if (!ptr) {
2216 if (stkctr == &tmpstkctr)
2217 stktable_release(stkctr->table, stkctr_entry(stkctr));
2218 return 0; /* parameter not stored */
2219 }
2220
2221 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2222
2223 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2224 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2225
2226 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2227
2228 if (stkctr == &tmpstkctr)
2229 stktable_release(stkctr->table, stkctr_entry(stkctr));
2230 }
2231 return 1;
2232}
2233
Willy Tarreau7d562212016-11-25 16:10:05 +01002234/* Increment the General Purpose Counter 0 value from the stream's tracked
2235 * frontend counters and return it into temp integer.
2236 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2237 */
2238static int
2239smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2240{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002241 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002242 struct stkctr *stkctr;
2243
Emeric Brun819fc6f2017-06-13 19:37:32 +02002244 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002245 if (!stkctr)
2246 return 0;
2247
2248 smp->flags = SMP_F_VOL_TEST;
2249 smp->data.type = SMP_T_SINT;
2250 smp->data.u.sint = 0;
2251
Emeric Brun819fc6f2017-06-13 19:37:32 +02002252 if (!stkctr_entry(stkctr))
2253 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002254
2255 if (stkctr && stkctr_entry(stkctr)) {
2256 void *ptr1,*ptr2;
2257
Emeric Brun819fc6f2017-06-13 19:37:32 +02002258
Willy Tarreau7d562212016-11-25 16:10:05 +01002259 /* First, update gpc0_rate if it's tracked. Second, update its
2260 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2261 */
2262 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002263 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002264 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002265 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002266
Emeric Brun819fc6f2017-06-13 19:37:32 +02002267 if (ptr1) {
2268 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2269 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2270 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2271 }
2272
2273 if (ptr2)
2274 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2275
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002276 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002277
2278 /* If data was modified, we need to touch to re-schedule sync */
2279 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2280 }
2281 else if (stkctr == &tmpstkctr)
2282 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002283 }
2284 return 1;
2285}
2286
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002287/* Increment the General Purpose Counter 1 value from the stream's tracked
2288 * frontend counters and return it into temp integer.
2289 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2290 */
2291static int
2292smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2293{
2294 struct stkctr tmpstkctr;
2295 struct stkctr *stkctr;
2296
2297 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2298 if (!stkctr)
2299 return 0;
2300
2301 smp->flags = SMP_F_VOL_TEST;
2302 smp->data.type = SMP_T_SINT;
2303 smp->data.u.sint = 0;
2304
2305 if (!stkctr_entry(stkctr))
2306 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2307
2308 if (stkctr && stkctr_entry(stkctr)) {
2309 void *ptr1,*ptr2;
2310
2311
2312 /* First, update gpc1_rate if it's tracked. Second, update its
2313 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2314 */
2315 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2316 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2317 if (ptr1 || ptr2) {
2318 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2319
2320 if (ptr1) {
2321 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2322 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2323 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2324 }
2325
2326 if (ptr2)
2327 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2328
2329 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2330
2331 /* If data was modified, we need to touch to re-schedule sync */
2332 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2333 }
2334 else if (stkctr == &tmpstkctr)
2335 stktable_release(stkctr->table, stkctr_entry(stkctr));
2336 }
2337 return 1;
2338}
2339
Willy Tarreau7d562212016-11-25 16:10:05 +01002340/* Clear the General Purpose Counter 0 value from the stream's tracked
2341 * frontend counters and return its previous value into temp integer.
2342 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2343 */
2344static int
2345smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2346{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002347 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002348 struct stkctr *stkctr;
2349
Emeric Brun819fc6f2017-06-13 19:37:32 +02002350 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002351 if (!stkctr)
2352 return 0;
2353
2354 smp->flags = SMP_F_VOL_TEST;
2355 smp->data.type = SMP_T_SINT;
2356 smp->data.u.sint = 0;
2357
Emeric Brun819fc6f2017-06-13 19:37:32 +02002358 if (!stkctr_entry(stkctr))
2359 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002360
Emeric Brun819fc6f2017-06-13 19:37:32 +02002361 if (stkctr && stkctr_entry(stkctr)) {
2362 void *ptr;
2363
2364 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2365 if (!ptr) {
2366 if (stkctr == &tmpstkctr)
2367 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002368 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002369 }
2370
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002371 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002372
Willy Tarreau7d562212016-11-25 16:10:05 +01002373 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2374 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002375
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002376 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002377
Willy Tarreau7d562212016-11-25 16:10:05 +01002378 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002379 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002380 }
2381 return 1;
2382}
2383
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002384/* Clear the General Purpose Counter 1 value from the stream's tracked
2385 * frontend counters and return its previous value into temp integer.
2386 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2387 */
2388static int
2389smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2390{
2391 struct stkctr tmpstkctr;
2392 struct stkctr *stkctr;
2393
2394 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2395 if (!stkctr)
2396 return 0;
2397
2398 smp->flags = SMP_F_VOL_TEST;
2399 smp->data.type = SMP_T_SINT;
2400 smp->data.u.sint = 0;
2401
2402 if (!stkctr_entry(stkctr))
2403 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2404
2405 if (stkctr && stkctr_entry(stkctr)) {
2406 void *ptr;
2407
2408 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2409 if (!ptr) {
2410 if (stkctr == &tmpstkctr)
2411 stktable_release(stkctr->table, stkctr_entry(stkctr));
2412 return 0; /* parameter not stored */
2413 }
2414
2415 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2416
2417 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2418 stktable_data_cast(ptr, gpc1) = 0;
2419
2420 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2421
2422 /* If data was modified, we need to touch to re-schedule sync */
2423 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2424 }
2425 return 1;
2426}
2427
Willy Tarreau7d562212016-11-25 16:10:05 +01002428/* set <smp> to the cumulated number of connections from the stream's tracked
2429 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2430 * "src_conn_cnt" only.
2431 */
2432static int
2433smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2434{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002435 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002436 struct stkctr *stkctr;
2437
Emeric Brun819fc6f2017-06-13 19:37:32 +02002438 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002439 if (!stkctr)
2440 return 0;
2441
2442 smp->flags = SMP_F_VOL_TEST;
2443 smp->data.type = SMP_T_SINT;
2444 smp->data.u.sint = 0;
2445 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002446 void *ptr;
2447
2448 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2449 if (!ptr) {
2450 if (stkctr == &tmpstkctr)
2451 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002452 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002453 }
2454
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002455 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002456
Willy Tarreau7d562212016-11-25 16:10:05 +01002457 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002458
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002459 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002460
2461 if (stkctr == &tmpstkctr)
2462 stktable_release(stkctr->table, stkctr_entry(stkctr));
2463
2464
Willy Tarreau7d562212016-11-25 16:10:05 +01002465 }
2466 return 1;
2467}
2468
2469/* set <smp> to the connection rate from the stream's tracked frontend
2470 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2471 * only.
2472 */
2473static int
2474smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2475{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002476 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002477 struct stkctr *stkctr;
2478
Emeric Brun819fc6f2017-06-13 19:37:32 +02002479 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002480 if (!stkctr)
2481 return 0;
2482
2483 smp->flags = SMP_F_VOL_TEST;
2484 smp->data.type = SMP_T_SINT;
2485 smp->data.u.sint = 0;
2486 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002487 void *ptr;
2488
2489 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2490 if (!ptr) {
2491 if (stkctr == &tmpstkctr)
2492 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002493 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002494 }
2495
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002496 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002497
Willy Tarreau7d562212016-11-25 16:10:05 +01002498 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2499 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002500
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002501 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002502
2503 if (stkctr == &tmpstkctr)
2504 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002505 }
2506 return 1;
2507}
2508
2509/* set temp integer to the number of connections from the stream's source address
2510 * in the table pointed to by expr, after updating it.
2511 * Accepts exactly 1 argument of type table.
2512 */
2513static int
2514smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2515{
2516 struct connection *conn = objt_conn(smp->sess->origin);
2517 struct stksess *ts;
2518 struct stktable_key *key;
2519 void *ptr;
2520 struct proxy *px;
2521
2522 if (!conn)
2523 return 0;
2524
Joseph Herlant5662fa42018-11-15 13:43:28 -08002525 /* Fetch source address in a sample. */
Willy Tarreau7d562212016-11-25 16:10:05 +01002526 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2527 return 0;
2528
2529 /* Converts into key. */
2530 key = smp_to_stkey(smp, &args->data.prx->table);
2531 if (!key)
2532 return 0;
2533
2534 px = args->data.prx;
2535
Emeric Brun819fc6f2017-06-13 19:37:32 +02002536 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002537 /* entry does not exist and could not be created */
2538 return 0;
2539
2540 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002541 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002542 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002543 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002544
2545 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002546
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002547 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002548
Willy Tarreau7d562212016-11-25 16:10:05 +01002549 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002551 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002552
Willy Tarreau7d562212016-11-25 16:10:05 +01002553 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002554
2555 stktable_touch_local(&px->table, ts, 1);
2556
2557 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002558 return 1;
2559}
2560
2561/* set <smp> to the number of concurrent connections from the stream's tracked
2562 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2563 * "src_conn_cur" only.
2564 */
2565static int
2566smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2567{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002568 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002569 struct stkctr *stkctr;
2570
Emeric Brun819fc6f2017-06-13 19:37:32 +02002571 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002572 if (!stkctr)
2573 return 0;
2574
2575 smp->flags = SMP_F_VOL_TEST;
2576 smp->data.type = SMP_T_SINT;
2577 smp->data.u.sint = 0;
2578 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002579 void *ptr;
2580
2581 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2582 if (!ptr) {
2583 if (stkctr == &tmpstkctr)
2584 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002585 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002586 }
2587
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002588 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002589
Willy Tarreau7d562212016-11-25 16:10:05 +01002590 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002591
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002592 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002593
2594 if (stkctr == &tmpstkctr)
2595 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002596 }
2597 return 1;
2598}
2599
2600/* set <smp> to the cumulated number of streams from the stream's tracked
2601 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2602 * "src_sess_cnt" only.
2603 */
2604static int
2605smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2606{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002607 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002608 struct stkctr *stkctr;
2609
Emeric Brun819fc6f2017-06-13 19:37:32 +02002610 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002611 if (!stkctr)
2612 return 0;
2613
2614 smp->flags = SMP_F_VOL_TEST;
2615 smp->data.type = SMP_T_SINT;
2616 smp->data.u.sint = 0;
2617 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002618 void *ptr;
2619
2620 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2621 if (!ptr) {
2622 if (stkctr == &tmpstkctr)
2623 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002624 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002625 }
2626
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002627 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002628
Willy Tarreau7d562212016-11-25 16:10:05 +01002629 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002630
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002631 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002632
2633 if (stkctr == &tmpstkctr)
2634 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002635 }
2636 return 1;
2637}
2638
2639/* set <smp> to the stream rate from the stream's tracked frontend counters.
2640 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2641 */
2642static int
2643smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2644{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002645 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002646 struct stkctr *stkctr;
2647
Emeric Brun819fc6f2017-06-13 19:37:32 +02002648 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002649 if (!stkctr)
2650 return 0;
2651
2652 smp->flags = SMP_F_VOL_TEST;
2653 smp->data.type = SMP_T_SINT;
2654 smp->data.u.sint = 0;
2655 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002656 void *ptr;
2657
2658 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2659 if (!ptr) {
2660 if (stkctr == &tmpstkctr)
2661 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002662 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002663 }
2664
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002665 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002666
Willy Tarreau7d562212016-11-25 16:10:05 +01002667 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2668 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002669
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002670 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002671
2672 if (stkctr == &tmpstkctr)
2673 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002674 }
2675 return 1;
2676}
2677
2678/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2679 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2680 * "src_http_req_cnt" only.
2681 */
2682static int
2683smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2684{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002685 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002686 struct stkctr *stkctr;
2687
Emeric Brun819fc6f2017-06-13 19:37:32 +02002688 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002689 if (!stkctr)
2690 return 0;
2691
2692 smp->flags = SMP_F_VOL_TEST;
2693 smp->data.type = SMP_T_SINT;
2694 smp->data.u.sint = 0;
2695 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002696 void *ptr;
2697
2698 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2699 if (!ptr) {
2700 if (stkctr == &tmpstkctr)
2701 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002702 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002703 }
2704
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002705 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002706
Willy Tarreau7d562212016-11-25 16:10:05 +01002707 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002708
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002709 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002710
2711 if (stkctr == &tmpstkctr)
2712 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002713 }
2714 return 1;
2715}
2716
2717/* set <smp> to the HTTP request rate from the stream's tracked frontend
2718 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2719 * "src_http_req_rate" only.
2720 */
2721static int
2722smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2723{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002724 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002725 struct stkctr *stkctr;
2726
Emeric Brun819fc6f2017-06-13 19:37:32 +02002727 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002728 if (!stkctr)
2729 return 0;
2730
2731 smp->flags = SMP_F_VOL_TEST;
2732 smp->data.type = SMP_T_SINT;
2733 smp->data.u.sint = 0;
2734 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002735 void *ptr;
2736
2737 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2738 if (!ptr) {
2739 if (stkctr == &tmpstkctr)
2740 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002741 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002742 }
2743
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002744 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002745
Willy Tarreau7d562212016-11-25 16:10:05 +01002746 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2747 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002748
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002749 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002750
2751 if (stkctr == &tmpstkctr)
2752 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002753 }
2754 return 1;
2755}
2756
2757/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2758 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2759 * "src_http_err_cnt" only.
2760 */
2761static int
2762smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2763{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002764 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002765 struct stkctr *stkctr;
2766
Emeric Brun819fc6f2017-06-13 19:37:32 +02002767 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002768 if (!stkctr)
2769 return 0;
2770
2771 smp->flags = SMP_F_VOL_TEST;
2772 smp->data.type = SMP_T_SINT;
2773 smp->data.u.sint = 0;
2774 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002775 void *ptr;
2776
2777 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2778 if (!ptr) {
2779 if (stkctr == &tmpstkctr)
2780 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002781 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002782 }
2783
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002784 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002785
Willy Tarreau7d562212016-11-25 16:10:05 +01002786 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002787
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002788 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002789
2790 if (stkctr == &tmpstkctr)
2791 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002792 }
2793 return 1;
2794}
2795
2796/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2797 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2798 * "src_http_err_rate" only.
2799 */
2800static int
2801smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2802{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002803 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002804 struct stkctr *stkctr;
2805
Emeric Brun819fc6f2017-06-13 19:37:32 +02002806 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002807 if (!stkctr)
2808 return 0;
2809
2810 smp->flags = SMP_F_VOL_TEST;
2811 smp->data.type = SMP_T_SINT;
2812 smp->data.u.sint = 0;
2813 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002814 void *ptr;
2815
2816 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2817 if (!ptr) {
2818 if (stkctr == &tmpstkctr)
2819 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002820 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002821 }
2822
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002823 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002824
Willy Tarreau7d562212016-11-25 16:10:05 +01002825 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2826 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002828 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002829
2830 if (stkctr == &tmpstkctr)
2831 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002832 }
2833 return 1;
2834}
2835
2836/* set <smp> to the number of kbytes received from clients, as found in the
2837 * stream's tracked frontend counters. Supports being called as
2838 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2839 */
2840static int
2841smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2842{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002843 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002844 struct stkctr *stkctr;
2845
Emeric Brun819fc6f2017-06-13 19:37:32 +02002846 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002847 if (!stkctr)
2848 return 0;
2849
2850 smp->flags = SMP_F_VOL_TEST;
2851 smp->data.type = SMP_T_SINT;
2852 smp->data.u.sint = 0;
2853 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002854 void *ptr;
2855
2856 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2857 if (!ptr) {
2858 if (stkctr == &tmpstkctr)
2859 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002860 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002861 }
2862
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002863 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002864
Willy Tarreau7d562212016-11-25 16:10:05 +01002865 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002866
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002867 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002868
2869 if (stkctr == &tmpstkctr)
2870 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002871 }
2872 return 1;
2873}
2874
2875/* set <smp> to the data rate received from clients in bytes/s, as found
2876 * in the stream's tracked frontend counters. Supports being called as
2877 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2878 */
2879static int
2880smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2881{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002882 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002883 struct stkctr *stkctr;
2884
Emeric Brun819fc6f2017-06-13 19:37:32 +02002885 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002886 if (!stkctr)
2887 return 0;
2888
2889 smp->flags = SMP_F_VOL_TEST;
2890 smp->data.type = SMP_T_SINT;
2891 smp->data.u.sint = 0;
2892 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002893 void *ptr;
2894
2895 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2896 if (!ptr) {
2897 if (stkctr == &tmpstkctr)
2898 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002899 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002900 }
2901
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002902 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002903
Willy Tarreau7d562212016-11-25 16:10:05 +01002904 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2905 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002906
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002907 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002908
2909 if (stkctr == &tmpstkctr)
2910 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002911 }
2912 return 1;
2913}
2914
2915/* set <smp> to the number of kbytes sent to clients, as found in the
2916 * stream's tracked frontend counters. Supports being called as
2917 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2918 */
2919static int
2920smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2921{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002922 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002923 struct stkctr *stkctr;
2924
Emeric Brun819fc6f2017-06-13 19:37:32 +02002925 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002926 if (!stkctr)
2927 return 0;
2928
2929 smp->flags = SMP_F_VOL_TEST;
2930 smp->data.type = SMP_T_SINT;
2931 smp->data.u.sint = 0;
2932 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002933 void *ptr;
2934
2935 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2936 if (!ptr) {
2937 if (stkctr == &tmpstkctr)
2938 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002939 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002940 }
2941
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002942 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002943
Willy Tarreau7d562212016-11-25 16:10:05 +01002944 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002945
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002946 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002947
2948 if (stkctr == &tmpstkctr)
2949 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002950 }
2951 return 1;
2952}
2953
2954/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2955 * stream's tracked frontend counters. Supports being called as
2956 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2957 */
2958static int
2959smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2960{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002961 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002962 struct stkctr *stkctr;
2963
Emeric Brun819fc6f2017-06-13 19:37:32 +02002964 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002965 if (!stkctr)
2966 return 0;
2967
2968 smp->flags = SMP_F_VOL_TEST;
2969 smp->data.type = SMP_T_SINT;
2970 smp->data.u.sint = 0;
2971 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002972 void *ptr;
2973
2974 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2975 if (!ptr) {
2976 if (stkctr == &tmpstkctr)
2977 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002978 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002979 }
2980
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002981 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002982
Willy Tarreau7d562212016-11-25 16:10:05 +01002983 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2984 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002985
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002986 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002987
2988 if (stkctr == &tmpstkctr)
2989 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002990 }
2991 return 1;
2992}
2993
2994/* set <smp> to the number of active trackers on the SC entry in the stream's
2995 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2996 */
2997static int
2998smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2999{
Emeric Brun819fc6f2017-06-13 19:37:32 +02003000 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01003001 struct stkctr *stkctr;
3002
Emeric Brun819fc6f2017-06-13 19:37:32 +02003003 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003004 if (!stkctr)
3005 return 0;
3006
3007 smp->flags = SMP_F_VOL_TEST;
3008 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003009 if (stkctr == &tmpstkctr) {
3010 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3011 stktable_release(stkctr->table, stkctr_entry(stkctr));
3012 }
3013 else {
3014 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3015 }
3016
Willy Tarreau7d562212016-11-25 16:10:05 +01003017 return 1;
3018}
3019
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003020
3021/* The functions below are used to manipulate table contents from the CLI.
3022 * There are 3 main actions, "clear", "set" and "show". The code is shared
3023 * between all actions, and the action is encoded in the void *private in
3024 * the appctx as well as in the keyword registration, among one of the
3025 * following values.
3026 */
3027
3028enum {
3029 STK_CLI_ACT_CLR,
3030 STK_CLI_ACT_SET,
3031 STK_CLI_ACT_SHOW,
3032};
3033
3034/* Dump the status of a table to a stream interface's
3035 * read buffer. It returns 0 if the output buffer is full
3036 * and needs to be called again, otherwise non-zero.
3037 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003038static int table_dump_head_to_buffer(struct buffer *msg,
3039 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003040 struct proxy *proxy, struct proxy *target)
3041{
3042 struct stream *s = si_strm(si);
3043
3044 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3045 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3046
3047 /* any other information should be dumped here */
3048
William Lallemand07a62f72017-05-24 00:57:40 +02003049 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003050 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3051
Willy Tarreau06d80a92017-10-19 14:32:15 +02003052 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003053 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003054 return 0;
3055 }
3056
3057 return 1;
3058}
3059
3060/* Dump a table entry to a stream interface's
3061 * read buffer. It returns 0 if the output buffer is full
3062 * and needs to be called again, otherwise non-zero.
3063 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003064static int table_dump_entry_to_buffer(struct buffer *msg,
3065 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003066 struct proxy *proxy, struct stksess *entry)
3067{
3068 int dt;
3069
3070 chunk_appendf(msg, "%p:", entry);
3071
3072 if (proxy->table.type == SMP_T_IPV4) {
3073 char addr[INET_ADDRSTRLEN];
3074 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3075 chunk_appendf(msg, " key=%s", addr);
3076 }
3077 else if (proxy->table.type == SMP_T_IPV6) {
3078 char addr[INET6_ADDRSTRLEN];
3079 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3080 chunk_appendf(msg, " key=%s", addr);
3081 }
3082 else if (proxy->table.type == SMP_T_SINT) {
3083 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3084 }
3085 else if (proxy->table.type == SMP_T_STR) {
3086 chunk_appendf(msg, " key=");
3087 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3088 }
3089 else {
3090 chunk_appendf(msg, " key=");
3091 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3092 }
3093
3094 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3095
3096 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3097 void *ptr;
3098
3099 if (proxy->table.data_ofs[dt] == 0)
3100 continue;
3101 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3102 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3103 else
3104 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3105
3106 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3107 switch (stktable_data_types[dt].std_type) {
3108 case STD_T_SINT:
3109 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3110 break;
3111 case STD_T_UINT:
3112 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3113 break;
3114 case STD_T_ULL:
3115 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3116 break;
3117 case STD_T_FRQP:
3118 chunk_appendf(msg, "%d",
3119 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3120 proxy->table.data_arg[dt].u));
3121 break;
3122 }
3123 }
3124 chunk_appendf(msg, "\n");
3125
Willy Tarreau06d80a92017-10-19 14:32:15 +02003126 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003127 si_rx_room_blk(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003128 return 0;
3129 }
3130
3131 return 1;
3132}
3133
3134
3135/* Processes a single table entry matching a specific key passed in argument.
3136 * returns 0 if wants to be called again, 1 if has ended processing.
3137 */
3138static int table_process_entry_per_key(struct appctx *appctx, char **args)
3139{
3140 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003141 struct proxy *px = appctx->ctx.table.target;
3142 struct stksess *ts;
3143 uint32_t uint32_key;
3144 unsigned char ip6_key[sizeof(struct in6_addr)];
3145 long long value;
3146 int data_type;
3147 int cur_arg;
3148 void *ptr;
3149 struct freq_ctr_period *frqp;
3150
3151 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003152 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003153 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003154 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003155 return 1;
3156 }
3157
3158 switch (px->table.type) {
3159 case SMP_T_IPV4:
3160 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003161 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003162 break;
3163 case SMP_T_IPV6:
3164 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003165 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003166 break;
3167 case SMP_T_SINT:
3168 {
3169 char *endptr;
3170 unsigned long val;
3171 errno = 0;
3172 val = strtoul(args[4], &endptr, 10);
3173 if ((errno == ERANGE && val == ULONG_MAX) ||
3174 (errno != 0 && val == 0) || endptr == args[4] ||
3175 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003176 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003177 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003178 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003179 return 1;
3180 }
3181 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003182 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003183 break;
3184 }
3185 break;
3186 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003187 static_table_key.key = args[4];
3188 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003189 break;
3190 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003191 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003192 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003193 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003194 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3195 break;
3196 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003197 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003198 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3199 break;
3200 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003201 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003202 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3203 break;
3204 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003205 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003206 appctx->ctx.cli.msg = "Unknown action\n";
3207 break;
3208 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003209 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003210 return 1;
3211 }
3212
3213 /* check permissions */
3214 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3215 return 1;
3216
Willy Tarreaua24bc782016-12-14 15:50:35 +01003217 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003218 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003220 if (!ts)
3221 return 1;
3222 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003223 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3224 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003225 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003226 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003227 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003229 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003231 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003232 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003233 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003234 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003235 break;
3236
3237 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003238 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003239 if (!ts)
3240 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003241
3242 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003243 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003244 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003245 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003246 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003247 return 1;
3248 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003249
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003250 break;
3251
3252 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003253 ts = stktable_get_entry(&px->table, &static_table_key);
3254 if (!ts) {
3255 /* don't delete an entry which is currently referenced */
3256 appctx->ctx.cli.severity = LOG_ERR;
3257 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3258 appctx->st0 = CLI_ST_PRINT;
3259 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003260 }
3261
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003262 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003263 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3264 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003265 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003266 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003267 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003268 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003269 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003270 return 1;
3271 }
3272
3273 data_type = stktable_get_data_type(args[cur_arg] + 5);
3274 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003275 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003276 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003277 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003278 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003279 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003280 return 1;
3281 }
3282
3283 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003284 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003285 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003286 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003287 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003288 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003289 return 1;
3290 }
3291
3292 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003293 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003294 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003295 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003296 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003297 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003298 return 1;
3299 }
3300
3301 ptr = stktable_data_ptr(&px->table, ts, data_type);
3302
3303 switch (stktable_data_types[data_type].std_type) {
3304 case STD_T_SINT:
3305 stktable_data_cast(ptr, std_t_sint) = value;
3306 break;
3307 case STD_T_UINT:
3308 stktable_data_cast(ptr, std_t_uint) = value;
3309 break;
3310 case STD_T_ULL:
3311 stktable_data_cast(ptr, std_t_ull) = value;
3312 break;
3313 case STD_T_FRQP:
3314 /* We set both the current and previous values. That way
3315 * the reported frequency is stable during all the period
3316 * then slowly fades out. This allows external tools to
3317 * push measures without having to update them too often.
3318 */
3319 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003320 /* First bit is reserved for the freq_ctr_period lock
3321 Note: here we're still protected by the stksess lock
3322 so we don't need to update the update the freq_ctr_period
3323 using its internal lock */
3324 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003325 frqp->prev_ctr = 0;
3326 frqp->curr_ctr = value;
3327 break;
3328 }
3329 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003330 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003331 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003332 break;
3333
3334 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003335 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003336 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003337 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003338 break;
3339 }
3340 return 1;
3341}
3342
3343/* Prepares the appctx fields with the data-based filters from the command line.
3344 * Returns 0 if the dump can proceed, 1 if has ended processing.
3345 */
3346static int table_prepare_data_request(struct appctx *appctx, char **args)
3347{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003348 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003349 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003350 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003351 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003352 return 1;
3353 }
3354
3355 /* condition on stored data value */
3356 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3357 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003358 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003359 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003360 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003361 return 1;
3362 }
3363
3364 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003365 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003366 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003367 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003368 return 1;
3369 }
3370
3371 appctx->ctx.table.data_op = get_std_op(args[4]);
3372 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003373 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003374 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003375 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003376 return 1;
3377 }
3378
3379 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003380 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003381 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003382 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003383 return 1;
3384 }
3385
3386 /* OK we're done, all the fields are set */
3387 return 0;
3388}
3389
3390/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003391static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003392{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003393 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003394 appctx->ctx.table.target = NULL;
3395 appctx->ctx.table.proxy = NULL;
3396 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003397 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003398
3399 if (*args[2]) {
3400 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3401 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003402 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003403 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003404 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003405 return 1;
3406 }
3407 }
3408 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003409 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003410 goto err_args;
3411 return 0;
3412 }
3413
3414 if (strcmp(args[3], "key") == 0)
3415 return table_process_entry_per_key(appctx, args);
3416 else if (strncmp(args[3], "data.", 5) == 0)
3417 return table_prepare_data_request(appctx, args);
3418 else if (*args[3])
3419 goto err_args;
3420
3421 return 0;
3422
3423err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003424 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003425 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003426 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003427 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3428 break;
3429 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003430 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003431 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3432 break;
3433 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003434 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003435 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3436 break;
3437 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003438 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003439 appctx->ctx.cli.msg = "Unknown action\n";
3440 break;
3441 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003442 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003443 return 1;
3444}
3445
3446/* This function is used to deal with table operations (dump or clear depending
3447 * on the action stored in appctx->private). It returns 0 if the output buffer is
3448 * full and it needs to be called again, otherwise non-zero.
3449 */
3450static int cli_io_handler_table(struct appctx *appctx)
3451{
3452 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003453 struct stream *s = si_strm(si);
3454 struct ebmb_node *eb;
3455 int dt;
3456 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003457 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003458
3459 /*
3460 * We have 3 possible states in appctx->st2 :
3461 * - STAT_ST_INIT : the first call
3462 * - STAT_ST_INFO : the proxy pointer points to the next table to
3463 * dump, the entry pointer is NULL ;
3464 * - STAT_ST_LIST : the proxy pointer points to the current table
3465 * and the entry pointer points to the next entry to be dumped,
3466 * and the refcount on the next entry is held ;
3467 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3468 * data though.
3469 */
3470
3471 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3472 /* in case of abort, remove any refcount we might have set on an entry */
3473 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003474 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003475 }
3476 return 1;
3477 }
3478
3479 chunk_reset(&trash);
3480
3481 while (appctx->st2 != STAT_ST_FIN) {
3482 switch (appctx->st2) {
3483 case STAT_ST_INIT:
3484 appctx->ctx.table.proxy = appctx->ctx.table.target;
3485 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003486 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003487
3488 appctx->ctx.table.entry = NULL;
3489 appctx->st2 = STAT_ST_INFO;
3490 break;
3491
3492 case STAT_ST_INFO:
3493 if (!appctx->ctx.table.proxy ||
3494 (appctx->ctx.table.target &&
3495 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3496 appctx->st2 = STAT_ST_END;
3497 break;
3498 }
3499
3500 if (appctx->ctx.table.proxy->table.size) {
3501 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3502 return 0;
3503
3504 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003505 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003506 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003507 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003508 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3509 if (eb) {
3510 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3511 appctx->ctx.table.entry->ref_cnt++;
3512 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003513 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003514 break;
3515 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003516 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003517 }
3518 }
3519 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3520 break;
3521
3522 case STAT_ST_LIST:
3523 skip_entry = 0;
3524
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003525 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003526
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003527 if (appctx->ctx.table.data_type >= 0) {
3528 /* we're filtering on some data contents */
3529 void *ptr;
3530 long long data;
3531
Emeric Brun819fc6f2017-06-13 19:37:32 +02003532
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003533 dt = appctx->ctx.table.data_type;
3534 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3535 appctx->ctx.table.entry,
3536 dt);
3537
3538 data = 0;
3539 switch (stktable_data_types[dt].std_type) {
3540 case STD_T_SINT:
3541 data = stktable_data_cast(ptr, std_t_sint);
3542 break;
3543 case STD_T_UINT:
3544 data = stktable_data_cast(ptr, std_t_uint);
3545 break;
3546 case STD_T_ULL:
3547 data = stktable_data_cast(ptr, std_t_ull);
3548 break;
3549 case STD_T_FRQP:
3550 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3551 appctx->ctx.table.proxy->table.data_arg[dt].u);
3552 break;
3553 }
3554
3555 /* skip the entry if the data does not match the test and the value */
3556 if ((data < appctx->ctx.table.value &&
3557 (appctx->ctx.table.data_op == STD_OP_EQ ||
3558 appctx->ctx.table.data_op == STD_OP_GT ||
3559 appctx->ctx.table.data_op == STD_OP_GE)) ||
3560 (data == appctx->ctx.table.value &&
3561 (appctx->ctx.table.data_op == STD_OP_NE ||
3562 appctx->ctx.table.data_op == STD_OP_GT ||
3563 appctx->ctx.table.data_op == STD_OP_LT)) ||
3564 (data > appctx->ctx.table.value &&
3565 (appctx->ctx.table.data_op == STD_OP_EQ ||
3566 appctx->ctx.table.data_op == STD_OP_LT ||
3567 appctx->ctx.table.data_op == STD_OP_LE)))
3568 skip_entry = 1;
3569 }
3570
3571 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003572 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003573 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003574 return 0;
3575 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003576
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003577 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003578
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003579 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003580 appctx->ctx.table.entry->ref_cnt--;
3581
3582 eb = ebmb_next(&appctx->ctx.table.entry->key);
3583 if (eb) {
3584 struct stksess *old = appctx->ctx.table.entry;
3585 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3586 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003587 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003588 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003589 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003590 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003591 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003592 break;
3593 }
3594
3595
3596 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003597 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003598 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003599 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3600
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003601 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003602
3603 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3604 appctx->st2 = STAT_ST_INFO;
3605 break;
3606
3607 case STAT_ST_END:
3608 appctx->st2 = STAT_ST_FIN;
3609 break;
3610 }
3611 }
3612 return 1;
3613}
3614
3615static void cli_release_show_table(struct appctx *appctx)
3616{
3617 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003618 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003619 }
3620}
3621
3622/* register cli keywords */
3623static struct cli_kw_list cli_kws = {{ },{
3624 { { "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 },
3625 { { "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 },
3626 { { "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 },
3627 {{},}
3628}};
3629
Willy Tarreau0108d902018-11-25 19:14:37 +01003630INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003631
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003632static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003633 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003634 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003635 { "sc-set-gpt0", parse_set_gpt0, 1 },
3636 { /* END */ }
3637}};
3638
Willy Tarreau0108d902018-11-25 19:14:37 +01003639INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
3640
Willy Tarreau620408f2016-10-21 16:37:51 +02003641static struct action_kw_list tcp_sess_kws = { { }, {
3642 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003643 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003644 { "sc-set-gpt0", parse_set_gpt0, 1 },
3645 { /* END */ }
3646}};
3647
Willy Tarreau0108d902018-11-25 19:14:37 +01003648INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
3649
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003650static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003651 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003652 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003653 { "sc-set-gpt0", parse_set_gpt0, 1 },
3654 { /* END */ }
3655}};
3656
Willy Tarreau0108d902018-11-25 19:14:37 +01003657INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
3658
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003659static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003660 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003661 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003662 { "sc-set-gpt0", parse_set_gpt0, 1 },
3663 { /* END */ }
3664}};
3665
Willy Tarreau0108d902018-11-25 19:14:37 +01003666INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
3667
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003668static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003669 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003670 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003671 { "sc-set-gpt0", parse_set_gpt0, 1 },
3672 { /* END */ }
3673}};
3674
Willy Tarreau0108d902018-11-25 19:14:37 +01003675INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
3676
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003677static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003678 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003679 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003680 { "sc-set-gpt0", parse_set_gpt0, 1 },
3681 { /* END */ }
3682}};
3683
Willy Tarreau0108d902018-11-25 19:14:37 +01003684INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
3685
Willy Tarreau7d562212016-11-25 16:10:05 +01003686///* Note: must not be declared <const> as its list will be overwritten.
3687// * Please take care of keeping this list alphabetically sorted.
3688// */
3689//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3690// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3691// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3692// { /* END */ },
3693//}};
3694/* Note: must not be declared <const> as its list will be overwritten.
3695 * Please take care of keeping this list alphabetically sorted.
3696 */
3697static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3698 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3699 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3700 { "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 +01003701 { "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 +01003702 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3703 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3704 { "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 +01003705 { "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 +01003706 { "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 +01003707 { "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 +01003708 { "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 +01003709 { "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 +01003710 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3711 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3712 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3713 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3714 { "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 +01003715 { "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 +01003716 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3717 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3718 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3719 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3720 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3721 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3722 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3723 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3724 { "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 +01003725 { "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 +01003726 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3727 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3728 { "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 +01003729 { "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 +01003730 { "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 +01003731 { "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 +01003732 { "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 +01003733 { "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 +01003734 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3735 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3736 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3737 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3738 { "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 +01003739 { "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 +01003740 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3741 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3742 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3743 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3744 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3745 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3746 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3747 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3748 { "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 +01003749 { "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 +01003750 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3751 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3752 { "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 +01003753 { "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 +01003754 { "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 +01003755 { "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 +01003756 { "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 +01003757 { "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 +01003758 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3759 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3760 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3761 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3762 { "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 +01003763 { "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 +01003764 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3765 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3766 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3767 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3768 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3769 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3770 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3771 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3772 { "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 +01003773 { "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 +01003774 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3775 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3776 { "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 +01003777 { "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 +01003778 { "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 +01003779 { "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 +01003780 { "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 +01003781 { "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 +01003782 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3783 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3784 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3785 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3786 { "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 +01003787 { "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 +01003788 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3789 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3790 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3791 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3792 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3793 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3794 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3795 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3796 { "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 +01003797 { "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 +01003798 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3799 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3800 { "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 +01003801 { "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 +01003802 { "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 +01003803 { "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 +01003804 { "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 +01003805 { "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 +01003806 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3807 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3808 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3809 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3810 { "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 +01003811 { "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 +01003812 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3813 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3814 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3815 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3816 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3817 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3818 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3819 { /* END */ },
3820}};
3821
Willy Tarreau0108d902018-11-25 19:14:37 +01003822INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
Willy Tarreau7d562212016-11-25 16:10:05 +01003823
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003824/* Note: must not be declared <const> as its list will be overwritten */
3825static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003826 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3827 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3828 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3829 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3830 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3831 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3832 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3833 { "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 +01003834 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003835 { "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 +01003836 { "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 +02003837 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3838 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3839 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3840 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3841 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3842 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3843 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3844 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3845 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3846 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003847 { /* END */ },
3848}};
3849
Willy Tarreau0108d902018-11-25 19:14:37 +01003850INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);