blob: fe26e31214181d22cbf6be2a07150d4e078e1c7d [file] [log] [blame]
Emeric Brun3bd697e2010-01-04 15:23:48 +01001/*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreau08d5f982010-06-06 13:34:54 +02005 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
Emeric Brun3bd697e2010-01-04 15:23:48 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010015#include <errno.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010016
17#include <common/config.h>
18#include <common/memory.h>
19#include <common/mini-clist.h>
20#include <common/standard.h>
21#include <common/time.h>
22
23#include <ebmbtree.h>
24#include <ebsttree.h>
25
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010026#include <types/cli.h>
Willy Tarreau39713102016-11-25 15:49:32 +010027#include <types/global.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010028#include <types/stats.h>
29
Willy Tarreaud9f316a2014-07-10 14:03:38 +020030#include <proto/arg.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010031#include <proto/cli.h>
Andjelko Iharosc3680ec2017-07-20 16:49:14 +020032#include <proto/log.h>
Thierry FOURNIER236657b2015-08-19 08:25:14 +020033#include <proto/proto_http.h>
Willy Tarreau7d562212016-11-25 16:10:05 +010034#include <proto/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010035#include <proto/proxy.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020036#include <proto/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020037#include <proto/stream.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010038#include <proto/stream_interface.h>
Willy Tarreau68129b92010-06-06 16:06:52 +020039#include <proto/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010040#include <proto/task.h>
Emeric Brun32da3c42010-09-23 18:39:19 +020041#include <proto/peers.h>
Willy Tarreau39713102016-11-25 15:49:32 +010042#include <proto/tcp_rules.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010043
Willy Tarreau12785782012-04-27 21:37:17 +020044/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020045static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020046
Emeric Brun3bd697e2010-01-04 15:23:48 +010047/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020048 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
49 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010050 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020051void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010052{
53 t->current--;
Willy Tarreaubafbe012017-11-24 17:34:44 +010054 pool_free(t->pool, (void *)ts - t->data_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +010055}
56
57/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020058 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
59 * in table <t>.
60 * This function locks the table
61 */
62void stksess_free(struct stktable *t, struct stksess *ts)
63{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010064 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020065 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010066 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020067}
68
69/*
Willy Tarreauf6efda12010-08-03 20:34:06 +020070 * Kill an stksess (only if its ref_cnt is zero).
71 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020072int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +020073{
74 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +020075 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +020076
77 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +020078 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +020079 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +020080 __stksess_free(t, ts);
81 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +020082}
83
84/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020085 * Decrease the refcount if decrefcnt is not 0.
86 * and try to kill the stksess
87 * This function locks the table
88 */
89int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
90{
91 int ret;
92
Christopher Faulet2a944ee2017-11-07 10:42:54 +010093 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020094 if (decrefcnt)
95 ts->ref_cnt--;
96 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010097 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020098
99 return ret;
100}
101
102/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200103 * Initialize or update the key in the sticky session <ts> present in table <t>
104 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100105 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200106void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100107{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200108 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200109 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100110 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200111 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
112 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100113 }
114}
115
116
117/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200118 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
119 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100120 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200121static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100122{
Willy Tarreau393379c2010-06-06 12:11:37 +0200123 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200124 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200125 ts->key.node.leaf_p = NULL;
126 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200127 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200128 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100129 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100130 return ts;
131}
132
133/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200134 * Trash oldest <to_batch> sticky sessions from table <t>
135 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100136 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200137int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100138{
139 struct stksess *ts;
140 struct eb32_node *eb;
141 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200142 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100143
144 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
145
146 while (batched < to_batch) {
147
148 if (unlikely(!eb)) {
149 /* we might have reached the end of the tree, typically because
150 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200151 * half. Let's loop back to the beginning of the tree now if we
152 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100153 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200154 if (looped)
155 break;
156 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100157 eb = eb32_first(&t->exps);
158 if (likely(!eb))
159 break;
160 }
161
162 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200163 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100164 eb = eb32_next(eb);
165
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200166 /* don't delete an entry which is currently referenced */
167 if (ts->ref_cnt)
168 continue;
169
Willy Tarreau86257dc2010-06-06 12:57:10 +0200170 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100171
Willy Tarreau86257dc2010-06-06 12:57:10 +0200172 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100173 if (!tick_isset(ts->expire))
174 continue;
175
Willy Tarreau86257dc2010-06-06 12:57:10 +0200176 ts->exp.key = ts->expire;
177 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100178
Willy Tarreau86257dc2010-06-06 12:57:10 +0200179 if (!eb || eb->key > ts->exp.key)
180 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100181
182 continue;
183 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100184
Willy Tarreauaea940e2010-06-06 11:56:36 +0200185 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200186 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200187 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200188 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100189 batched++;
190 }
191
192 return batched;
193}
194
195/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200196 * Trash oldest <to_batch> sticky sessions from table <t>
197 * Returns number of trashed sticky sessions.
198 * This function locks the table
199 */
200int stktable_trash_oldest(struct stktable *t, int to_batch)
201{
202 int ret;
203
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100204 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200205 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100206 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200207
208 return ret;
209}
210/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200211 * Allocate and initialise a new sticky session.
212 * The new sticky session is returned or NULL in case of lack of memory.
213 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200214 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
215 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100216 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200217struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100218{
219 struct stksess *ts;
220
221 if (unlikely(t->current == t->size)) {
222 if ( t->nopurge )
223 return NULL;
224
Emeric Brun819fc6f2017-06-13 19:37:32 +0200225 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100226 return NULL;
227 }
228
Willy Tarreaubafbe012017-11-24 17:34:44 +0100229 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100230 if (ts) {
231 t->current++;
Willy Tarreau51791462016-11-18 18:21:39 +0100232 ts = (void *)ts + t->data_size;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200233 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200234 if (key)
235 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100236 }
237
238 return ts;
239}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200240/*
241 * Allocate and initialise a new sticky session.
242 * The new sticky session is returned or NULL in case of lack of memory.
243 * Sticky sessions should only be allocated this way, and must be freed using
244 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
245 * is not NULL, it is assigned to the new session.
246 * This function locks the table
247 */
248struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
249{
250 struct stksess *ts;
251
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100252 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200253 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100254 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200255
256 return ts;
257}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100258
259/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200260 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200261 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100262 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200263struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100264{
265 struct ebmb_node *eb;
266
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200267 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200268 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 +0100269 else
270 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
271
272 if (unlikely(!eb)) {
273 /* no session found */
274 return NULL;
275 }
276
Willy Tarreau86257dc2010-06-06 12:57:10 +0200277 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100278}
279
Emeric Brun819fc6f2017-06-13 19:37:32 +0200280/*
281 * Looks in table <t> for a sticky session matching key <key>.
282 * Returns pointer on requested sticky session or NULL if none was found.
283 * The refcount of the found entry is increased and this function
284 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200285 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200286struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200287{
288 struct stksess *ts;
289
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100290 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200291 ts = __stktable_lookup_key(t, key);
292 if (ts)
293 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100294 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200295
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200296 return ts;
297}
298
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200299/*
300 * Looks in table <t> for a sticky session with same key as <ts>.
301 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100302 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200303struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100304{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100305 struct ebmb_node *eb;
306
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200307 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200308 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100309 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200310 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100311
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200312 if (unlikely(!eb))
313 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100314
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200315 return ebmb_entry(eb, struct stksess, key);
316}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100317
Emeric Brun819fc6f2017-06-13 19:37:32 +0200318/*
319 * Looks in table <t> for a sticky session with same key as <ts>.
320 * Returns pointer on requested sticky session or NULL if none was found.
321 * The refcount of the found entry is increased and this function
322 * is protected using the table lock
323 */
324struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
325{
326 struct stksess *lts;
327
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100328 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200329 lts = __stktable_lookup(t, ts);
330 if (lts)
331 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100332 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200333
334 return lts;
335}
336
Willy Tarreaucb183642010-06-06 17:58:34 +0200337/* Update the expiration timer for <ts> but do not touch its expiration node.
338 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200339 * The node will be also inserted into the update tree if needed, at a position
340 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200341 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200342void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200343{
Emeric Brun85e77c72010-09-23 18:16:52 +0200344 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200345 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200346 if (t->expire) {
347 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
348 task_queue(t->exp_task);
349 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200350
Emeric Brun819fc6f2017-06-13 19:37:32 +0200351 /* If sync is enabled */
352 if (t->sync_task) {
353 if (local) {
354 /* If this entry is not in the tree
355 or not scheduled for at least one peer */
356 if (!ts->upd.node.leaf_p
357 || (int)(t->commitupdate - ts->upd.key) >= 0
358 || (int)(ts->upd.key - t->localupdate) >= 0) {
359 ts->upd.key = ++t->update;
360 t->localupdate = t->update;
361 eb32_delete(&ts->upd);
362 eb = eb32_insert(&t->updates, &ts->upd);
363 if (eb != &ts->upd) {
364 eb32_delete(eb);
365 eb32_insert(&t->updates, &ts->upd);
366 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200367 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200368 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200369 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200370 else {
371 /* If this entry is not in the tree */
372 if (!ts->upd.node.leaf_p) {
373 ts->upd.key= (++t->update)+(2147483648U);
374 eb = eb32_insert(&t->updates, &ts->upd);
375 if (eb != &ts->upd) {
376 eb32_delete(eb);
377 eb32_insert(&t->updates, &ts->upd);
378 }
379 }
380 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200381 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200382}
383
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200384/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200385 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200386 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200387 * The node will be also inserted into the update tree if needed, at a position
388 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200389 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200390void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
391{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100392 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200393 __stktable_touch_with_exp(t, ts, 0, ts->expire);
394 if (decrefcnt)
395 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100396 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200397}
398
399/* Update the expiration timer for <ts> but do not touch its expiration node.
400 * The table's expiration timer is updated using the date of expiration coming from
401 * <t> stick-table configuration.
402 * The node will be also inserted into the update tree if needed, at a position
403 * considering the update was made locally
404 */
405void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200406{
407 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
408
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100409 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200410 __stktable_touch_with_exp(t, ts, 1, expire);
411 if (decrefcnt)
412 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100413 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200414}
415/* Just decrease the ref_cnt of the current session */
416void stktable_release(struct stktable *t, struct stksess *ts)
417{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100418 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200419 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100420 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200421}
422
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200423/* Insert new sticky session <ts> in the table. It is assumed that it does not
424 * yet exist (the caller must check this). The table's timeout is updated if it
425 * is set. <ts> is returned.
426 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200427void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200428{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100429
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200430 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200431 ts->exp.key = ts->expire;
432 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 if (t->expire) {
434 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
435 task_queue(t->exp_task);
436 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200437}
438
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200439/* Returns a valid or initialized stksess for the specified stktable_key in the
440 * specified table, or NULL if the key was NULL, or if no entry was found nor
441 * could be created. The entry's expiration is updated.
442 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200443struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200444{
445 struct stksess *ts;
446
447 if (!key)
448 return NULL;
449
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200451 if (ts == NULL) {
452 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200454 if (!ts)
455 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200457 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200458 return ts;
459}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460/* Returns a valid or initialized stksess for the specified stktable_key in the
461 * specified table, or NULL if the key was NULL, or if no entry was found nor
462 * could be created. The entry's expiration is updated.
463 * This function locks the table, and the refcount of the entry is increased.
464 */
465struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
466{
467 struct stksess *ts;
468
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100469 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200470 ts = __stktable_get_entry(table, key);
471 if (ts)
472 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100473 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200474
475 return ts;
476}
477
478/* Lookup for an entry with the same key and store the submitted
479 * stksess if not found.
480 */
481struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
482{
483 struct stksess *ts;
484
485 ts = __stktable_lookup(table, nts);
486 if (ts == NULL) {
487 ts = nts;
488 __stktable_store(table, ts);
489 }
490 return ts;
491}
492
493/* Lookup for an entry with the same key and store the submitted
494 * stksess if not found.
495 * This function locks the table, and the refcount of the entry is increased.
496 */
497struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
498{
499 struct stksess *ts;
500
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100501 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200502 ts = __stktable_set_entry(table, nts);
503 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100504 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200505
Emeric Brun819fc6f2017-06-13 19:37:32 +0200506 return ts;
507}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100508/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200509 * Trash expired sticky sessions from table <t>. The next expiration date is
510 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100511 */
512static int stktable_trash_expired(struct stktable *t)
513{
514 struct stksess *ts;
515 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200516 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100517
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100518 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100519 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
520
521 while (1) {
522 if (unlikely(!eb)) {
523 /* we might have reached the end of the tree, typically because
524 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200525 * half. Let's loop back to the beginning of the tree now if we
526 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100527 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200528 if (looped)
529 break;
530 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100531 eb = eb32_first(&t->exps);
532 if (likely(!eb))
533 break;
534 }
535
536 if (likely(tick_is_lt(now_ms, eb->key))) {
537 /* timer not expired yet, revisit it later */
538 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100539 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100540 }
541
542 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200543 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100544 eb = eb32_next(eb);
545
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200546 /* don't delete an entry which is currently referenced */
547 if (ts->ref_cnt)
548 continue;
549
Willy Tarreau86257dc2010-06-06 12:57:10 +0200550 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100551
552 if (!tick_is_expired(ts->expire, now_ms)) {
553 if (!tick_isset(ts->expire))
554 continue;
555
Willy Tarreau86257dc2010-06-06 12:57:10 +0200556 ts->exp.key = ts->expire;
557 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100558
Willy Tarreau86257dc2010-06-06 12:57:10 +0200559 if (!eb || eb->key > ts->exp.key)
560 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100561 continue;
562 }
563
564 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200565 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200566 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200567 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100568 }
569
570 /* We have found no task to expire in any tree */
571 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100572out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100573 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100574 return t->exp_next;
575}
576
577/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200578 * Task processing function to trash expired sticky sessions. A pointer to the
579 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100580 */
Willy Tarreauaea940e2010-06-06 11:56:36 +0200581static struct task *process_table_expire(struct task *task)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100582{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200583 struct stktable *t = task->context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100584
585 task->expire = stktable_trash_expired(t);
586 return task;
587}
588
Willy Tarreauaea940e2010-06-06 11:56:36 +0200589/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100590int stktable_init(struct stktable *t)
591{
592 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200593 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100594 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100595 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100596 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100597
Willy Tarreau393379c2010-06-06 12:11:37 +0200598 t->pool = create_pool("sticktables", sizeof(struct stksess) + t->data_size + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
600 t->exp_next = TICK_ETERNITY;
601 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200602 t->exp_task = task_new(MAX_THREADS_MASK);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100603 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100604 t->exp_task->context = (void *)t;
605 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200606 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200607 peers_register_table(t->peers.p, t);
608 }
609
Emeric Brun3bd697e2010-01-04 15:23:48 +0100610 return t->pool != NULL;
611 }
612 return 1;
613}
614
615/*
616 * Configuration keywords of known table types
617 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200618struct stktable_type stktable_types[SMP_TYPES] = {
619 [SMP_T_SINT] = { "integer", 0, 4 },
620 [SMP_T_IPV4] = { "ip", 0, 4 },
621 [SMP_T_IPV6] = { "ipv6", 0, 16 },
622 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
623 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
624};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100625
626/*
627 * Parse table type configuration.
628 * Returns 0 on successful parsing, else 1.
629 * <myidx> is set at next configuration <args> index.
630 */
631int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
632{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200633 for (*type = 0; *type < SMP_TYPES; (*type)++) {
634 if (!stktable_types[*type].kw)
635 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100636 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
637 continue;
638
639 *key_size = stktable_types[*type].default_size;
640 (*myidx)++;
641
Willy Tarreauaea940e2010-06-06 11:56:36 +0200642 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 if (strcmp("len", args[*myidx]) == 0) {
644 (*myidx)++;
645 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200646 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200648 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200649 /* null terminated string needs +1 for '\0'. */
650 (*key_size)++;
651 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100652 (*myidx)++;
653 }
654 }
655 return 0;
656 }
657 return 1;
658}
659
Willy Tarreau8fed9032014-07-03 17:02:46 +0200660/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200661 * Note that the sample *is* modified and that the returned key may point
662 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200663 * Returns NULL if the sample could not be converted (eg: no matching type),
664 * otherwise a pointer to the static stktable_key filled with what is needed
665 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200666 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200667struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200668{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200669 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200670 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200671 return NULL;
672
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200673 /* Fill static_table_key. */
674 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200675
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200676 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200677 static_table_key.key = &smp->data.u.ipv4;
678 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200679 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200680
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200681 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200682 static_table_key.key = &smp->data.u.ipv6;
683 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200684 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200685
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200686 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200687 /* The stick table require a 32bit unsigned int, "sint" is a
688 * signed 64 it, so we can convert it inplace.
689 */
690 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200691 static_table_key.key = &smp->data.u.sint;
692 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200693 break;
694
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200695 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200696 if (!smp_make_safe(smp))
697 return NULL;
Christopher Fauletca20d022017-08-29 15:30:31 +0200698 static_table_key.key = smp->data.u.str.str;
699 static_table_key.key_len = smp->data.u.str.len;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200700 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200701
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200702 case SMP_T_BIN:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200703 if (smp->data.u.str.len < t->key_size) {
704 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200705 if (!smp_make_rw(smp))
706 return NULL;
707
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200708 if (smp->data.u.str.size < t->key_size)
709 if (!smp_dup(smp))
710 return NULL;
711 if (smp->data.u.str.size < t->key_size)
712 return NULL;
713 memset(smp->data.u.str.str + smp->data.u.str.len, 0,
714 t->key_size - smp->data.u.str.len);
715 smp->data.u.str.len = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200716 }
Christopher Fauletca20d022017-08-29 15:30:31 +0200717 static_table_key.key = smp->data.u.str.str;
718 static_table_key.key_len = smp->data.u.str.len;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200719 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200720
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200721 default: /* impossible case. */
722 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200723 }
724
Christopher Fauletca20d022017-08-29 15:30:31 +0200725 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200726}
727
728/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200729 * Process a fetch + format conversion as defined by the sample expression <expr>
730 * on request or response considering the <opt> parameter. Returns either NULL if
731 * no key could be extracted, or a pointer to the converted result stored in
732 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
733 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200734 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
735 * without SMP_OPT_FINAL). The output will be usable like this :
736 *
737 * return MAY_CHANGE FINAL Meaning for the sample
738 * NULL 0 * Not present and will never be (eg: header)
739 * NULL 1 0 Not present or unstable, could change (eg: req_len)
740 * NULL 1 1 Not present, will not change anymore
741 * smp 0 * Present and will not change (eg: header)
742 * smp 1 0 not possible
743 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200744 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200745struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200746 unsigned int opt, struct sample_expr *expr, struct sample *smp)
747{
748 if (smp)
749 memset(smp, 0, sizeof(*smp));
750
Willy Tarreau192252e2015-04-04 01:47:55 +0200751 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200752 if (!smp)
753 return NULL;
754
755 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
756 return NULL; /* we can only use stable samples */
757
758 return smp_to_stkey(smp, t);
759}
760
761/*
Willy Tarreau12785782012-04-27 21:37:17 +0200762 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200763 * type <table_type>, otherwise zero. Used in configuration check.
764 */
Willy Tarreau12785782012-04-27 21:37:17 +0200765int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200766{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100767 int out_type;
768
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200769 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200770 return 0;
771
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100772 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200773
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200774 /* Convert sample. */
775 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100776 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200777
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200778 return 1;
779}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100780
Willy Tarreauedee1d62014-07-15 16:44:27 +0200781/* Extra data types processing : after the last one, some room may remain
782 * before STKTABLE_DATA_TYPES that may be used to register extra data types
783 * at run time.
784 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200785struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200786 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200787 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200788 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200789 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200790 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
791 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
792 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
793 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
794 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
795 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
796 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
797 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
798 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
799 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
800 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
801 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
802 [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 +0100803 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
804 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +0200805};
806
Willy Tarreauedee1d62014-07-15 16:44:27 +0200807/* Registers stick-table extra data type with index <idx>, name <name>, type
808 * <std_type> and arg type <arg_type>. If the index is negative, the next free
809 * index is automatically allocated. The allocated index is returned, or -1 if
810 * no free index was found or <name> was already registered. The <name> is used
811 * directly as a pointer, so if it's not stable, the caller must allocate it.
812 */
813int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
814{
815 if (idx < 0) {
816 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
817 if (!stktable_data_types[idx].name)
818 break;
819
820 if (strcmp(stktable_data_types[idx].name, name) == 0)
821 return -1;
822 }
823 }
824
825 if (idx >= STKTABLE_DATA_TYPES)
826 return -1;
827
828 if (stktable_data_types[idx].name != NULL)
829 return -1;
830
831 stktable_data_types[idx].name = name;
832 stktable_data_types[idx].std_type = std_type;
833 stktable_data_types[idx].arg_type = arg_type;
834 return idx;
835}
836
Willy Tarreau08d5f982010-06-06 13:34:54 +0200837/*
838 * Returns the data type number for the stktable_data_type whose name is <name>,
839 * or <0 if not found.
840 */
841int stktable_get_data_type(char *name)
842{
843 int type;
844
845 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +0200846 if (!stktable_data_types[type].name)
847 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +0200848 if (strcmp(name, stktable_data_types[type].name) == 0)
849 return type;
850 }
851 return -1;
852}
853
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200854/* Casts sample <smp> to the type of the table specified in arg(0), and looks
855 * it up into this table. Returns true if found, false otherwise. The input
856 * type is STR so that input samples are converted to string (since all types
857 * can be converted to strings), then the function casts the string again into
858 * the table's type. This is a double conversion, but in the future we might
859 * support automatic input types to perform the cast on the fly.
860 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200861static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200862{
863 struct stktable *t;
864 struct stktable_key *key;
865 struct stksess *ts;
866
867 t = &arg_p[0].data.prx->table;
868
869 key = smp_to_stkey(smp, t);
870 if (!key)
871 return 0;
872
873 ts = stktable_lookup_key(t, key);
874
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200875 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200876 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200877 smp->flags = SMP_F_VOL_TEST;
878 return 1;
879}
880
881/* Casts sample <smp> to the type of the table specified in arg(0), and looks
882 * it up into this table. Returns the data rate received from clients in bytes/s
883 * if the key is present in the table, otherwise zero, so that comparisons can
884 * be easily performed. If the inspected parameter is not stored in the table,
885 * <not found> is returned.
886 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200887static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200888{
889 struct stktable *t;
890 struct stktable_key *key;
891 struct stksess *ts;
892 void *ptr;
893
894 t = &arg_p[0].data.prx->table;
895
896 key = smp_to_stkey(smp, t);
897 if (!key)
898 return 0;
899
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200900 ts = stktable_lookup_key(t, key);
901
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200902 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200903 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200904 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200905
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200906 if (!ts) /* key not present */
907 return 1;
908
909 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
910 if (!ptr)
911 return 0; /* parameter not stored */
912
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200913 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200914 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
915 return 1;
916}
917
918/* Casts sample <smp> to the type of the table specified in arg(0), and looks
919 * it up into this table. Returns the cumulated number of connections for the key
920 * if the key is present in the table, otherwise zero, so that comparisons can
921 * be easily performed. If the inspected parameter is not stored in the table,
922 * <not found> is returned.
923 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200924static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200925{
926 struct stktable *t;
927 struct stktable_key *key;
928 struct stksess *ts;
929 void *ptr;
930
931 t = &arg_p[0].data.prx->table;
932
933 key = smp_to_stkey(smp, t);
934 if (!key)
935 return 0;
936
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200937 ts = stktable_lookup_key(t, key);
938
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200939 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200940 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200941 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200942
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200943 if (!ts) /* key not present */
944 return 1;
945
946 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
947 if (!ptr)
948 return 0; /* parameter not stored */
949
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200950 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200951 return 1;
952}
953
954/* Casts sample <smp> to the type of the table specified in arg(0), and looks
955 * it up into this table. Returns the number of concurrent connections for the
956 * key if the key is present in the table, otherwise zero, so that comparisons
957 * can be easily performed. If the inspected parameter is not stored in the
958 * table, <not found> is returned.
959 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200960static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200961{
962 struct stktable *t;
963 struct stktable_key *key;
964 struct stksess *ts;
965 void *ptr;
966
967 t = &arg_p[0].data.prx->table;
968
969 key = smp_to_stkey(smp, t);
970 if (!key)
971 return 0;
972
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200973 ts = stktable_lookup_key(t, key);
974
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200975 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200976 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200977 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200978
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200979 if (!ts) /* key not present */
980 return 1;
981
982 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
983 if (!ptr)
984 return 0; /* parameter not stored */
985
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200986 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200987 return 1;
988}
989
990/* Casts sample <smp> to the type of the table specified in arg(0), and looks
991 * it up into this table. Returns the rate of incoming connections from the key
992 * if the key is present in the table, otherwise zero, so that comparisons can
993 * be easily performed. If the inspected parameter is not stored in the table,
994 * <not found> is returned.
995 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200996static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200997{
998 struct stktable *t;
999 struct stktable_key *key;
1000 struct stksess *ts;
1001 void *ptr;
1002
1003 t = &arg_p[0].data.prx->table;
1004
1005 key = smp_to_stkey(smp, t);
1006 if (!key)
1007 return 0;
1008
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001009 ts = stktable_lookup_key(t, key);
1010
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001011 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001012 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001013 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001014
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001015 if (!ts) /* key not present */
1016 return 1;
1017
1018 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
1019 if (!ptr)
1020 return 0; /* parameter not stored */
1021
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001022 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001023 t->data_arg[STKTABLE_DT_CONN_RATE].u);
1024 return 1;
1025}
1026
1027/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1028 * it up into this table. Returns the data rate sent to clients in bytes/s
1029 * if the key is present in the table, otherwise zero, so that comparisons can
1030 * be easily performed. If the inspected parameter is not stored in the table,
1031 * <not found> is returned.
1032 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001033static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001034{
1035 struct stktable *t;
1036 struct stktable_key *key;
1037 struct stksess *ts;
1038 void *ptr;
1039
1040 t = &arg_p[0].data.prx->table;
1041
1042 key = smp_to_stkey(smp, t);
1043 if (!key)
1044 return 0;
1045
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001046 ts = stktable_lookup_key(t, key);
1047
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001048 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001049 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001050 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001051
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001052 if (!ts) /* key not present */
1053 return 1;
1054
1055 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
1056 if (!ptr)
1057 return 0; /* parameter not stored */
1058
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001059 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001060 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
1061 return 1;
1062}
1063
1064/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001065 * it up into this table. Returns the value of the GPT0 tag for the key
1066 * if the key is present in the table, otherwise false, so that comparisons can
1067 * be easily performed. If the inspected parameter is not stored in the table,
1068 * <not found> is returned.
1069 */
1070static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1071{
1072 struct stktable *t;
1073 struct stktable_key *key;
1074 struct stksess *ts;
1075 void *ptr;
1076
1077 t = &arg_p[0].data.prx->table;
1078
1079 key = smp_to_stkey(smp, t);
1080 if (!key)
1081 return 0;
1082
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001083 ts = stktable_lookup_key(t, key);
1084
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001085 smp->flags = SMP_F_VOL_TEST;
1086 smp->data.type = SMP_T_SINT;
1087 smp->data.u.sint = 0;
1088
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001089 if (!ts) /* key not present */
1090 return 1;
1091
1092 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
1093 if (!ptr)
1094 return 0; /* parameter not stored */
1095
1096 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
1097 return 1;
1098}
1099
1100/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001101 * it up into this table. Returns the value of the GPC0 counter for the key
1102 * if the key is present in the table, otherwise zero, so that comparisons can
1103 * be easily performed. If the inspected parameter is not stored in the table,
1104 * <not found> is returned.
1105 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001106static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001107{
1108 struct stktable *t;
1109 struct stktable_key *key;
1110 struct stksess *ts;
1111 void *ptr;
1112
1113 t = &arg_p[0].data.prx->table;
1114
1115 key = smp_to_stkey(smp, t);
1116 if (!key)
1117 return 0;
1118
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001119 ts = stktable_lookup_key(t, key);
1120
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001121 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001122 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001123 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001124
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001125 if (!ts) /* key not present */
1126 return 1;
1127
1128 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
1129 if (!ptr)
1130 return 0; /* parameter not stored */
1131
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001132 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001133 return 1;
1134}
1135
1136/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1137 * it up into this table. Returns the event rate of the GPC0 counter for the key
1138 * if the key is present in the table, otherwise zero, so that comparisons can
1139 * be easily performed. If the inspected parameter is not stored in the table,
1140 * <not found> is returned.
1141 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001142static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001143{
1144 struct stktable *t;
1145 struct stktable_key *key;
1146 struct stksess *ts;
1147 void *ptr;
1148
1149 t = &arg_p[0].data.prx->table;
1150
1151 key = smp_to_stkey(smp, t);
1152 if (!key)
1153 return 0;
1154
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001155 ts = stktable_lookup_key(t, key);
1156
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001157 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001158 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001159 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001160
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001161 if (!ts) /* key not present */
1162 return 1;
1163
1164 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
1165 if (!ptr)
1166 return 0; /* parameter not stored */
1167
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001168 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001169 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
1170 return 1;
1171}
1172
1173/* 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 +01001174 * it up into this table. Returns the value of the GPC1 counter for the key
1175 * if the key is present in the table, otherwise zero, so that comparisons can
1176 * be easily performed. If the inspected parameter is not stored in the table,
1177 * <not found> is returned.
1178 */
1179static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1180{
1181 struct stktable *t;
1182 struct stktable_key *key;
1183 struct stksess *ts;
1184 void *ptr;
1185
1186 t = &arg_p[0].data.prx->table;
1187
1188 key = smp_to_stkey(smp, t);
1189 if (!key)
1190 return 0;
1191
1192 ts = stktable_lookup_key(t, key);
1193
1194 smp->flags = SMP_F_VOL_TEST;
1195 smp->data.type = SMP_T_SINT;
1196 smp->data.u.sint = 0;
1197
1198 if (!ts) /* key not present */
1199 return 1;
1200
1201 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
1202 if (!ptr)
1203 return 0; /* parameter not stored */
1204
1205 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
1206 return 1;
1207}
1208
1209/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1210 * it up into this table. Returns the event rate of the GPC1 counter for the key
1211 * if the key is present in the table, otherwise zero, so that comparisons can
1212 * be easily performed. If the inspected parameter is not stored in the table,
1213 * <not found> is returned.
1214 */
1215static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1216{
1217 struct stktable *t;
1218 struct stktable_key *key;
1219 struct stksess *ts;
1220 void *ptr;
1221
1222 t = &arg_p[0].data.prx->table;
1223
1224 key = smp_to_stkey(smp, t);
1225 if (!key)
1226 return 0;
1227
1228 ts = stktable_lookup_key(t, key);
1229
1230 smp->flags = SMP_F_VOL_TEST;
1231 smp->data.type = SMP_T_SINT;
1232 smp->data.u.sint = 0;
1233
1234 if (!ts) /* key not present */
1235 return 1;
1236
1237 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
1238 if (!ptr)
1239 return 0; /* parameter not stored */
1240
1241 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1242 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
1243 return 1;
1244}
1245
1246/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001247 * it up into this table. Returns the cumulated number of HTTP request errors
1248 * for the key if the key is present in the table, otherwise zero, so that
1249 * comparisons can be easily performed. If the inspected parameter is not stored
1250 * in the table, <not found> is returned.
1251 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001252static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001253{
1254 struct stktable *t;
1255 struct stktable_key *key;
1256 struct stksess *ts;
1257 void *ptr;
1258
1259 t = &arg_p[0].data.prx->table;
1260
1261 key = smp_to_stkey(smp, t);
1262 if (!key)
1263 return 0;
1264
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001265 ts = stktable_lookup_key(t, key);
1266
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001267 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001268 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001269 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001270
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271 if (!ts) /* key not present */
1272 return 1;
1273
1274 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
1275 if (!ptr)
1276 return 0; /* parameter not stored */
1277
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001278 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001279 return 1;
1280}
1281
1282/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1283 * it up into this table. Returns the HTTP request error rate the key
1284 * if the key is present in the table, otherwise zero, so that comparisons can
1285 * be easily performed. If the inspected parameter is not stored in the table,
1286 * <not found> is returned.
1287 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001288static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001289{
1290 struct stktable *t;
1291 struct stktable_key *key;
1292 struct stksess *ts;
1293 void *ptr;
1294
1295 t = &arg_p[0].data.prx->table;
1296
1297 key = smp_to_stkey(smp, t);
1298 if (!key)
1299 return 0;
1300
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001301 ts = stktable_lookup_key(t, key);
1302
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001303 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001304 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001305 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001306
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307 if (!ts) /* key not present */
1308 return 1;
1309
1310 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
1311 if (!ptr)
1312 return 0; /* parameter not stored */
1313
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001314 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
1316 return 1;
1317}
1318
1319/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1320 * it up into this table. Returns the cumulated number of HTTP request for the
1321 * key if the key is present in the table, otherwise zero, so that comparisons
1322 * can be easily performed. If the inspected parameter is not stored in the
1323 * table, <not found> is returned.
1324 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001325static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001326{
1327 struct stktable *t;
1328 struct stktable_key *key;
1329 struct stksess *ts;
1330 void *ptr;
1331
1332 t = &arg_p[0].data.prx->table;
1333
1334 key = smp_to_stkey(smp, t);
1335 if (!key)
1336 return 0;
1337
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001338 ts = stktable_lookup_key(t, key);
1339
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001340 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001341 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001342 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344 if (!ts) /* key not present */
1345 return 1;
1346
1347 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
1348 if (!ptr)
1349 return 0; /* parameter not stored */
1350
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001351 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001352 return 1;
1353}
1354
1355/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1356 * it up into this table. Returns the HTTP request rate the key if the key is
1357 * present in the table, otherwise zero, so that comparisons can be easily
1358 * performed. If the inspected parameter is not stored in the table, <not found>
1359 * is returned.
1360 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001361static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001362{
1363 struct stktable *t;
1364 struct stktable_key *key;
1365 struct stksess *ts;
1366 void *ptr;
1367
1368 t = &arg_p[0].data.prx->table;
1369
1370 key = smp_to_stkey(smp, t);
1371 if (!key)
1372 return 0;
1373
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001374 ts = stktable_lookup_key(t, key);
1375
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001376 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001377 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001378 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380 if (!ts) /* key not present */
1381 return 1;
1382
1383 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
1384 if (!ptr)
1385 return 0; /* parameter not stored */
1386
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001387 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001388 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
1389 return 1;
1390}
1391
1392/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1393 * it up into this table. Returns the volume of datareceived from clients in kbytes
1394 * if the key is present in the table, otherwise zero, so that comparisons can
1395 * be easily performed. If the inspected parameter is not stored in the table,
1396 * <not found> is returned.
1397 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001398static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001399{
1400 struct stktable *t;
1401 struct stktable_key *key;
1402 struct stksess *ts;
1403 void *ptr;
1404
1405 t = &arg_p[0].data.prx->table;
1406
1407 key = smp_to_stkey(smp, t);
1408 if (!key)
1409 return 0;
1410
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001411 ts = stktable_lookup_key(t, key);
1412
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001413 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001414 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001415 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001416
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417 if (!ts) /* key not present */
1418 return 1;
1419
1420 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
1421 if (!ptr)
1422 return 0; /* parameter not stored */
1423
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001424 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001425 return 1;
1426}
1427
1428/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1429 * it up into this table. Returns the volume of data sent to clients in kbytes
1430 * if the key is present in the table, otherwise zero, so that comparisons can
1431 * be easily performed. If the inspected parameter is not stored in the table,
1432 * <not found> is returned.
1433 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001434static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001435{
1436 struct stktable *t;
1437 struct stktable_key *key;
1438 struct stksess *ts;
1439 void *ptr;
1440
1441 t = &arg_p[0].data.prx->table;
1442
1443 key = smp_to_stkey(smp, t);
1444 if (!key)
1445 return 0;
1446
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001447 ts = stktable_lookup_key(t, key);
1448
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001449 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001450 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001451 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001452
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453 if (!ts) /* key not present */
1454 return 1;
1455
1456 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
1457 if (!ptr)
1458 return 0; /* parameter not stored */
1459
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001460 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001461 return 1;
1462}
1463
1464/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1465 * it up into this table. Returns the server ID associated with the key if the
1466 * key is present in the table, otherwise zero, so that comparisons can be
1467 * easily performed. If the inspected parameter is not stored in the table,
1468 * <not found> is returned.
1469 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001470static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001471{
1472 struct stktable *t;
1473 struct stktable_key *key;
1474 struct stksess *ts;
1475 void *ptr;
1476
1477 t = &arg_p[0].data.prx->table;
1478
1479 key = smp_to_stkey(smp, t);
1480 if (!key)
1481 return 0;
1482
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001483 ts = stktable_lookup_key(t, key);
1484
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001485 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001486 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001487 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001488
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001489 if (!ts) /* key not present */
1490 return 1;
1491
1492 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
1493 if (!ptr)
1494 return 0; /* parameter not stored */
1495
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001496 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001497 return 1;
1498}
1499
1500/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1501 * it up into this table. Returns the cumulated number of sessions for the
1502 * key if the key is present in the table, otherwise zero, so that comparisons
1503 * can be easily performed. If the inspected parameter is not stored in the
1504 * table, <not found> is returned.
1505 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001506static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001507{
1508 struct stktable *t;
1509 struct stktable_key *key;
1510 struct stksess *ts;
1511 void *ptr;
1512
1513 t = &arg_p[0].data.prx->table;
1514
1515 key = smp_to_stkey(smp, t);
1516 if (!key)
1517 return 0;
1518
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001519 ts = stktable_lookup_key(t, key);
1520
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001521 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001522 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001523 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001524
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001525 if (!ts) /* key not present */
1526 return 1;
1527
1528 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
1529 if (!ptr)
1530 return 0; /* parameter not stored */
1531
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001532 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001533 return 1;
1534}
1535
1536/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1537 * it up into this table. Returns the session rate the key if the key is
1538 * present in the table, otherwise zero, so that comparisons can be easily
1539 * performed. If the inspected parameter is not stored in the table, <not found>
1540 * is returned.
1541 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001542static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001543{
1544 struct stktable *t;
1545 struct stktable_key *key;
1546 struct stksess *ts;
1547 void *ptr;
1548
1549 t = &arg_p[0].data.prx->table;
1550
1551 key = smp_to_stkey(smp, t);
1552 if (!key)
1553 return 0;
1554
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001555 ts = stktable_lookup_key(t, key);
1556
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001557 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001558 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001559 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001560
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001561 if (!ts) /* key not present */
1562 return 1;
1563
1564 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
1565 if (!ptr)
1566 return 0; /* parameter not stored */
1567
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001568 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001569 t->data_arg[STKTABLE_DT_SESS_RATE].u);
1570 return 1;
1571}
1572
1573/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1574 * it up into this table. Returns the amount of concurrent connections tracking
1575 * the same key if the key is present in the table, otherwise zero, so that
1576 * comparisons can be easily performed. If the inspected parameter is not
1577 * stored in the table, <not found> is returned.
1578 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001579static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001580{
1581 struct stktable *t;
1582 struct stktable_key *key;
1583 struct stksess *ts;
1584
1585 t = &arg_p[0].data.prx->table;
1586
1587 key = smp_to_stkey(smp, t);
1588 if (!key)
1589 return 0;
1590
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001591 ts = stktable_lookup_key(t, key);
1592
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001593 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001594 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001595 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001597 if (ts)
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001598 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599
1600 return 1;
1601}
1602
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001603/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001604static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001605 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001606{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001607 struct stksess *ts;
1608 struct stkctr *stkctr;
1609
1610 /* Extract the stksess, return OK if no stksess available. */
1611 if (s)
1612 stkctr = &s->stkctr[rule->arg.gpc.sc];
1613 else
1614 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001615
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001616 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001617 if (ts) {
1618 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001619
Willy Tarreau79c1e912016-01-25 14:54:45 +01001620 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1621 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001622 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1623 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001624 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001625
1626 if (ptr1)
1627 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001628 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001629
Emeric Brun819fc6f2017-06-13 19:37:32 +02001630 if (ptr2)
1631 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001632
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001633 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001634
1635 /* If data was modified, we need to touch to re-schedule sync */
1636 stktable_touch_local(stkctr->table, ts, 0);
1637 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001638 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001639 return ACT_RET_CONT;
1640}
1641
1642/* This function is a common parser for using variables. It understands
1643 * the formats:
1644 *
1645 * sc-inc-gpc0(<stick-table ID>)
1646 *
1647 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1648 * it returns 1 and the variable <expr> is filled with the pointer to the
1649 * expression to execute.
1650 */
1651static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1652 struct act_rule *rule, char **err)
1653{
1654 const char *cmd_name = args[*arg-1];
1655 char *error;
1656
1657 cmd_name += strlen("sc-inc-gpc0");
1658 if (*cmd_name == '\0') {
1659 /* default stick table id. */
1660 rule->arg.gpc.sc = 0;
1661 } else {
1662 /* parse the stick table id. */
1663 if (*cmd_name != '(') {
1664 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1665 return ACT_RET_PRS_ERR;
1666 }
1667 cmd_name++; /* jump the '(' */
1668 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1669 if (*error != ')') {
1670 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1671 return ACT_RET_PRS_ERR;
1672 }
1673
1674 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1675 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1676 ACT_ACTION_TRK_SCMAX-1);
1677 return ACT_RET_PRS_ERR;
1678 }
1679 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001680 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001681 rule->action_ptr = action_inc_gpc0;
1682 return ACT_RET_PRS_OK;
1683}
1684
1685/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001686static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1687 struct session *sess, struct stream *s, int flags)
1688{
1689 struct stksess *ts;
1690 struct stkctr *stkctr;
1691
1692 /* Extract the stksess, return OK if no stksess available. */
1693 if (s)
1694 stkctr = &s->stkctr[rule->arg.gpc.sc];
1695 else
1696 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1697
1698 ts = stkctr_entry(stkctr);
1699 if (ts) {
1700 void *ptr1, *ptr2;
1701
1702 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1703 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1704 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1705 if (ptr1 || ptr2) {
1706 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1707
1708 if (ptr1)
1709 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1710 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1711
1712 if (ptr2)
1713 stktable_data_cast(ptr2, gpc1)++;
1714
1715 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1716
1717 /* If data was modified, we need to touch to re-schedule sync */
1718 stktable_touch_local(stkctr->table, ts, 0);
1719 }
1720 }
1721 return ACT_RET_CONT;
1722}
1723
1724/* This function is a common parser for using variables. It understands
1725 * the formats:
1726 *
1727 * sc-inc-gpc1(<stick-table ID>)
1728 *
1729 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1730 * it returns 1 and the variable <expr> is filled with the pointer to the
1731 * expression to execute.
1732 */
1733static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1734 struct act_rule *rule, char **err)
1735{
1736 const char *cmd_name = args[*arg-1];
1737 char *error;
1738
1739 cmd_name += strlen("sc-inc-gpc1");
1740 if (*cmd_name == '\0') {
1741 /* default stick table id. */
1742 rule->arg.gpc.sc = 0;
1743 } else {
1744 /* parse the stick table id. */
1745 if (*cmd_name != '(') {
1746 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1747 return ACT_RET_PRS_ERR;
1748 }
1749 cmd_name++; /* jump the '(' */
1750 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1751 if (*error != ')') {
1752 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1753 return ACT_RET_PRS_ERR;
1754 }
1755
1756 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1757 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1758 ACT_ACTION_TRK_SCMAX-1);
1759 return ACT_RET_PRS_ERR;
1760 }
1761 }
1762 rule->action = ACT_CUSTOM;
1763 rule->action_ptr = action_inc_gpc1;
1764 return ACT_RET_PRS_OK;
1765}
1766
1767/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001768static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001769 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001770{
1771 void *ptr;
1772 struct stksess *ts;
1773 struct stkctr *stkctr;
1774
1775 /* Extract the stksess, return OK if no stksess available. */
1776 if (s)
1777 stkctr = &s->stkctr[rule->arg.gpt.sc];
1778 else
1779 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001780
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001781 ts = stkctr_entry(stkctr);
1782 if (!ts)
1783 return ACT_RET_CONT;
1784
1785 /* Store the sample in the required sc, and ignore errors. */
1786 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001787 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001788 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001789
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001790 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001791
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001792 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001793
1794 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001795 }
1796
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001797 return ACT_RET_CONT;
1798}
1799
1800/* This function is a common parser for using variables. It understands
1801 * the format:
1802 *
1803 * set-gpt0(<stick-table ID>) <expression>
1804 *
1805 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1806 * it returns 1 and the variable <expr> is filled with the pointer to the
1807 * expression to execute.
1808 */
1809static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1810 struct act_rule *rule, char **err)
1811
1812
1813{
1814 const char *cmd_name = args[*arg-1];
1815 char *error;
1816
1817 cmd_name += strlen("sc-set-gpt0");
1818 if (*cmd_name == '\0') {
1819 /* default stick table id. */
1820 rule->arg.gpt.sc = 0;
1821 } else {
1822 /* parse the stick table id. */
1823 if (*cmd_name != '(') {
1824 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1825 return ACT_RET_PRS_ERR;
1826 }
1827 cmd_name++; /* jump the '(' */
1828 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1829 if (*error != ')') {
1830 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1831 return ACT_RET_PRS_ERR;
1832 }
1833
1834 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1835 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1836 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1837 return ACT_RET_PRS_ERR;
1838 }
1839 }
1840
1841 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1842 if (*error != '\0') {
1843 memprintf(err, "invalid integer value '%s'", args[*arg]);
1844 return ACT_RET_PRS_ERR;
1845 }
1846 (*arg)++;
1847
Thierry FOURNIER42148732015-09-02 17:17:33 +02001848 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001849 rule->action_ptr = action_set_gpt0;
1850
1851 return ACT_RET_PRS_OK;
1852}
1853
Willy Tarreau7d562212016-11-25 16:10:05 +01001854/* set temp integer to the number of used entries in the table pointed to by expr.
1855 * Accepts exactly 1 argument of type table.
1856 */
1857static int
1858smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1859{
1860 smp->flags = SMP_F_VOL_TEST;
1861 smp->data.type = SMP_T_SINT;
1862 smp->data.u.sint = args->data.prx->table.current;
1863 return 1;
1864}
1865
1866/* set temp integer to the number of free entries in the table pointed to by expr.
1867 * Accepts exactly 1 argument of type table.
1868 */
1869static int
1870smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1871{
1872 struct proxy *px;
1873
1874 px = args->data.prx;
1875 smp->flags = SMP_F_VOL_TEST;
1876 smp->data.type = SMP_T_SINT;
1877 smp->data.u.sint = px->table.size - px->table.current;
1878 return 1;
1879}
1880
1881/* Returns a pointer to a stkctr depending on the fetch keyword name.
1882 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1883 * sc[0-9]_* will return a pointer to the respective field in the
1884 * stream <l4>. sc_* requires an UINT argument specifying the stick
1885 * counter number. src_* will fill a locally allocated structure with
1886 * the table and entry corresponding to what is specified with src_*.
1887 * NULL may be returned if the designated stkctr is not tracked. For
1888 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1889 * passed. When present, the currently tracked key is then looked up
1890 * in the specified table instead of the current table. The purpose is
1891 * to be able to convery multiple values per key (eg: have gpc0 from
1892 * multiple tables). <strm> is allowed to be NULL, in which case only
1893 * the session will be consulted.
1894 */
1895struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001896smp_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 +01001897{
Willy Tarreau7d562212016-11-25 16:10:05 +01001898 struct stkctr *stkptr;
1899 struct stksess *stksess;
1900 unsigned int num = kw[2] - '0';
1901 int arg = 0;
1902
1903 if (num == '_' - '0') {
1904 /* sc_* variant, args[0] = ctr# (mandatory) */
1905 num = args[arg++].data.sint;
1906 if (num >= MAX_SESS_STKCTR)
1907 return NULL;
1908 }
1909 else if (num > 9) { /* src_* variant, args[0] = table */
1910 struct stktable_key *key;
1911 struct connection *conn = objt_conn(sess->origin);
1912 struct sample smp;
1913
1914 if (!conn)
1915 return NULL;
1916
1917 /* Fetch source adress in a sample. */
1918 smp.px = NULL;
1919 smp.sess = sess;
1920 smp.strm = strm;
1921 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1922 return NULL;
1923
1924 /* Converts into key. */
1925 key = smp_to_stkey(&smp, &args->data.prx->table);
1926 if (!key)
1927 return NULL;
1928
Emeric Brun819fc6f2017-06-13 19:37:32 +02001929 stkctr->table = &args->data.prx->table;
1930 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1931 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001932 }
1933
1934 /* Here, <num> contains the counter number from 0 to 9 for
1935 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1936 * args[arg] is the first optional argument. We first lookup the
1937 * ctr form the stream, then from the session if it was not there.
1938 */
1939
1940 if (strm)
1941 stkptr = &strm->stkctr[num];
1942 if (!strm || !stkctr_entry(stkptr)) {
1943 stkptr = &sess->stkctr[num];
1944 if (!stkctr_entry(stkptr))
1945 return NULL;
1946 }
1947
1948 stksess = stkctr_entry(stkptr);
1949 if (!stksess)
1950 return NULL;
1951
1952 if (unlikely(args[arg].type == ARGT_TAB)) {
1953 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001954 stkctr->table = &args[arg].data.prx->table;
1955 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1956 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001957 }
1958 return stkptr;
1959}
1960
1961/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1962 * the entry if it doesn't exist yet. This is needed for a few fetch
1963 * functions which need to create an entry, such as src_inc_gpc* and
1964 * src_clr_gpc*.
1965 */
1966struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001967smp_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 +01001968{
Willy Tarreau7d562212016-11-25 16:10:05 +01001969 struct stktable_key *key;
1970 struct connection *conn = objt_conn(sess->origin);
1971 struct sample smp;
1972
1973 if (strncmp(kw, "src_", 4) != 0)
1974 return NULL;
1975
1976 if (!conn)
1977 return NULL;
1978
1979 /* Fetch source adress in a sample. */
1980 smp.px = NULL;
1981 smp.sess = sess;
1982 smp.strm = strm;
1983 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1984 return NULL;
1985
1986 /* Converts into key. */
1987 key = smp_to_stkey(&smp, &args->data.prx->table);
1988 if (!key)
1989 return NULL;
1990
Emeric Brun819fc6f2017-06-13 19:37:32 +02001991 stkctr->table = &args->data.prx->table;
1992 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
1993 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001994}
1995
1996/* set return a boolean indicating if the requested stream counter is
1997 * currently being tracked or not.
1998 * Supports being called as "sc[0-9]_tracked" only.
1999 */
2000static int
2001smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2002{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002003 struct stkctr tmpstkctr;
2004 struct stkctr *stkctr;
2005
Willy Tarreau7d562212016-11-25 16:10:05 +01002006 smp->flags = SMP_F_VOL_TEST;
2007 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002008 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2009 smp->data.u.sint = !!stkctr;
2010
2011 /* release the ref count */
2012 if ((stkctr == &tmpstkctr) && stkctr_entry(stkctr))
2013 stktable_release(stkctr->table, stkctr_entry(stkctr));
2014
Willy Tarreau7d562212016-11-25 16:10:05 +01002015 return 1;
2016}
2017
2018/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2019 * frontend counters or from the src.
2020 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2021 * zero is returned if the key is new.
2022 */
2023static int
2024smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2025{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002026 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002027 struct stkctr *stkctr;
2028
Emeric Brun819fc6f2017-06-13 19:37:32 +02002029 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002030 if (!stkctr)
2031 return 0;
2032
2033 smp->flags = SMP_F_VOL_TEST;
2034 smp->data.type = SMP_T_SINT;
2035 smp->data.u.sint = 0;
2036
Emeric Brun819fc6f2017-06-13 19:37:32 +02002037 if (stkctr_entry(stkctr)) {
2038 void *ptr;
2039
2040 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2041 if (!ptr) {
2042 if (stkctr == &tmpstkctr)
2043 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002044 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002045 }
2046
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002047 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002048
Willy Tarreau7d562212016-11-25 16:10:05 +01002049 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002050
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002051 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002052
2053 if (stkctr == &tmpstkctr)
2054 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002055 }
2056 return 1;
2057}
2058
2059/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2060 * frontend counters or from the src.
2061 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2062 * zero is returned if the key is new.
2063 */
2064static int
2065smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2066{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002067 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002068 struct stkctr *stkctr;
2069
Emeric Brun819fc6f2017-06-13 19:37:32 +02002070 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002071 if (!stkctr)
2072 return 0;
2073
2074 smp->flags = SMP_F_VOL_TEST;
2075 smp->data.type = SMP_T_SINT;
2076 smp->data.u.sint = 0;
2077
2078 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002079 void *ptr;
2080
2081 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2082 if (!ptr) {
2083 if (stkctr == &tmpstkctr)
2084 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002085 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002086 }
2087
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002088 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002089
Willy Tarreau7d562212016-11-25 16:10:05 +01002090 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002091
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002092 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002093
2094 if (stkctr == &tmpstkctr)
2095 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002096 }
2097 return 1;
2098}
2099
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002100/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2101 * frontend counters or from the src.
2102 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2103 * zero is returned if the key is new.
2104 */
2105static int
2106smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2107{
2108 struct stkctr tmpstkctr;
2109 struct stkctr *stkctr;
2110
2111 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2112 if (!stkctr)
2113 return 0;
2114
2115 smp->flags = SMP_F_VOL_TEST;
2116 smp->data.type = SMP_T_SINT;
2117 smp->data.u.sint = 0;
2118
2119 if (stkctr_entry(stkctr) != NULL) {
2120 void *ptr;
2121
2122 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2123 if (!ptr) {
2124 if (stkctr == &tmpstkctr)
2125 stktable_release(stkctr->table, stkctr_entry(stkctr));
2126 return 0; /* parameter not stored */
2127 }
2128
2129 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2130
2131 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2132
2133 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2134
2135 if (stkctr == &tmpstkctr)
2136 stktable_release(stkctr->table, stkctr_entry(stkctr));
2137 }
2138 return 1;
2139}
2140
Willy Tarreau7d562212016-11-25 16:10:05 +01002141/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2142 * tracked frontend counters or from the src.
2143 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2144 * Value zero is returned if the key is new.
2145 */
2146static int
2147smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2148{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002149 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002150 struct stkctr *stkctr;
2151
Emeric Brun819fc6f2017-06-13 19:37:32 +02002152 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002153 if (!stkctr)
2154 return 0;
2155
2156 smp->flags = SMP_F_VOL_TEST;
2157 smp->data.type = SMP_T_SINT;
2158 smp->data.u.sint = 0;
2159 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002160 void *ptr;
2161
2162 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2163 if (!ptr) {
2164 if (stkctr == &tmpstkctr)
2165 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002166 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002167 }
2168
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002169 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002170
Willy Tarreau7d562212016-11-25 16:10:05 +01002171 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2172 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002173
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002174 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002175
2176 if (stkctr == &tmpstkctr)
2177 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002178 }
2179 return 1;
2180}
2181
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002182/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2183 * tracked frontend counters or from the src.
2184 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2185 * Value zero is returned if the key is new.
2186 */
2187static int
2188smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2189{
2190 struct stkctr tmpstkctr;
2191 struct stkctr *stkctr;
2192
2193 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2194 if (!stkctr)
2195 return 0;
2196
2197 smp->flags = SMP_F_VOL_TEST;
2198 smp->data.type = SMP_T_SINT;
2199 smp->data.u.sint = 0;
2200 if (stkctr_entry(stkctr) != NULL) {
2201 void *ptr;
2202
2203 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2204 if (!ptr) {
2205 if (stkctr == &tmpstkctr)
2206 stktable_release(stkctr->table, stkctr_entry(stkctr));
2207 return 0; /* parameter not stored */
2208 }
2209
2210 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2211
2212 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2213 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2214
2215 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2216
2217 if (stkctr == &tmpstkctr)
2218 stktable_release(stkctr->table, stkctr_entry(stkctr));
2219 }
2220 return 1;
2221}
2222
Willy Tarreau7d562212016-11-25 16:10:05 +01002223/* Increment the General Purpose Counter 0 value from the stream's tracked
2224 * frontend counters and return it into temp integer.
2225 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2226 */
2227static int
2228smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2229{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002230 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002231 struct stkctr *stkctr;
2232
Emeric Brun819fc6f2017-06-13 19:37:32 +02002233 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002234 if (!stkctr)
2235 return 0;
2236
2237 smp->flags = SMP_F_VOL_TEST;
2238 smp->data.type = SMP_T_SINT;
2239 smp->data.u.sint = 0;
2240
Emeric Brun819fc6f2017-06-13 19:37:32 +02002241 if (!stkctr_entry(stkctr))
2242 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002243
2244 if (stkctr && stkctr_entry(stkctr)) {
2245 void *ptr1,*ptr2;
2246
Emeric Brun819fc6f2017-06-13 19:37:32 +02002247
Willy Tarreau7d562212016-11-25 16:10:05 +01002248 /* First, update gpc0_rate if it's tracked. Second, update its
2249 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2250 */
2251 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002252 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002253 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002254 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002255
Emeric Brun819fc6f2017-06-13 19:37:32 +02002256 if (ptr1) {
2257 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2258 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2259 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2260 }
2261
2262 if (ptr2)
2263 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2264
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002265 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002266
2267 /* If data was modified, we need to touch to re-schedule sync */
2268 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2269 }
2270 else if (stkctr == &tmpstkctr)
2271 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002272 }
2273 return 1;
2274}
2275
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002276/* Increment the General Purpose Counter 1 value from the stream's tracked
2277 * frontend counters and return it into temp integer.
2278 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2279 */
2280static int
2281smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2282{
2283 struct stkctr tmpstkctr;
2284 struct stkctr *stkctr;
2285
2286 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2287 if (!stkctr)
2288 return 0;
2289
2290 smp->flags = SMP_F_VOL_TEST;
2291 smp->data.type = SMP_T_SINT;
2292 smp->data.u.sint = 0;
2293
2294 if (!stkctr_entry(stkctr))
2295 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2296
2297 if (stkctr && stkctr_entry(stkctr)) {
2298 void *ptr1,*ptr2;
2299
2300
2301 /* First, update gpc1_rate if it's tracked. Second, update its
2302 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2303 */
2304 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2305 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2306 if (ptr1 || ptr2) {
2307 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2308
2309 if (ptr1) {
2310 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2311 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2312 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2313 }
2314
2315 if (ptr2)
2316 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2317
2318 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2319
2320 /* If data was modified, we need to touch to re-schedule sync */
2321 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2322 }
2323 else if (stkctr == &tmpstkctr)
2324 stktable_release(stkctr->table, stkctr_entry(stkctr));
2325 }
2326 return 1;
2327}
2328
Willy Tarreau7d562212016-11-25 16:10:05 +01002329/* Clear the General Purpose Counter 0 value from the stream's tracked
2330 * frontend counters and return its previous value into temp integer.
2331 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2332 */
2333static int
2334smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2335{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002336 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002337 struct stkctr *stkctr;
2338
Emeric Brun819fc6f2017-06-13 19:37:32 +02002339 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002340 if (!stkctr)
2341 return 0;
2342
2343 smp->flags = SMP_F_VOL_TEST;
2344 smp->data.type = SMP_T_SINT;
2345 smp->data.u.sint = 0;
2346
Emeric Brun819fc6f2017-06-13 19:37:32 +02002347 if (!stkctr_entry(stkctr))
2348 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002349
Emeric Brun819fc6f2017-06-13 19:37:32 +02002350 if (stkctr && stkctr_entry(stkctr)) {
2351 void *ptr;
2352
2353 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2354 if (!ptr) {
2355 if (stkctr == &tmpstkctr)
2356 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002357 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002358 }
2359
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002360 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002361
Willy Tarreau7d562212016-11-25 16:10:05 +01002362 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2363 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002364
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002365 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002366
Willy Tarreau7d562212016-11-25 16:10:05 +01002367 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002368 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002369 }
2370 return 1;
2371}
2372
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002373/* Clear the General Purpose Counter 1 value from the stream's tracked
2374 * frontend counters and return its previous value into temp integer.
2375 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2376 */
2377static int
2378smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2379{
2380 struct stkctr tmpstkctr;
2381 struct stkctr *stkctr;
2382
2383 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2384 if (!stkctr)
2385 return 0;
2386
2387 smp->flags = SMP_F_VOL_TEST;
2388 smp->data.type = SMP_T_SINT;
2389 smp->data.u.sint = 0;
2390
2391 if (!stkctr_entry(stkctr))
2392 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2393
2394 if (stkctr && stkctr_entry(stkctr)) {
2395 void *ptr;
2396
2397 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2398 if (!ptr) {
2399 if (stkctr == &tmpstkctr)
2400 stktable_release(stkctr->table, stkctr_entry(stkctr));
2401 return 0; /* parameter not stored */
2402 }
2403
2404 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2405
2406 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2407 stktable_data_cast(ptr, gpc1) = 0;
2408
2409 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2410
2411 /* If data was modified, we need to touch to re-schedule sync */
2412 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2413 }
2414 return 1;
2415}
2416
Willy Tarreau7d562212016-11-25 16:10:05 +01002417/* set <smp> to the cumulated number of connections from the stream's tracked
2418 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2419 * "src_conn_cnt" only.
2420 */
2421static int
2422smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2423{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002424 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002425 struct stkctr *stkctr;
2426
Emeric Brun819fc6f2017-06-13 19:37:32 +02002427 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002428 if (!stkctr)
2429 return 0;
2430
2431 smp->flags = SMP_F_VOL_TEST;
2432 smp->data.type = SMP_T_SINT;
2433 smp->data.u.sint = 0;
2434 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002435 void *ptr;
2436
2437 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2438 if (!ptr) {
2439 if (stkctr == &tmpstkctr)
2440 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002441 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002442 }
2443
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002444 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002445
Willy Tarreau7d562212016-11-25 16:10:05 +01002446 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002447
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002448 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002449
2450 if (stkctr == &tmpstkctr)
2451 stktable_release(stkctr->table, stkctr_entry(stkctr));
2452
2453
Willy Tarreau7d562212016-11-25 16:10:05 +01002454 }
2455 return 1;
2456}
2457
2458/* set <smp> to the connection rate from the stream's tracked frontend
2459 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2460 * only.
2461 */
2462static int
2463smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2464{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002465 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002466 struct stkctr *stkctr;
2467
Emeric Brun819fc6f2017-06-13 19:37:32 +02002468 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002469 if (!stkctr)
2470 return 0;
2471
2472 smp->flags = SMP_F_VOL_TEST;
2473 smp->data.type = SMP_T_SINT;
2474 smp->data.u.sint = 0;
2475 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002476 void *ptr;
2477
2478 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2479 if (!ptr) {
2480 if (stkctr == &tmpstkctr)
2481 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002482 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002483 }
2484
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002485 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002486
Willy Tarreau7d562212016-11-25 16:10:05 +01002487 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2488 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002489
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002490 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002491
2492 if (stkctr == &tmpstkctr)
2493 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002494 }
2495 return 1;
2496}
2497
2498/* set temp integer to the number of connections from the stream's source address
2499 * in the table pointed to by expr, after updating it.
2500 * Accepts exactly 1 argument of type table.
2501 */
2502static int
2503smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2504{
2505 struct connection *conn = objt_conn(smp->sess->origin);
2506 struct stksess *ts;
2507 struct stktable_key *key;
2508 void *ptr;
2509 struct proxy *px;
2510
2511 if (!conn)
2512 return 0;
2513
2514 /* Fetch source adress in a sample. */
2515 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2516 return 0;
2517
2518 /* Converts into key. */
2519 key = smp_to_stkey(smp, &args->data.prx->table);
2520 if (!key)
2521 return 0;
2522
2523 px = args->data.prx;
2524
Emeric Brun819fc6f2017-06-13 19:37:32 +02002525 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002526 /* entry does not exist and could not be created */
2527 return 0;
2528
2529 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002530 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002531 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002532 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002533
2534 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002535
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002536 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002537
Willy Tarreau7d562212016-11-25 16:10:05 +01002538 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002539
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002540 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002541
Willy Tarreau7d562212016-11-25 16:10:05 +01002542 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002543
2544 stktable_touch_local(&px->table, ts, 1);
2545
2546 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002547 return 1;
2548}
2549
2550/* set <smp> to the number of concurrent connections from the stream's tracked
2551 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2552 * "src_conn_cur" only.
2553 */
2554static int
2555smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2556{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002557 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002558 struct stkctr *stkctr;
2559
Emeric Brun819fc6f2017-06-13 19:37:32 +02002560 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002561 if (!stkctr)
2562 return 0;
2563
2564 smp->flags = SMP_F_VOL_TEST;
2565 smp->data.type = SMP_T_SINT;
2566 smp->data.u.sint = 0;
2567 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002568 void *ptr;
2569
2570 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2571 if (!ptr) {
2572 if (stkctr == &tmpstkctr)
2573 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002574 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002575 }
2576
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002577 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002578
Willy Tarreau7d562212016-11-25 16:10:05 +01002579 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002580
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002581 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002582
2583 if (stkctr == &tmpstkctr)
2584 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002585 }
2586 return 1;
2587}
2588
2589/* set <smp> to the cumulated number of streams from the stream's tracked
2590 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2591 * "src_sess_cnt" only.
2592 */
2593static int
2594smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2595{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002596 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002597 struct stkctr *stkctr;
2598
Emeric Brun819fc6f2017-06-13 19:37:32 +02002599 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002600 if (!stkctr)
2601 return 0;
2602
2603 smp->flags = SMP_F_VOL_TEST;
2604 smp->data.type = SMP_T_SINT;
2605 smp->data.u.sint = 0;
2606 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002607 void *ptr;
2608
2609 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2610 if (!ptr) {
2611 if (stkctr == &tmpstkctr)
2612 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002613 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002614 }
2615
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002616 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002617
Willy Tarreau7d562212016-11-25 16:10:05 +01002618 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002619
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002620 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002621
2622 if (stkctr == &tmpstkctr)
2623 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002624 }
2625 return 1;
2626}
2627
2628/* set <smp> to the stream rate from the stream's tracked frontend counters.
2629 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2630 */
2631static int
2632smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2633{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002634 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002635 struct stkctr *stkctr;
2636
Emeric Brun819fc6f2017-06-13 19:37:32 +02002637 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002638 if (!stkctr)
2639 return 0;
2640
2641 smp->flags = SMP_F_VOL_TEST;
2642 smp->data.type = SMP_T_SINT;
2643 smp->data.u.sint = 0;
2644 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002645 void *ptr;
2646
2647 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2648 if (!ptr) {
2649 if (stkctr == &tmpstkctr)
2650 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002651 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002652 }
2653
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002654 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002655
Willy Tarreau7d562212016-11-25 16:10:05 +01002656 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2657 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002658
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002659 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002660
2661 if (stkctr == &tmpstkctr)
2662 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002663 }
2664 return 1;
2665}
2666
2667/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2668 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2669 * "src_http_req_cnt" only.
2670 */
2671static int
2672smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2673{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002674 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002675 struct stkctr *stkctr;
2676
Emeric Brun819fc6f2017-06-13 19:37:32 +02002677 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002678 if (!stkctr)
2679 return 0;
2680
2681 smp->flags = SMP_F_VOL_TEST;
2682 smp->data.type = SMP_T_SINT;
2683 smp->data.u.sint = 0;
2684 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002685 void *ptr;
2686
2687 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2688 if (!ptr) {
2689 if (stkctr == &tmpstkctr)
2690 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002691 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002692 }
2693
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002694 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002695
Willy Tarreau7d562212016-11-25 16:10:05 +01002696 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002697
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002698 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002699
2700 if (stkctr == &tmpstkctr)
2701 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002702 }
2703 return 1;
2704}
2705
2706/* set <smp> to the HTTP request rate from the stream's tracked frontend
2707 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2708 * "src_http_req_rate" only.
2709 */
2710static int
2711smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2712{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002713 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002714 struct stkctr *stkctr;
2715
Emeric Brun819fc6f2017-06-13 19:37:32 +02002716 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002717 if (!stkctr)
2718 return 0;
2719
2720 smp->flags = SMP_F_VOL_TEST;
2721 smp->data.type = SMP_T_SINT;
2722 smp->data.u.sint = 0;
2723 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002724 void *ptr;
2725
2726 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2727 if (!ptr) {
2728 if (stkctr == &tmpstkctr)
2729 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002730 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002731 }
2732
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002733 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002734
Willy Tarreau7d562212016-11-25 16:10:05 +01002735 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2736 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002737
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002738 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002739
2740 if (stkctr == &tmpstkctr)
2741 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002742 }
2743 return 1;
2744}
2745
2746/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2747 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2748 * "src_http_err_cnt" only.
2749 */
2750static int
2751smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2752{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002753 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002754 struct stkctr *stkctr;
2755
Emeric Brun819fc6f2017-06-13 19:37:32 +02002756 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002757 if (!stkctr)
2758 return 0;
2759
2760 smp->flags = SMP_F_VOL_TEST;
2761 smp->data.type = SMP_T_SINT;
2762 smp->data.u.sint = 0;
2763 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002764 void *ptr;
2765
2766 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2767 if (!ptr) {
2768 if (stkctr == &tmpstkctr)
2769 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002770 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771 }
2772
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002773 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002774
Willy Tarreau7d562212016-11-25 16:10:05 +01002775 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002776
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002777 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002778
2779 if (stkctr == &tmpstkctr)
2780 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002781 }
2782 return 1;
2783}
2784
2785/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2786 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2787 * "src_http_err_rate" only.
2788 */
2789static int
2790smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2791{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002792 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002793 struct stkctr *stkctr;
2794
Emeric Brun819fc6f2017-06-13 19:37:32 +02002795 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002796 if (!stkctr)
2797 return 0;
2798
2799 smp->flags = SMP_F_VOL_TEST;
2800 smp->data.type = SMP_T_SINT;
2801 smp->data.u.sint = 0;
2802 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002803 void *ptr;
2804
2805 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2806 if (!ptr) {
2807 if (stkctr == &tmpstkctr)
2808 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002809 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002810 }
2811
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002812 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002813
Willy Tarreau7d562212016-11-25 16:10:05 +01002814 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2815 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002816
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002817 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002818
2819 if (stkctr == &tmpstkctr)
2820 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002821 }
2822 return 1;
2823}
2824
2825/* set <smp> to the number of kbytes received from clients, as found in the
2826 * stream's tracked frontend counters. Supports being called as
2827 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2828 */
2829static int
2830smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2831{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002832 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002833 struct stkctr *stkctr;
2834
Emeric Brun819fc6f2017-06-13 19:37:32 +02002835 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002836 if (!stkctr)
2837 return 0;
2838
2839 smp->flags = SMP_F_VOL_TEST;
2840 smp->data.type = SMP_T_SINT;
2841 smp->data.u.sint = 0;
2842 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002843 void *ptr;
2844
2845 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2846 if (!ptr) {
2847 if (stkctr == &tmpstkctr)
2848 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002849 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002850 }
2851
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002852 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002853
Willy Tarreau7d562212016-11-25 16:10:05 +01002854 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002855
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002856 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002857
2858 if (stkctr == &tmpstkctr)
2859 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002860 }
2861 return 1;
2862}
2863
2864/* set <smp> to the data rate received from clients in bytes/s, as found
2865 * in the stream's tracked frontend counters. Supports being called as
2866 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2867 */
2868static int
2869smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2870{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002871 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002872 struct stkctr *stkctr;
2873
Emeric Brun819fc6f2017-06-13 19:37:32 +02002874 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002875 if (!stkctr)
2876 return 0;
2877
2878 smp->flags = SMP_F_VOL_TEST;
2879 smp->data.type = SMP_T_SINT;
2880 smp->data.u.sint = 0;
2881 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002882 void *ptr;
2883
2884 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2885 if (!ptr) {
2886 if (stkctr == &tmpstkctr)
2887 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002888 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889 }
2890
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002891 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892
Willy Tarreau7d562212016-11-25 16:10:05 +01002893 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2894 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002895
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002896 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002897
2898 if (stkctr == &tmpstkctr)
2899 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002900 }
2901 return 1;
2902}
2903
2904/* set <smp> to the number of kbytes sent to clients, as found in the
2905 * stream's tracked frontend counters. Supports being called as
2906 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2907 */
2908static int
2909smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2910{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002911 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002912 struct stkctr *stkctr;
2913
Emeric Brun819fc6f2017-06-13 19:37:32 +02002914 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002915 if (!stkctr)
2916 return 0;
2917
2918 smp->flags = SMP_F_VOL_TEST;
2919 smp->data.type = SMP_T_SINT;
2920 smp->data.u.sint = 0;
2921 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002922 void *ptr;
2923
2924 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2925 if (!ptr) {
2926 if (stkctr == &tmpstkctr)
2927 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002928 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002929 }
2930
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002931 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002932
Willy Tarreau7d562212016-11-25 16:10:05 +01002933 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002935 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002936
2937 if (stkctr == &tmpstkctr)
2938 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002939 }
2940 return 1;
2941}
2942
2943/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2944 * stream's tracked frontend counters. Supports being called as
2945 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2946 */
2947static int
2948smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2949{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002950 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002951 struct stkctr *stkctr;
2952
Emeric Brun819fc6f2017-06-13 19:37:32 +02002953 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002954 if (!stkctr)
2955 return 0;
2956
2957 smp->flags = SMP_F_VOL_TEST;
2958 smp->data.type = SMP_T_SINT;
2959 smp->data.u.sint = 0;
2960 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002961 void *ptr;
2962
2963 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2964 if (!ptr) {
2965 if (stkctr == &tmpstkctr)
2966 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002967 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002968 }
2969
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002970 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002971
Willy Tarreau7d562212016-11-25 16:10:05 +01002972 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2973 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002974
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002975 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002976
2977 if (stkctr == &tmpstkctr)
2978 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002979 }
2980 return 1;
2981}
2982
2983/* set <smp> to the number of active trackers on the SC entry in the stream's
2984 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2985 */
2986static int
2987smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2988{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002989 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002990 struct stkctr *stkctr;
2991
Emeric Brun819fc6f2017-06-13 19:37:32 +02002992 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002993 if (!stkctr)
2994 return 0;
2995
2996 smp->flags = SMP_F_VOL_TEST;
2997 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998 if (stkctr == &tmpstkctr) {
2999 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3000 stktable_release(stkctr->table, stkctr_entry(stkctr));
3001 }
3002 else {
3003 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3004 }
3005
Willy Tarreau7d562212016-11-25 16:10:05 +01003006 return 1;
3007}
3008
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003009
3010/* The functions below are used to manipulate table contents from the CLI.
3011 * There are 3 main actions, "clear", "set" and "show". The code is shared
3012 * between all actions, and the action is encoded in the void *private in
3013 * the appctx as well as in the keyword registration, among one of the
3014 * following values.
3015 */
3016
3017enum {
3018 STK_CLI_ACT_CLR,
3019 STK_CLI_ACT_SET,
3020 STK_CLI_ACT_SHOW,
3021};
3022
3023/* Dump the status of a table to a stream interface's
3024 * read buffer. It returns 0 if the output buffer is full
3025 * and needs to be called again, otherwise non-zero.
3026 */
3027static int table_dump_head_to_buffer(struct chunk *msg, struct stream_interface *si,
3028 struct proxy *proxy, struct proxy *target)
3029{
3030 struct stream *s = si_strm(si);
3031
3032 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3033 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3034
3035 /* any other information should be dumped here */
3036
William Lallemand07a62f72017-05-24 00:57:40 +02003037 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003038 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3039
Willy Tarreau06d80a92017-10-19 14:32:15 +02003040 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003041 si_applet_cant_put(si);
3042 return 0;
3043 }
3044
3045 return 1;
3046}
3047
3048/* Dump a table entry to a stream interface's
3049 * read buffer. It returns 0 if the output buffer is full
3050 * and needs to be called again, otherwise non-zero.
3051 */
3052static int table_dump_entry_to_buffer(struct chunk *msg, struct stream_interface *si,
3053 struct proxy *proxy, struct stksess *entry)
3054{
3055 int dt;
3056
3057 chunk_appendf(msg, "%p:", entry);
3058
3059 if (proxy->table.type == SMP_T_IPV4) {
3060 char addr[INET_ADDRSTRLEN];
3061 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3062 chunk_appendf(msg, " key=%s", addr);
3063 }
3064 else if (proxy->table.type == SMP_T_IPV6) {
3065 char addr[INET6_ADDRSTRLEN];
3066 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3067 chunk_appendf(msg, " key=%s", addr);
3068 }
3069 else if (proxy->table.type == SMP_T_SINT) {
3070 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3071 }
3072 else if (proxy->table.type == SMP_T_STR) {
3073 chunk_appendf(msg, " key=");
3074 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3075 }
3076 else {
3077 chunk_appendf(msg, " key=");
3078 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3079 }
3080
3081 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3082
3083 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3084 void *ptr;
3085
3086 if (proxy->table.data_ofs[dt] == 0)
3087 continue;
3088 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3089 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3090 else
3091 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3092
3093 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3094 switch (stktable_data_types[dt].std_type) {
3095 case STD_T_SINT:
3096 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3097 break;
3098 case STD_T_UINT:
3099 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3100 break;
3101 case STD_T_ULL:
3102 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3103 break;
3104 case STD_T_FRQP:
3105 chunk_appendf(msg, "%d",
3106 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3107 proxy->table.data_arg[dt].u));
3108 break;
3109 }
3110 }
3111 chunk_appendf(msg, "\n");
3112
Willy Tarreau06d80a92017-10-19 14:32:15 +02003113 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003114 si_applet_cant_put(si);
3115 return 0;
3116 }
3117
3118 return 1;
3119}
3120
3121
3122/* Processes a single table entry matching a specific key passed in argument.
3123 * returns 0 if wants to be called again, 1 if has ended processing.
3124 */
3125static int table_process_entry_per_key(struct appctx *appctx, char **args)
3126{
3127 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003128 struct proxy *px = appctx->ctx.table.target;
3129 struct stksess *ts;
3130 uint32_t uint32_key;
3131 unsigned char ip6_key[sizeof(struct in6_addr)];
3132 long long value;
3133 int data_type;
3134 int cur_arg;
3135 void *ptr;
3136 struct freq_ctr_period *frqp;
3137
3138 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003139 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003140 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003141 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003142 return 1;
3143 }
3144
3145 switch (px->table.type) {
3146 case SMP_T_IPV4:
3147 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003148 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003149 break;
3150 case SMP_T_IPV6:
3151 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003152 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003153 break;
3154 case SMP_T_SINT:
3155 {
3156 char *endptr;
3157 unsigned long val;
3158 errno = 0;
3159 val = strtoul(args[4], &endptr, 10);
3160 if ((errno == ERANGE && val == ULONG_MAX) ||
3161 (errno != 0 && val == 0) || endptr == args[4] ||
3162 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003163 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003164 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003165 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003166 return 1;
3167 }
3168 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003169 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003170 break;
3171 }
3172 break;
3173 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003174 static_table_key.key = args[4];
3175 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003176 break;
3177 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003178 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003179 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003180 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003181 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3182 break;
3183 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003184 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003185 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3186 break;
3187 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003188 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003189 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3190 break;
3191 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003192 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003193 appctx->ctx.cli.msg = "Unknown action\n";
3194 break;
3195 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003196 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003197 return 1;
3198 }
3199
3200 /* check permissions */
3201 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3202 return 1;
3203
Willy Tarreaua24bc782016-12-14 15:50:35 +01003204 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003205 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003206 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003207 if (!ts)
3208 return 1;
3209 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003210 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3211 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003212 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003213 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003214 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003215 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003216 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003218 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003220 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003221 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003222 break;
3223
3224 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003226 if (!ts)
3227 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228
3229 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003230 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003231 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003232 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003233 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003234 return 1;
3235 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003237 break;
3238
3239 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003240 ts = stktable_get_entry(&px->table, &static_table_key);
3241 if (!ts) {
3242 /* don't delete an entry which is currently referenced */
3243 appctx->ctx.cli.severity = LOG_ERR;
3244 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3245 appctx->st0 = CLI_ST_PRINT;
3246 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003247 }
3248
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003249 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003250 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3251 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003252 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003253 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003254 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003255 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003256 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003257 return 1;
3258 }
3259
3260 data_type = stktable_get_data_type(args[cur_arg] + 5);
3261 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003262 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003263 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003264 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003265 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003266 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003267 return 1;
3268 }
3269
3270 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003271 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003272 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003273 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003274 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003275 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003276 return 1;
3277 }
3278
3279 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003280 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003281 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003282 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003283 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003284 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003285 return 1;
3286 }
3287
3288 ptr = stktable_data_ptr(&px->table, ts, data_type);
3289
3290 switch (stktable_data_types[data_type].std_type) {
3291 case STD_T_SINT:
3292 stktable_data_cast(ptr, std_t_sint) = value;
3293 break;
3294 case STD_T_UINT:
3295 stktable_data_cast(ptr, std_t_uint) = value;
3296 break;
3297 case STD_T_ULL:
3298 stktable_data_cast(ptr, std_t_ull) = value;
3299 break;
3300 case STD_T_FRQP:
3301 /* We set both the current and previous values. That way
3302 * the reported frequency is stable during all the period
3303 * then slowly fades out. This allows external tools to
3304 * push measures without having to update them too often.
3305 */
3306 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003307 /* First bit is reserved for the freq_ctr_period lock
3308 Note: here we're still protected by the stksess lock
3309 so we don't need to update the update the freq_ctr_period
3310 using its internal lock */
3311 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003312 frqp->prev_ctr = 0;
3313 frqp->curr_ctr = value;
3314 break;
3315 }
3316 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003317 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003318 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003319 break;
3320
3321 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003322 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003323 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003324 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003325 break;
3326 }
3327 return 1;
3328}
3329
3330/* Prepares the appctx fields with the data-based filters from the command line.
3331 * Returns 0 if the dump can proceed, 1 if has ended processing.
3332 */
3333static int table_prepare_data_request(struct appctx *appctx, char **args)
3334{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003335 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003336 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003337 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003338 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003339 return 1;
3340 }
3341
3342 /* condition on stored data value */
3343 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3344 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003345 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003346 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003347 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003348 return 1;
3349 }
3350
3351 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003352 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003353 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003354 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003355 return 1;
3356 }
3357
3358 appctx->ctx.table.data_op = get_std_op(args[4]);
3359 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003360 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003361 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003362 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003363 return 1;
3364 }
3365
3366 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003367 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003368 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003369 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003370 return 1;
3371 }
3372
3373 /* OK we're done, all the fields are set */
3374 return 0;
3375}
3376
3377/* returns 0 if wants to be called, 1 if has ended processing */
3378static int cli_parse_table_req(char **args, struct appctx *appctx, void *private)
3379{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003380 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003381 appctx->ctx.table.target = NULL;
3382 appctx->ctx.table.proxy = NULL;
3383 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003384 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003385
3386 if (*args[2]) {
3387 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3388 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003389 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003390 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003391 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003392 return 1;
3393 }
3394 }
3395 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003396 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003397 goto err_args;
3398 return 0;
3399 }
3400
3401 if (strcmp(args[3], "key") == 0)
3402 return table_process_entry_per_key(appctx, args);
3403 else if (strncmp(args[3], "data.", 5) == 0)
3404 return table_prepare_data_request(appctx, args);
3405 else if (*args[3])
3406 goto err_args;
3407
3408 return 0;
3409
3410err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003411 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003412 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003413 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003414 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3415 break;
3416 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003417 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003418 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3419 break;
3420 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003421 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003422 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3423 break;
3424 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003425 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003426 appctx->ctx.cli.msg = "Unknown action\n";
3427 break;
3428 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003429 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003430 return 1;
3431}
3432
3433/* This function is used to deal with table operations (dump or clear depending
3434 * on the action stored in appctx->private). It returns 0 if the output buffer is
3435 * full and it needs to be called again, otherwise non-zero.
3436 */
3437static int cli_io_handler_table(struct appctx *appctx)
3438{
3439 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003440 struct stream *s = si_strm(si);
3441 struct ebmb_node *eb;
3442 int dt;
3443 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003444 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003445
3446 /*
3447 * We have 3 possible states in appctx->st2 :
3448 * - STAT_ST_INIT : the first call
3449 * - STAT_ST_INFO : the proxy pointer points to the next table to
3450 * dump, the entry pointer is NULL ;
3451 * - STAT_ST_LIST : the proxy pointer points to the current table
3452 * and the entry pointer points to the next entry to be dumped,
3453 * and the refcount on the next entry is held ;
3454 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3455 * data though.
3456 */
3457
3458 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3459 /* in case of abort, remove any refcount we might have set on an entry */
3460 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003461 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003462 }
3463 return 1;
3464 }
3465
3466 chunk_reset(&trash);
3467
3468 while (appctx->st2 != STAT_ST_FIN) {
3469 switch (appctx->st2) {
3470 case STAT_ST_INIT:
3471 appctx->ctx.table.proxy = appctx->ctx.table.target;
3472 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003473 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003474
3475 appctx->ctx.table.entry = NULL;
3476 appctx->st2 = STAT_ST_INFO;
3477 break;
3478
3479 case STAT_ST_INFO:
3480 if (!appctx->ctx.table.proxy ||
3481 (appctx->ctx.table.target &&
3482 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3483 appctx->st2 = STAT_ST_END;
3484 break;
3485 }
3486
3487 if (appctx->ctx.table.proxy->table.size) {
3488 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3489 return 0;
3490
3491 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003492 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003493 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003494 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003495 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3496 if (eb) {
3497 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3498 appctx->ctx.table.entry->ref_cnt++;
3499 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003500 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003501 break;
3502 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003503 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003504 }
3505 }
3506 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3507 break;
3508
3509 case STAT_ST_LIST:
3510 skip_entry = 0;
3511
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003512 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003513
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003514 if (appctx->ctx.table.data_type >= 0) {
3515 /* we're filtering on some data contents */
3516 void *ptr;
3517 long long data;
3518
Emeric Brun819fc6f2017-06-13 19:37:32 +02003519
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003520 dt = appctx->ctx.table.data_type;
3521 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3522 appctx->ctx.table.entry,
3523 dt);
3524
3525 data = 0;
3526 switch (stktable_data_types[dt].std_type) {
3527 case STD_T_SINT:
3528 data = stktable_data_cast(ptr, std_t_sint);
3529 break;
3530 case STD_T_UINT:
3531 data = stktable_data_cast(ptr, std_t_uint);
3532 break;
3533 case STD_T_ULL:
3534 data = stktable_data_cast(ptr, std_t_ull);
3535 break;
3536 case STD_T_FRQP:
3537 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3538 appctx->ctx.table.proxy->table.data_arg[dt].u);
3539 break;
3540 }
3541
3542 /* skip the entry if the data does not match the test and the value */
3543 if ((data < appctx->ctx.table.value &&
3544 (appctx->ctx.table.data_op == STD_OP_EQ ||
3545 appctx->ctx.table.data_op == STD_OP_GT ||
3546 appctx->ctx.table.data_op == STD_OP_GE)) ||
3547 (data == appctx->ctx.table.value &&
3548 (appctx->ctx.table.data_op == STD_OP_NE ||
3549 appctx->ctx.table.data_op == STD_OP_GT ||
3550 appctx->ctx.table.data_op == STD_OP_LT)) ||
3551 (data > appctx->ctx.table.value &&
3552 (appctx->ctx.table.data_op == STD_OP_EQ ||
3553 appctx->ctx.table.data_op == STD_OP_LT ||
3554 appctx->ctx.table.data_op == STD_OP_LE)))
3555 skip_entry = 1;
3556 }
3557
3558 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003559 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003560 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003561 return 0;
3562 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003563
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003564 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003565
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003566 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003567 appctx->ctx.table.entry->ref_cnt--;
3568
3569 eb = ebmb_next(&appctx->ctx.table.entry->key);
3570 if (eb) {
3571 struct stksess *old = appctx->ctx.table.entry;
3572 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3573 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003574 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003575 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003576 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003577 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003578 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003579 break;
3580 }
3581
3582
3583 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003584 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003585 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003586 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3587
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003588 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003589
3590 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3591 appctx->st2 = STAT_ST_INFO;
3592 break;
3593
3594 case STAT_ST_END:
3595 appctx->st2 = STAT_ST_FIN;
3596 break;
3597 }
3598 }
3599 return 1;
3600}
3601
3602static void cli_release_show_table(struct appctx *appctx)
3603{
3604 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003605 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003606 }
3607}
3608
3609/* register cli keywords */
3610static struct cli_kw_list cli_kws = {{ },{
3611 { { "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 },
3612 { { "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 },
3613 { { "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 },
3614 {{},}
3615}};
3616
3617
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003618static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003619 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003620 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003621 { "sc-set-gpt0", parse_set_gpt0, 1 },
3622 { /* END */ }
3623}};
3624
Willy Tarreau620408f2016-10-21 16:37:51 +02003625static struct action_kw_list tcp_sess_kws = { { }, {
3626 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003627 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003628 { "sc-set-gpt0", parse_set_gpt0, 1 },
3629 { /* END */ }
3630}};
3631
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003632static struct action_kw_list tcp_req_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
3639static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003640 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003641 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003642 { "sc-set-gpt0", parse_set_gpt0, 1 },
3643 { /* END */ }
3644}};
3645
3646static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003647 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003648 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003649 { "sc-set-gpt0", parse_set_gpt0, 1 },
3650 { /* END */ }
3651}};
3652
3653static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003654 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003655 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003656 { "sc-set-gpt0", parse_set_gpt0, 1 },
3657 { /* END */ }
3658}};
3659
Willy Tarreau7d562212016-11-25 16:10:05 +01003660///* Note: must not be declared <const> as its list will be overwritten.
3661// * Please take care of keeping this list alphabetically sorted.
3662// */
3663//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3664// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3665// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3666// { /* END */ },
3667//}};
3668/* Note: must not be declared <const> as its list will be overwritten.
3669 * Please take care of keeping this list alphabetically sorted.
3670 */
3671static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3672 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3673 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3674 { "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 +01003675 { "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 +01003676 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3677 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3678 { "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 +01003679 { "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 +01003680 { "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 +01003681 { "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 +01003682 { "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 +01003683 { "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 +01003684 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3685 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3686 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3687 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3688 { "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 +01003689 { "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 +01003690 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3691 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3692 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3693 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3694 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3695 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3696 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3697 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3698 { "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 +01003699 { "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 +01003700 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3701 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3702 { "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 +01003703 { "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 +01003704 { "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 +01003705 { "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 +01003706 { "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 +01003707 { "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 +01003708 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3709 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3710 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3711 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3712 { "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 +01003713 { "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 +01003714 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3715 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3716 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3717 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3718 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3719 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3720 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3721 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3722 { "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 +01003723 { "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 +01003724 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3725 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3726 { "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 +01003727 { "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 +01003728 { "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 +01003729 { "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 +01003730 { "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 +01003731 { "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 +01003732 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3733 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3734 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3735 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3736 { "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 +01003737 { "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 +01003738 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3739 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3740 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3741 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3742 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3743 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3744 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3745 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3746 { "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 +01003747 { "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 +01003748 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3749 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3750 { "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 +01003751 { "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 +01003752 { "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 +01003753 { "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 +01003754 { "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 +01003755 { "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 +01003756 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3757 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3758 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3759 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3760 { "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 +01003761 { "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 +01003762 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3763 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3764 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3765 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3766 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3767 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3768 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3769 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3770 { "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 +01003771 { "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 +01003772 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3773 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3774 { "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 +01003775 { "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 +01003776 { "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 +01003777 { "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 +01003778 { "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 +01003779 { "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 +01003780 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3781 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3782 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3783 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3784 { "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 +01003785 { "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 +01003786 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3787 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3788 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3789 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3790 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3791 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3792 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3793 { /* END */ },
3794}};
3795
3796
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003797/* Note: must not be declared <const> as its list will be overwritten */
3798static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003799 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3800 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3801 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3802 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3803 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3804 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3805 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3806 { "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 +01003807 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003808 { "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 +01003809 { "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 +02003810 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3811 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3812 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3813 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3814 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3815 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3816 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3817 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3818 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3819 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003820 { /* END */ },
3821}};
3822
3823__attribute__((constructor))
3824static void __stick_table_init(void)
3825{
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003826 /* register som action keywords. */
3827 tcp_req_conn_keywords_register(&tcp_conn_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +02003828 tcp_req_sess_keywords_register(&tcp_sess_kws);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003829 tcp_req_cont_keywords_register(&tcp_req_kws);
3830 tcp_res_cont_keywords_register(&tcp_res_kws);
3831 http_req_keywords_register(&http_req_kws);
3832 http_res_keywords_register(&http_res_kws);
3833
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003834 /* register sample fetch and format conversion keywords */
Willy Tarreau7d562212016-11-25 16:10:05 +01003835 sample_register_fetches(&smp_fetch_keywords);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003836 sample_register_convs(&sample_conv_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003837 cli_register_kw(&cli_kws);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003838}