blob: 101a4e253f01d7389a0344f1c4bd80474d418129 [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 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200581static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100582{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200583 struct stktable *t = 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;
Daniel Corbett3e60b112018-05-27 09:47:12 -0400878 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200879 return 1;
880}
881
882/* Casts sample <smp> to the type of the table specified in arg(0), and looks
883 * it up into this table. Returns the data rate received from clients in bytes/s
884 * if the key is present in the table, otherwise zero, so that comparisons can
885 * be easily performed. If the inspected parameter is not stored in the table,
886 * <not found> is returned.
887 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200888static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200889{
890 struct stktable *t;
891 struct stktable_key *key;
892 struct stksess *ts;
893 void *ptr;
894
895 t = &arg_p[0].data.prx->table;
896
897 key = smp_to_stkey(smp, t);
898 if (!key)
899 return 0;
900
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200901 ts = stktable_lookup_key(t, key);
902
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200903 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200904 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200905 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200906
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200907 if (!ts) /* key not present */
908 return 1;
909
910 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400911 if (ptr)
912 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
913 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200914
Daniel Corbett3e60b112018-05-27 09:47:12 -0400915 stktable_release(t, ts);
916 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200917}
918
919/* Casts sample <smp> to the type of the table specified in arg(0), and looks
920 * it up into this table. Returns the cumulated number of connections for the key
921 * if the key is present in the table, otherwise zero, so that comparisons can
922 * be easily performed. If the inspected parameter is not stored in the table,
923 * <not found> is returned.
924 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200925static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200926{
927 struct stktable *t;
928 struct stktable_key *key;
929 struct stksess *ts;
930 void *ptr;
931
932 t = &arg_p[0].data.prx->table;
933
934 key = smp_to_stkey(smp, t);
935 if (!key)
936 return 0;
937
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200938 ts = stktable_lookup_key(t, key);
939
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200940 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200941 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200942 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200943
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200944 if (!ts) /* key not present */
945 return 1;
946
947 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400948 if (ptr)
949 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200950
Daniel Corbett3e60b112018-05-27 09:47:12 -0400951 stktable_release(t, ts);
952 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200953}
954
955/* Casts sample <smp> to the type of the table specified in arg(0), and looks
956 * it up into this table. Returns the number of concurrent connections for the
957 * key if the key is present in the table, otherwise zero, so that comparisons
958 * can be easily performed. If the inspected parameter is not stored in the
959 * table, <not found> is returned.
960 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200961static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200962{
963 struct stktable *t;
964 struct stktable_key *key;
965 struct stksess *ts;
966 void *ptr;
967
968 t = &arg_p[0].data.prx->table;
969
970 key = smp_to_stkey(smp, t);
971 if (!key)
972 return 0;
973
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200974 ts = stktable_lookup_key(t, key);
975
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200976 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200977 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200978 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200979
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200980 if (!ts) /* key not present */
981 return 1;
982
983 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400984 if (ptr)
985 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200986
Daniel Corbett3e60b112018-05-27 09:47:12 -0400987 stktable_release(t, ts);
988 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200989}
990
991/* Casts sample <smp> to the type of the table specified in arg(0), and looks
992 * it up into this table. Returns the rate of incoming connections from the key
993 * if the key is present in the table, otherwise zero, so that comparisons can
994 * be easily performed. If the inspected parameter is not stored in the table,
995 * <not found> is returned.
996 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200997static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200998{
999 struct stktable *t;
1000 struct stktable_key *key;
1001 struct stksess *ts;
1002 void *ptr;
1003
1004 t = &arg_p[0].data.prx->table;
1005
1006 key = smp_to_stkey(smp, t);
1007 if (!key)
1008 return 0;
1009
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001010 ts = stktable_lookup_key(t, key);
1011
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001012 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001013 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001014 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001015
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001016 if (!ts) /* key not present */
1017 return 1;
1018
1019 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001020 if (ptr)
1021 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1022 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001023
Daniel Corbett3e60b112018-05-27 09:47:12 -04001024 stktable_release(t, ts);
1025 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001026}
1027
1028/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1029 * it up into this table. Returns the data rate sent to clients in bytes/s
1030 * if the key is present in the table, otherwise zero, so that comparisons can
1031 * be easily performed. If the inspected parameter is not stored in the table,
1032 * <not found> is returned.
1033 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001034static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001035{
1036 struct stktable *t;
1037 struct stktable_key *key;
1038 struct stksess *ts;
1039 void *ptr;
1040
1041 t = &arg_p[0].data.prx->table;
1042
1043 key = smp_to_stkey(smp, t);
1044 if (!key)
1045 return 0;
1046
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001047 ts = stktable_lookup_key(t, key);
1048
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001049 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001050 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001051 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001052
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001053 if (!ts) /* key not present */
1054 return 1;
1055
1056 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001057 if (ptr)
1058 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1059 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001060
Daniel Corbett3e60b112018-05-27 09:47:12 -04001061 stktable_release(t, ts);
1062 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001063}
1064
1065/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001066 * it up into this table. Returns the value of the GPT0 tag for the key
1067 * if the key is present in the table, otherwise false, so that comparisons can
1068 * be easily performed. If the inspected parameter is not stored in the table,
1069 * <not found> is returned.
1070 */
1071static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1072{
1073 struct stktable *t;
1074 struct stktable_key *key;
1075 struct stksess *ts;
1076 void *ptr;
1077
1078 t = &arg_p[0].data.prx->table;
1079
1080 key = smp_to_stkey(smp, t);
1081 if (!key)
1082 return 0;
1083
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001084 ts = stktable_lookup_key(t, key);
1085
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001086 smp->flags = SMP_F_VOL_TEST;
1087 smp->data.type = SMP_T_SINT;
1088 smp->data.u.sint = 0;
1089
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001090 if (!ts) /* key not present */
1091 return 1;
1092
1093 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001094 if (ptr)
1095 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001096
Daniel Corbett3e60b112018-05-27 09:47:12 -04001097 stktable_release(t, ts);
1098 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001099}
1100
1101/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001102 * it up into this table. Returns the value of the GPC0 counter for the key
1103 * if the key is present in the table, otherwise zero, so that comparisons can
1104 * be easily performed. If the inspected parameter is not stored in the table,
1105 * <not found> is returned.
1106 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001107static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001108{
1109 struct stktable *t;
1110 struct stktable_key *key;
1111 struct stksess *ts;
1112 void *ptr;
1113
1114 t = &arg_p[0].data.prx->table;
1115
1116 key = smp_to_stkey(smp, t);
1117 if (!key)
1118 return 0;
1119
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001120 ts = stktable_lookup_key(t, key);
1121
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001122 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001123 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001124 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001125
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001126 if (!ts) /* key not present */
1127 return 1;
1128
1129 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001130 if (ptr)
1131 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001132
Daniel Corbett3e60b112018-05-27 09:47:12 -04001133 stktable_release(t, ts);
1134 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001135}
1136
1137/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1138 * it up into this table. Returns the event rate of the GPC0 counter for the key
1139 * if the key is present in the table, otherwise zero, so that comparisons can
1140 * be easily performed. If the inspected parameter is not stored in the table,
1141 * <not found> is returned.
1142 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001143static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001144{
1145 struct stktable *t;
1146 struct stktable_key *key;
1147 struct stksess *ts;
1148 void *ptr;
1149
1150 t = &arg_p[0].data.prx->table;
1151
1152 key = smp_to_stkey(smp, t);
1153 if (!key)
1154 return 0;
1155
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001156 ts = stktable_lookup_key(t, key);
1157
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001158 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001159 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001160 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001161
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001162 if (!ts) /* key not present */
1163 return 1;
1164
1165 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001166 if (ptr)
1167 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1168 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001169
Daniel Corbett3e60b112018-05-27 09:47:12 -04001170 stktable_release(t, ts);
1171 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001172}
1173
1174/* 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 +01001175 * it up into this table. Returns the value of the GPC1 counter for the key
1176 * if the key is present in the table, otherwise zero, so that comparisons can
1177 * be easily performed. If the inspected parameter is not stored in the table,
1178 * <not found> is returned.
1179 */
1180static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1181{
1182 struct stktable *t;
1183 struct stktable_key *key;
1184 struct stksess *ts;
1185 void *ptr;
1186
1187 t = &arg_p[0].data.prx->table;
1188
1189 key = smp_to_stkey(smp, t);
1190 if (!key)
1191 return 0;
1192
1193 ts = stktable_lookup_key(t, key);
1194
1195 smp->flags = SMP_F_VOL_TEST;
1196 smp->data.type = SMP_T_SINT;
1197 smp->data.u.sint = 0;
1198
1199 if (!ts) /* key not present */
1200 return 1;
1201
1202 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001203 if (ptr)
1204 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001205
Daniel Corbett3e60b112018-05-27 09:47:12 -04001206 stktable_release(t, ts);
1207 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001208}
1209
1210/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1211 * it up into this table. Returns the event rate of the GPC1 counter for the key
1212 * if the key is present in the table, otherwise zero, so that comparisons can
1213 * be easily performed. If the inspected parameter is not stored in the table,
1214 * <not found> is returned.
1215 */
1216static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1217{
1218 struct stktable *t;
1219 struct stktable_key *key;
1220 struct stksess *ts;
1221 void *ptr;
1222
1223 t = &arg_p[0].data.prx->table;
1224
1225 key = smp_to_stkey(smp, t);
1226 if (!key)
1227 return 0;
1228
1229 ts = stktable_lookup_key(t, key);
1230
1231 smp->flags = SMP_F_VOL_TEST;
1232 smp->data.type = SMP_T_SINT;
1233 smp->data.u.sint = 0;
1234
1235 if (!ts) /* key not present */
1236 return 1;
1237
1238 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001239 if (ptr)
1240 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1241 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001242
Daniel Corbett3e60b112018-05-27 09:47:12 -04001243 stktable_release(t, ts);
1244 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001245}
1246
1247/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001248 * it up into this table. Returns the cumulated number of HTTP request errors
1249 * for the key if the key is present in the table, otherwise zero, so that
1250 * comparisons can be easily performed. If the inspected parameter is not stored
1251 * in the table, <not found> is returned.
1252 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001253static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001254{
1255 struct stktable *t;
1256 struct stktable_key *key;
1257 struct stksess *ts;
1258 void *ptr;
1259
1260 t = &arg_p[0].data.prx->table;
1261
1262 key = smp_to_stkey(smp, t);
1263 if (!key)
1264 return 0;
1265
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001266 ts = stktable_lookup_key(t, key);
1267
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001268 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001269 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001270 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001272 if (!ts) /* key not present */
1273 return 1;
1274
1275 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001276 if (ptr)
1277 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001278
Daniel Corbett3e60b112018-05-27 09:47:12 -04001279 stktable_release(t, ts);
1280 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281}
1282
1283/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1284 * it up into this table. Returns the HTTP request error rate the key
1285 * if the key is present in the table, otherwise zero, so that comparisons can
1286 * be easily performed. If the inspected parameter is not stored in the table,
1287 * <not found> is returned.
1288 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001289static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001290{
1291 struct stktable *t;
1292 struct stktable_key *key;
1293 struct stksess *ts;
1294 void *ptr;
1295
1296 t = &arg_p[0].data.prx->table;
1297
1298 key = smp_to_stkey(smp, t);
1299 if (!key)
1300 return 0;
1301
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001302 ts = stktable_lookup_key(t, key);
1303
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001304 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001305 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001306 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001308 if (!ts) /* key not present */
1309 return 1;
1310
1311 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001312 if (ptr)
1313 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1314 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001315
Daniel Corbett3e60b112018-05-27 09:47:12 -04001316 stktable_release(t, ts);
1317 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001318}
1319
1320/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1321 * it up into this table. Returns the cumulated number of HTTP request for the
1322 * key if the key is present in the table, otherwise zero, so that comparisons
1323 * can be easily performed. If the inspected parameter is not stored in the
1324 * table, <not found> is returned.
1325 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001326static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001327{
1328 struct stktable *t;
1329 struct stktable_key *key;
1330 struct stksess *ts;
1331 void *ptr;
1332
1333 t = &arg_p[0].data.prx->table;
1334
1335 key = smp_to_stkey(smp, t);
1336 if (!key)
1337 return 0;
1338
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001339 ts = stktable_lookup_key(t, key);
1340
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001342 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001343 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001345 if (!ts) /* key not present */
1346 return 1;
1347
1348 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001349 if (ptr)
1350 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001351
Daniel Corbett3e60b112018-05-27 09:47:12 -04001352 stktable_release(t, ts);
1353 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354}
1355
1356/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1357 * it up into this table. Returns the HTTP request rate the key if the key is
1358 * present in the table, otherwise zero, so that comparisons can be easily
1359 * performed. If the inspected parameter is not stored in the table, <not found>
1360 * is returned.
1361 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001362static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001363{
1364 struct stktable *t;
1365 struct stktable_key *key;
1366 struct stksess *ts;
1367 void *ptr;
1368
1369 t = &arg_p[0].data.prx->table;
1370
1371 key = smp_to_stkey(smp, t);
1372 if (!key)
1373 return 0;
1374
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001375 ts = stktable_lookup_key(t, key);
1376
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001378 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001379 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001381 if (!ts) /* key not present */
1382 return 1;
1383
1384 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001385 if (ptr)
1386 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1387 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001388
Daniel Corbett3e60b112018-05-27 09:47:12 -04001389 stktable_release(t, ts);
1390 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391}
1392
1393/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1394 * it up into this table. Returns the volume of datareceived from clients in kbytes
1395 * if the key is present in the table, otherwise zero, so that comparisons can
1396 * be easily performed. If the inspected parameter is not stored in the table,
1397 * <not found> is returned.
1398 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001399static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001400{
1401 struct stktable *t;
1402 struct stktable_key *key;
1403 struct stksess *ts;
1404 void *ptr;
1405
1406 t = &arg_p[0].data.prx->table;
1407
1408 key = smp_to_stkey(smp, t);
1409 if (!key)
1410 return 0;
1411
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001412 ts = stktable_lookup_key(t, key);
1413
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001414 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001415 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001416 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001418 if (!ts) /* key not present */
1419 return 1;
1420
1421 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001422 if (ptr)
1423 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001424
Daniel Corbett3e60b112018-05-27 09:47:12 -04001425 stktable_release(t, ts);
1426 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001427}
1428
1429/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1430 * it up into this table. Returns the volume of data sent to clients in kbytes
1431 * if the key is present in the table, otherwise zero, so that comparisons can
1432 * be easily performed. If the inspected parameter is not stored in the table,
1433 * <not found> is returned.
1434 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001435static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001436{
1437 struct stktable *t;
1438 struct stktable_key *key;
1439 struct stksess *ts;
1440 void *ptr;
1441
1442 t = &arg_p[0].data.prx->table;
1443
1444 key = smp_to_stkey(smp, t);
1445 if (!key)
1446 return 0;
1447
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001448 ts = stktable_lookup_key(t, key);
1449
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001450 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001451 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001452 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001454 if (!ts) /* key not present */
1455 return 1;
1456
1457 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001458 if (ptr)
1459 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001460
Daniel Corbett3e60b112018-05-27 09:47:12 -04001461 stktable_release(t, ts);
1462 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001463}
1464
1465/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1466 * it up into this table. Returns the server ID associated with the key if the
1467 * key is present in the table, otherwise zero, so that comparisons can be
1468 * easily performed. If the inspected parameter is not stored in the table,
1469 * <not found> is returned.
1470 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001471static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001472{
1473 struct stktable *t;
1474 struct stktable_key *key;
1475 struct stksess *ts;
1476 void *ptr;
1477
1478 t = &arg_p[0].data.prx->table;
1479
1480 key = smp_to_stkey(smp, t);
1481 if (!key)
1482 return 0;
1483
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001484 ts = stktable_lookup_key(t, key);
1485
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001486 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001487 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001488 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001489
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001490 if (!ts) /* key not present */
1491 return 1;
1492
1493 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001494 if (ptr)
1495 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001496
Daniel Corbett3e60b112018-05-27 09:47:12 -04001497 stktable_release(t, ts);
1498 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001499}
1500
1501/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1502 * it up into this table. Returns the cumulated number of sessions for the
1503 * key if the key is present in the table, otherwise zero, so that comparisons
1504 * can be easily performed. If the inspected parameter is not stored in the
1505 * table, <not found> is returned.
1506 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001507static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001508{
1509 struct stktable *t;
1510 struct stktable_key *key;
1511 struct stksess *ts;
1512 void *ptr;
1513
1514 t = &arg_p[0].data.prx->table;
1515
1516 key = smp_to_stkey(smp, t);
1517 if (!key)
1518 return 0;
1519
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001520 ts = stktable_lookup_key(t, key);
1521
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001522 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001523 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001524 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001525
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001526 if (!ts) /* key not present */
1527 return 1;
1528
1529 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001530 if (ptr)
1531 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001532
Daniel Corbett3e60b112018-05-27 09:47:12 -04001533 stktable_release(t, ts);
1534 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001535}
1536
1537/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1538 * it up into this table. Returns the session rate the key if the key is
1539 * present in the table, otherwise zero, so that comparisons can be easily
1540 * performed. If the inspected parameter is not stored in the table, <not found>
1541 * is returned.
1542 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001543static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001544{
1545 struct stktable *t;
1546 struct stktable_key *key;
1547 struct stksess *ts;
1548 void *ptr;
1549
1550 t = &arg_p[0].data.prx->table;
1551
1552 key = smp_to_stkey(smp, t);
1553 if (!key)
1554 return 0;
1555
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001556 ts = stktable_lookup_key(t, key);
1557
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001558 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001559 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001560 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001561
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001562 if (!ts) /* key not present */
1563 return 1;
1564
1565 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001566 if (ptr)
1567 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1568 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001569
Daniel Corbett3e60b112018-05-27 09:47:12 -04001570 stktable_release(t, ts);
1571 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001572}
1573
1574/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1575 * it up into this table. Returns the amount of concurrent connections tracking
1576 * the same key if the key is present in the table, otherwise zero, so that
1577 * comparisons can be easily performed. If the inspected parameter is not
1578 * stored in the table, <not found> is returned.
1579 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001580static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001581{
1582 struct stktable *t;
1583 struct stktable_key *key;
1584 struct stksess *ts;
1585
1586 t = &arg_p[0].data.prx->table;
1587
1588 key = smp_to_stkey(smp, t);
1589 if (!key)
1590 return 0;
1591
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001592 ts = stktable_lookup_key(t, key);
1593
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001594 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001595 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001596 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001597
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001598 if (ts)
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001599 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001600
Daniel Corbett3e60b112018-05-27 09:47:12 -04001601 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001602 return 1;
1603}
1604
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001605/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001606static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001607 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001608{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001609 struct stksess *ts;
1610 struct stkctr *stkctr;
1611
1612 /* Extract the stksess, return OK if no stksess available. */
1613 if (s)
1614 stkctr = &s->stkctr[rule->arg.gpc.sc];
1615 else
1616 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001617
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001618 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001619 if (ts) {
1620 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001621
Willy Tarreau79c1e912016-01-25 14:54:45 +01001622 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1623 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001624 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1625 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001626 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001627
1628 if (ptr1)
1629 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001630 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001631
Emeric Brun819fc6f2017-06-13 19:37:32 +02001632 if (ptr2)
1633 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001634
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001635 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001636
1637 /* If data was modified, we need to touch to re-schedule sync */
1638 stktable_touch_local(stkctr->table, ts, 0);
1639 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001640 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001641 return ACT_RET_CONT;
1642}
1643
1644/* This function is a common parser for using variables. It understands
1645 * the formats:
1646 *
1647 * sc-inc-gpc0(<stick-table ID>)
1648 *
1649 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1650 * it returns 1 and the variable <expr> is filled with the pointer to the
1651 * expression to execute.
1652 */
1653static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1654 struct act_rule *rule, char **err)
1655{
1656 const char *cmd_name = args[*arg-1];
1657 char *error;
1658
1659 cmd_name += strlen("sc-inc-gpc0");
1660 if (*cmd_name == '\0') {
1661 /* default stick table id. */
1662 rule->arg.gpc.sc = 0;
1663 } else {
1664 /* parse the stick table id. */
1665 if (*cmd_name != '(') {
1666 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1667 return ACT_RET_PRS_ERR;
1668 }
1669 cmd_name++; /* jump the '(' */
1670 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1671 if (*error != ')') {
1672 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1673 return ACT_RET_PRS_ERR;
1674 }
1675
1676 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1677 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1678 ACT_ACTION_TRK_SCMAX-1);
1679 return ACT_RET_PRS_ERR;
1680 }
1681 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001682 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001683 rule->action_ptr = action_inc_gpc0;
1684 return ACT_RET_PRS_OK;
1685}
1686
1687/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001688static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1689 struct session *sess, struct stream *s, int flags)
1690{
1691 struct stksess *ts;
1692 struct stkctr *stkctr;
1693
1694 /* Extract the stksess, return OK if no stksess available. */
1695 if (s)
1696 stkctr = &s->stkctr[rule->arg.gpc.sc];
1697 else
1698 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1699
1700 ts = stkctr_entry(stkctr);
1701 if (ts) {
1702 void *ptr1, *ptr2;
1703
1704 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1705 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1706 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1707 if (ptr1 || ptr2) {
1708 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1709
1710 if (ptr1)
1711 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1712 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1713
1714 if (ptr2)
1715 stktable_data_cast(ptr2, gpc1)++;
1716
1717 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1718
1719 /* If data was modified, we need to touch to re-schedule sync */
1720 stktable_touch_local(stkctr->table, ts, 0);
1721 }
1722 }
1723 return ACT_RET_CONT;
1724}
1725
1726/* This function is a common parser for using variables. It understands
1727 * the formats:
1728 *
1729 * sc-inc-gpc1(<stick-table ID>)
1730 *
1731 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1732 * it returns 1 and the variable <expr> is filled with the pointer to the
1733 * expression to execute.
1734 */
1735static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1736 struct act_rule *rule, char **err)
1737{
1738 const char *cmd_name = args[*arg-1];
1739 char *error;
1740
1741 cmd_name += strlen("sc-inc-gpc1");
1742 if (*cmd_name == '\0') {
1743 /* default stick table id. */
1744 rule->arg.gpc.sc = 0;
1745 } else {
1746 /* parse the stick table id. */
1747 if (*cmd_name != '(') {
1748 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1749 return ACT_RET_PRS_ERR;
1750 }
1751 cmd_name++; /* jump the '(' */
1752 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1753 if (*error != ')') {
1754 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1755 return ACT_RET_PRS_ERR;
1756 }
1757
1758 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1759 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1760 ACT_ACTION_TRK_SCMAX-1);
1761 return ACT_RET_PRS_ERR;
1762 }
1763 }
1764 rule->action = ACT_CUSTOM;
1765 rule->action_ptr = action_inc_gpc1;
1766 return ACT_RET_PRS_OK;
1767}
1768
1769/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001770static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001771 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001772{
1773 void *ptr;
1774 struct stksess *ts;
1775 struct stkctr *stkctr;
1776
1777 /* Extract the stksess, return OK if no stksess available. */
1778 if (s)
1779 stkctr = &s->stkctr[rule->arg.gpt.sc];
1780 else
1781 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001782
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001783 ts = stkctr_entry(stkctr);
1784 if (!ts)
1785 return ACT_RET_CONT;
1786
1787 /* Store the sample in the required sc, and ignore errors. */
1788 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001789 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001790 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001791
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001792 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001793
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001794 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001795
1796 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001797 }
1798
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001799 return ACT_RET_CONT;
1800}
1801
1802/* This function is a common parser for using variables. It understands
1803 * the format:
1804 *
1805 * set-gpt0(<stick-table ID>) <expression>
1806 *
1807 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1808 * it returns 1 and the variable <expr> is filled with the pointer to the
1809 * expression to execute.
1810 */
1811static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1812 struct act_rule *rule, char **err)
1813
1814
1815{
1816 const char *cmd_name = args[*arg-1];
1817 char *error;
1818
1819 cmd_name += strlen("sc-set-gpt0");
1820 if (*cmd_name == '\0') {
1821 /* default stick table id. */
1822 rule->arg.gpt.sc = 0;
1823 } else {
1824 /* parse the stick table id. */
1825 if (*cmd_name != '(') {
1826 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1827 return ACT_RET_PRS_ERR;
1828 }
1829 cmd_name++; /* jump the '(' */
1830 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1831 if (*error != ')') {
1832 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1833 return ACT_RET_PRS_ERR;
1834 }
1835
1836 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1837 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1838 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1839 return ACT_RET_PRS_ERR;
1840 }
1841 }
1842
1843 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1844 if (*error != '\0') {
1845 memprintf(err, "invalid integer value '%s'", args[*arg]);
1846 return ACT_RET_PRS_ERR;
1847 }
1848 (*arg)++;
1849
Thierry FOURNIER42148732015-09-02 17:17:33 +02001850 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001851 rule->action_ptr = action_set_gpt0;
1852
1853 return ACT_RET_PRS_OK;
1854}
1855
Willy Tarreau7d562212016-11-25 16:10:05 +01001856/* set temp integer to the number of used entries in the table pointed to by expr.
1857 * Accepts exactly 1 argument of type table.
1858 */
1859static int
1860smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1861{
1862 smp->flags = SMP_F_VOL_TEST;
1863 smp->data.type = SMP_T_SINT;
1864 smp->data.u.sint = args->data.prx->table.current;
1865 return 1;
1866}
1867
1868/* set temp integer to the number of free entries in the table pointed to by expr.
1869 * Accepts exactly 1 argument of type table.
1870 */
1871static int
1872smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1873{
1874 struct proxy *px;
1875
1876 px = args->data.prx;
1877 smp->flags = SMP_F_VOL_TEST;
1878 smp->data.type = SMP_T_SINT;
1879 smp->data.u.sint = px->table.size - px->table.current;
1880 return 1;
1881}
1882
1883/* Returns a pointer to a stkctr depending on the fetch keyword name.
1884 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1885 * sc[0-9]_* will return a pointer to the respective field in the
1886 * stream <l4>. sc_* requires an UINT argument specifying the stick
1887 * counter number. src_* will fill a locally allocated structure with
1888 * the table and entry corresponding to what is specified with src_*.
1889 * NULL may be returned if the designated stkctr is not tracked. For
1890 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1891 * passed. When present, the currently tracked key is then looked up
1892 * in the specified table instead of the current table. The purpose is
1893 * to be able to convery multiple values per key (eg: have gpc0 from
1894 * multiple tables). <strm> is allowed to be NULL, in which case only
1895 * the session will be consulted.
1896 */
1897struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001898smp_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 +01001899{
Willy Tarreau7d562212016-11-25 16:10:05 +01001900 struct stkctr *stkptr;
1901 struct stksess *stksess;
1902 unsigned int num = kw[2] - '0';
1903 int arg = 0;
1904
1905 if (num == '_' - '0') {
1906 /* sc_* variant, args[0] = ctr# (mandatory) */
1907 num = args[arg++].data.sint;
1908 if (num >= MAX_SESS_STKCTR)
1909 return NULL;
1910 }
1911 else if (num > 9) { /* src_* variant, args[0] = table */
1912 struct stktable_key *key;
1913 struct connection *conn = objt_conn(sess->origin);
1914 struct sample smp;
1915
1916 if (!conn)
1917 return NULL;
1918
1919 /* Fetch source adress in a sample. */
1920 smp.px = NULL;
1921 smp.sess = sess;
1922 smp.strm = strm;
1923 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1924 return NULL;
1925
1926 /* Converts into key. */
1927 key = smp_to_stkey(&smp, &args->data.prx->table);
1928 if (!key)
1929 return NULL;
1930
Emeric Brun819fc6f2017-06-13 19:37:32 +02001931 stkctr->table = &args->data.prx->table;
1932 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1933 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001934 }
1935
1936 /* Here, <num> contains the counter number from 0 to 9 for
1937 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1938 * args[arg] is the first optional argument. We first lookup the
1939 * ctr form the stream, then from the session if it was not there.
1940 */
1941
1942 if (strm)
1943 stkptr = &strm->stkctr[num];
1944 if (!strm || !stkctr_entry(stkptr)) {
1945 stkptr = &sess->stkctr[num];
1946 if (!stkctr_entry(stkptr))
1947 return NULL;
1948 }
1949
1950 stksess = stkctr_entry(stkptr);
1951 if (!stksess)
1952 return NULL;
1953
1954 if (unlikely(args[arg].type == ARGT_TAB)) {
1955 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001956 stkctr->table = &args[arg].data.prx->table;
1957 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1958 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001959 }
1960 return stkptr;
1961}
1962
1963/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1964 * the entry if it doesn't exist yet. This is needed for a few fetch
1965 * functions which need to create an entry, such as src_inc_gpc* and
1966 * src_clr_gpc*.
1967 */
1968struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001969smp_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 +01001970{
Willy Tarreau7d562212016-11-25 16:10:05 +01001971 struct stktable_key *key;
1972 struct connection *conn = objt_conn(sess->origin);
1973 struct sample smp;
1974
1975 if (strncmp(kw, "src_", 4) != 0)
1976 return NULL;
1977
1978 if (!conn)
1979 return NULL;
1980
1981 /* Fetch source adress in a sample. */
1982 smp.px = NULL;
1983 smp.sess = sess;
1984 smp.strm = strm;
1985 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1986 return NULL;
1987
1988 /* Converts into key. */
1989 key = smp_to_stkey(&smp, &args->data.prx->table);
1990 if (!key)
1991 return NULL;
1992
Emeric Brun819fc6f2017-06-13 19:37:32 +02001993 stkctr->table = &args->data.prx->table;
1994 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
1995 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001996}
1997
1998/* set return a boolean indicating if the requested stream counter is
1999 * currently being tracked or not.
2000 * Supports being called as "sc[0-9]_tracked" only.
2001 */
2002static int
2003smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2004{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002005 struct stkctr tmpstkctr;
2006 struct stkctr *stkctr;
2007
Willy Tarreau7d562212016-11-25 16:10:05 +01002008 smp->flags = SMP_F_VOL_TEST;
2009 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002010 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2011 smp->data.u.sint = !!stkctr;
2012
2013 /* release the ref count */
2014 if ((stkctr == &tmpstkctr) && stkctr_entry(stkctr))
2015 stktable_release(stkctr->table, stkctr_entry(stkctr));
2016
Willy Tarreau7d562212016-11-25 16:10:05 +01002017 return 1;
2018}
2019
2020/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2021 * frontend counters or from the src.
2022 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2023 * zero is returned if the key is new.
2024 */
2025static int
2026smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2027{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002028 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002029 struct stkctr *stkctr;
2030
Emeric Brun819fc6f2017-06-13 19:37:32 +02002031 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002032 if (!stkctr)
2033 return 0;
2034
2035 smp->flags = SMP_F_VOL_TEST;
2036 smp->data.type = SMP_T_SINT;
2037 smp->data.u.sint = 0;
2038
Emeric Brun819fc6f2017-06-13 19:37:32 +02002039 if (stkctr_entry(stkctr)) {
2040 void *ptr;
2041
2042 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2043 if (!ptr) {
2044 if (stkctr == &tmpstkctr)
2045 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002046 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002047 }
2048
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002049 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002050
Willy Tarreau7d562212016-11-25 16:10:05 +01002051 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002052
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002053 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002054
2055 if (stkctr == &tmpstkctr)
2056 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002057 }
2058 return 1;
2059}
2060
2061/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2062 * frontend counters or from the src.
2063 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2064 * zero is returned if the key is new.
2065 */
2066static int
2067smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2068{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002069 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002070 struct stkctr *stkctr;
2071
Emeric Brun819fc6f2017-06-13 19:37:32 +02002072 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002073 if (!stkctr)
2074 return 0;
2075
2076 smp->flags = SMP_F_VOL_TEST;
2077 smp->data.type = SMP_T_SINT;
2078 smp->data.u.sint = 0;
2079
2080 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002081 void *ptr;
2082
2083 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2084 if (!ptr) {
2085 if (stkctr == &tmpstkctr)
2086 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002087 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002088 }
2089
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002090 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002091
Willy Tarreau7d562212016-11-25 16:10:05 +01002092 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002093
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002094 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002095
2096 if (stkctr == &tmpstkctr)
2097 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002098 }
2099 return 1;
2100}
2101
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002102/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2103 * frontend counters or from the src.
2104 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2105 * zero is returned if the key is new.
2106 */
2107static int
2108smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2109{
2110 struct stkctr tmpstkctr;
2111 struct stkctr *stkctr;
2112
2113 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2114 if (!stkctr)
2115 return 0;
2116
2117 smp->flags = SMP_F_VOL_TEST;
2118 smp->data.type = SMP_T_SINT;
2119 smp->data.u.sint = 0;
2120
2121 if (stkctr_entry(stkctr) != NULL) {
2122 void *ptr;
2123
2124 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2125 if (!ptr) {
2126 if (stkctr == &tmpstkctr)
2127 stktable_release(stkctr->table, stkctr_entry(stkctr));
2128 return 0; /* parameter not stored */
2129 }
2130
2131 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2132
2133 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2134
2135 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2136
2137 if (stkctr == &tmpstkctr)
2138 stktable_release(stkctr->table, stkctr_entry(stkctr));
2139 }
2140 return 1;
2141}
2142
Willy Tarreau7d562212016-11-25 16:10:05 +01002143/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2144 * tracked frontend counters or from the src.
2145 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2146 * Value zero is returned if the key is new.
2147 */
2148static int
2149smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2150{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002151 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002152 struct stkctr *stkctr;
2153
Emeric Brun819fc6f2017-06-13 19:37:32 +02002154 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002155 if (!stkctr)
2156 return 0;
2157
2158 smp->flags = SMP_F_VOL_TEST;
2159 smp->data.type = SMP_T_SINT;
2160 smp->data.u.sint = 0;
2161 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002162 void *ptr;
2163
2164 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2165 if (!ptr) {
2166 if (stkctr == &tmpstkctr)
2167 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002168 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002169 }
2170
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002171 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002172
Willy Tarreau7d562212016-11-25 16:10:05 +01002173 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2174 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002175
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002176 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002177
2178 if (stkctr == &tmpstkctr)
2179 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002180 }
2181 return 1;
2182}
2183
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002184/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2185 * tracked frontend counters or from the src.
2186 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2187 * Value zero is returned if the key is new.
2188 */
2189static int
2190smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2191{
2192 struct stkctr tmpstkctr;
2193 struct stkctr *stkctr;
2194
2195 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2196 if (!stkctr)
2197 return 0;
2198
2199 smp->flags = SMP_F_VOL_TEST;
2200 smp->data.type = SMP_T_SINT;
2201 smp->data.u.sint = 0;
2202 if (stkctr_entry(stkctr) != NULL) {
2203 void *ptr;
2204
2205 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2206 if (!ptr) {
2207 if (stkctr == &tmpstkctr)
2208 stktable_release(stkctr->table, stkctr_entry(stkctr));
2209 return 0; /* parameter not stored */
2210 }
2211
2212 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2213
2214 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2215 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2216
2217 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2218
2219 if (stkctr == &tmpstkctr)
2220 stktable_release(stkctr->table, stkctr_entry(stkctr));
2221 }
2222 return 1;
2223}
2224
Willy Tarreau7d562212016-11-25 16:10:05 +01002225/* Increment the General Purpose Counter 0 value from the stream's tracked
2226 * frontend counters and return it into temp integer.
2227 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2228 */
2229static int
2230smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2231{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002232 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002233 struct stkctr *stkctr;
2234
Emeric Brun819fc6f2017-06-13 19:37:32 +02002235 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002236 if (!stkctr)
2237 return 0;
2238
2239 smp->flags = SMP_F_VOL_TEST;
2240 smp->data.type = SMP_T_SINT;
2241 smp->data.u.sint = 0;
2242
Emeric Brun819fc6f2017-06-13 19:37:32 +02002243 if (!stkctr_entry(stkctr))
2244 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002245
2246 if (stkctr && stkctr_entry(stkctr)) {
2247 void *ptr1,*ptr2;
2248
Emeric Brun819fc6f2017-06-13 19:37:32 +02002249
Willy Tarreau7d562212016-11-25 16:10:05 +01002250 /* First, update gpc0_rate if it's tracked. Second, update its
2251 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2252 */
2253 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002254 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002255 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002256 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002257
Emeric Brun819fc6f2017-06-13 19:37:32 +02002258 if (ptr1) {
2259 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2260 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2261 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2262 }
2263
2264 if (ptr2)
2265 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2266
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002267 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002268
2269 /* If data was modified, we need to touch to re-schedule sync */
2270 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2271 }
2272 else if (stkctr == &tmpstkctr)
2273 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002274 }
2275 return 1;
2276}
2277
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002278/* Increment the General Purpose Counter 1 value from the stream's tracked
2279 * frontend counters and return it into temp integer.
2280 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2281 */
2282static int
2283smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2284{
2285 struct stkctr tmpstkctr;
2286 struct stkctr *stkctr;
2287
2288 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2289 if (!stkctr)
2290 return 0;
2291
2292 smp->flags = SMP_F_VOL_TEST;
2293 smp->data.type = SMP_T_SINT;
2294 smp->data.u.sint = 0;
2295
2296 if (!stkctr_entry(stkctr))
2297 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2298
2299 if (stkctr && stkctr_entry(stkctr)) {
2300 void *ptr1,*ptr2;
2301
2302
2303 /* First, update gpc1_rate if it's tracked. Second, update its
2304 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2305 */
2306 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2307 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2308 if (ptr1 || ptr2) {
2309 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2310
2311 if (ptr1) {
2312 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2313 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2314 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2315 }
2316
2317 if (ptr2)
2318 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2319
2320 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2321
2322 /* If data was modified, we need to touch to re-schedule sync */
2323 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2324 }
2325 else if (stkctr == &tmpstkctr)
2326 stktable_release(stkctr->table, stkctr_entry(stkctr));
2327 }
2328 return 1;
2329}
2330
Willy Tarreau7d562212016-11-25 16:10:05 +01002331/* Clear the General Purpose Counter 0 value from the stream's tracked
2332 * frontend counters and return its previous value into temp integer.
2333 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2334 */
2335static int
2336smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2337{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002338 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002339 struct stkctr *stkctr;
2340
Emeric Brun819fc6f2017-06-13 19:37:32 +02002341 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002342 if (!stkctr)
2343 return 0;
2344
2345 smp->flags = SMP_F_VOL_TEST;
2346 smp->data.type = SMP_T_SINT;
2347 smp->data.u.sint = 0;
2348
Emeric Brun819fc6f2017-06-13 19:37:32 +02002349 if (!stkctr_entry(stkctr))
2350 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002351
Emeric Brun819fc6f2017-06-13 19:37:32 +02002352 if (stkctr && stkctr_entry(stkctr)) {
2353 void *ptr;
2354
2355 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2356 if (!ptr) {
2357 if (stkctr == &tmpstkctr)
2358 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002359 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002360 }
2361
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002362 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002363
Willy Tarreau7d562212016-11-25 16:10:05 +01002364 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2365 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002366
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002367 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002368
Willy Tarreau7d562212016-11-25 16:10:05 +01002369 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002370 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002371 }
2372 return 1;
2373}
2374
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002375/* Clear the General Purpose Counter 1 value from the stream's tracked
2376 * frontend counters and return its previous value into temp integer.
2377 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2378 */
2379static int
2380smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2381{
2382 struct stkctr tmpstkctr;
2383 struct stkctr *stkctr;
2384
2385 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2386 if (!stkctr)
2387 return 0;
2388
2389 smp->flags = SMP_F_VOL_TEST;
2390 smp->data.type = SMP_T_SINT;
2391 smp->data.u.sint = 0;
2392
2393 if (!stkctr_entry(stkctr))
2394 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2395
2396 if (stkctr && stkctr_entry(stkctr)) {
2397 void *ptr;
2398
2399 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2400 if (!ptr) {
2401 if (stkctr == &tmpstkctr)
2402 stktable_release(stkctr->table, stkctr_entry(stkctr));
2403 return 0; /* parameter not stored */
2404 }
2405
2406 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2407
2408 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2409 stktable_data_cast(ptr, gpc1) = 0;
2410
2411 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2412
2413 /* If data was modified, we need to touch to re-schedule sync */
2414 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2415 }
2416 return 1;
2417}
2418
Willy Tarreau7d562212016-11-25 16:10:05 +01002419/* set <smp> to the cumulated number of connections from the stream's tracked
2420 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2421 * "src_conn_cnt" only.
2422 */
2423static int
2424smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2425{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002426 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002427 struct stkctr *stkctr;
2428
Emeric Brun819fc6f2017-06-13 19:37:32 +02002429 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002430 if (!stkctr)
2431 return 0;
2432
2433 smp->flags = SMP_F_VOL_TEST;
2434 smp->data.type = SMP_T_SINT;
2435 smp->data.u.sint = 0;
2436 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002437 void *ptr;
2438
2439 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2440 if (!ptr) {
2441 if (stkctr == &tmpstkctr)
2442 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002443 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002444 }
2445
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002446 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002447
Willy Tarreau7d562212016-11-25 16:10:05 +01002448 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002449
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002450 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002451
2452 if (stkctr == &tmpstkctr)
2453 stktable_release(stkctr->table, stkctr_entry(stkctr));
2454
2455
Willy Tarreau7d562212016-11-25 16:10:05 +01002456 }
2457 return 1;
2458}
2459
2460/* set <smp> to the connection rate from the stream's tracked frontend
2461 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2462 * only.
2463 */
2464static int
2465smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2466{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002467 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002468 struct stkctr *stkctr;
2469
Emeric Brun819fc6f2017-06-13 19:37:32 +02002470 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002471 if (!stkctr)
2472 return 0;
2473
2474 smp->flags = SMP_F_VOL_TEST;
2475 smp->data.type = SMP_T_SINT;
2476 smp->data.u.sint = 0;
2477 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002478 void *ptr;
2479
2480 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2481 if (!ptr) {
2482 if (stkctr == &tmpstkctr)
2483 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002484 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002485 }
2486
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002487 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002488
Willy Tarreau7d562212016-11-25 16:10:05 +01002489 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2490 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002491
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002492 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002493
2494 if (stkctr == &tmpstkctr)
2495 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002496 }
2497 return 1;
2498}
2499
2500/* set temp integer to the number of connections from the stream's source address
2501 * in the table pointed to by expr, after updating it.
2502 * Accepts exactly 1 argument of type table.
2503 */
2504static int
2505smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2506{
2507 struct connection *conn = objt_conn(smp->sess->origin);
2508 struct stksess *ts;
2509 struct stktable_key *key;
2510 void *ptr;
2511 struct proxy *px;
2512
2513 if (!conn)
2514 return 0;
2515
2516 /* Fetch source adress in a sample. */
2517 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2518 return 0;
2519
2520 /* Converts into key. */
2521 key = smp_to_stkey(smp, &args->data.prx->table);
2522 if (!key)
2523 return 0;
2524
2525 px = args->data.prx;
2526
Emeric Brun819fc6f2017-06-13 19:37:32 +02002527 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002528 /* entry does not exist and could not be created */
2529 return 0;
2530
2531 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002532 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002533 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002534 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002535
2536 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002537
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002538 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002539
Willy Tarreau7d562212016-11-25 16:10:05 +01002540 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002541
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002542 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002543
Willy Tarreau7d562212016-11-25 16:10:05 +01002544 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002545
2546 stktable_touch_local(&px->table, ts, 1);
2547
2548 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002549 return 1;
2550}
2551
2552/* set <smp> to the number of concurrent connections from the stream's tracked
2553 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2554 * "src_conn_cur" only.
2555 */
2556static int
2557smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2558{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002559 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002560 struct stkctr *stkctr;
2561
Emeric Brun819fc6f2017-06-13 19:37:32 +02002562 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002563 if (!stkctr)
2564 return 0;
2565
2566 smp->flags = SMP_F_VOL_TEST;
2567 smp->data.type = SMP_T_SINT;
2568 smp->data.u.sint = 0;
2569 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002570 void *ptr;
2571
2572 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2573 if (!ptr) {
2574 if (stkctr == &tmpstkctr)
2575 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002576 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002577 }
2578
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002579 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002580
Willy Tarreau7d562212016-11-25 16:10:05 +01002581 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002582
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002583 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002584
2585 if (stkctr == &tmpstkctr)
2586 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002587 }
2588 return 1;
2589}
2590
2591/* set <smp> to the cumulated number of streams from the stream's tracked
2592 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2593 * "src_sess_cnt" only.
2594 */
2595static int
2596smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2597{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002598 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002599 struct stkctr *stkctr;
2600
Emeric Brun819fc6f2017-06-13 19:37:32 +02002601 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002602 if (!stkctr)
2603 return 0;
2604
2605 smp->flags = SMP_F_VOL_TEST;
2606 smp->data.type = SMP_T_SINT;
2607 smp->data.u.sint = 0;
2608 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002609 void *ptr;
2610
2611 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2612 if (!ptr) {
2613 if (stkctr == &tmpstkctr)
2614 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002615 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002616 }
2617
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002618 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002619
Willy Tarreau7d562212016-11-25 16:10:05 +01002620 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002621
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002622 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002623
2624 if (stkctr == &tmpstkctr)
2625 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002626 }
2627 return 1;
2628}
2629
2630/* set <smp> to the stream rate from the stream's tracked frontend counters.
2631 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2632 */
2633static int
2634smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2635{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002636 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002637 struct stkctr *stkctr;
2638
Emeric Brun819fc6f2017-06-13 19:37:32 +02002639 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002640 if (!stkctr)
2641 return 0;
2642
2643 smp->flags = SMP_F_VOL_TEST;
2644 smp->data.type = SMP_T_SINT;
2645 smp->data.u.sint = 0;
2646 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002647 void *ptr;
2648
2649 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2650 if (!ptr) {
2651 if (stkctr == &tmpstkctr)
2652 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002653 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002654 }
2655
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002656 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002657
Willy Tarreau7d562212016-11-25 16:10:05 +01002658 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2659 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002660
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002661 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662
2663 if (stkctr == &tmpstkctr)
2664 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002665 }
2666 return 1;
2667}
2668
2669/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2670 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2671 * "src_http_req_cnt" only.
2672 */
2673static int
2674smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2675{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002676 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002677 struct stkctr *stkctr;
2678
Emeric Brun819fc6f2017-06-13 19:37:32 +02002679 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002680 if (!stkctr)
2681 return 0;
2682
2683 smp->flags = SMP_F_VOL_TEST;
2684 smp->data.type = SMP_T_SINT;
2685 smp->data.u.sint = 0;
2686 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002687 void *ptr;
2688
2689 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2690 if (!ptr) {
2691 if (stkctr == &tmpstkctr)
2692 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002693 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002694 }
2695
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002696 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002697
Willy Tarreau7d562212016-11-25 16:10:05 +01002698 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002699
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002700 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002701
2702 if (stkctr == &tmpstkctr)
2703 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002704 }
2705 return 1;
2706}
2707
2708/* set <smp> to the HTTP request rate from the stream's tracked frontend
2709 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2710 * "src_http_req_rate" only.
2711 */
2712static int
2713smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2714{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002715 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002716 struct stkctr *stkctr;
2717
Emeric Brun819fc6f2017-06-13 19:37:32 +02002718 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002719 if (!stkctr)
2720 return 0;
2721
2722 smp->flags = SMP_F_VOL_TEST;
2723 smp->data.type = SMP_T_SINT;
2724 smp->data.u.sint = 0;
2725 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002726 void *ptr;
2727
2728 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2729 if (!ptr) {
2730 if (stkctr == &tmpstkctr)
2731 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002732 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002733 }
2734
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002735 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002736
Willy Tarreau7d562212016-11-25 16:10:05 +01002737 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2738 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002739
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002740 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002741
2742 if (stkctr == &tmpstkctr)
2743 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002744 }
2745 return 1;
2746}
2747
2748/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2749 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2750 * "src_http_err_cnt" only.
2751 */
2752static int
2753smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2754{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002755 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002756 struct stkctr *stkctr;
2757
Emeric Brun819fc6f2017-06-13 19:37:32 +02002758 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002759 if (!stkctr)
2760 return 0;
2761
2762 smp->flags = SMP_F_VOL_TEST;
2763 smp->data.type = SMP_T_SINT;
2764 smp->data.u.sint = 0;
2765 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002766 void *ptr;
2767
2768 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2769 if (!ptr) {
2770 if (stkctr == &tmpstkctr)
2771 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002772 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002773 }
2774
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002775 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002776
Willy Tarreau7d562212016-11-25 16:10:05 +01002777 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002778
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002779 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780
2781 if (stkctr == &tmpstkctr)
2782 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002783 }
2784 return 1;
2785}
2786
2787/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2788 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2789 * "src_http_err_rate" only.
2790 */
2791static int
2792smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2793{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002794 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002795 struct stkctr *stkctr;
2796
Emeric Brun819fc6f2017-06-13 19:37:32 +02002797 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002798 if (!stkctr)
2799 return 0;
2800
2801 smp->flags = SMP_F_VOL_TEST;
2802 smp->data.type = SMP_T_SINT;
2803 smp->data.u.sint = 0;
2804 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002805 void *ptr;
2806
2807 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2808 if (!ptr) {
2809 if (stkctr == &tmpstkctr)
2810 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002811 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002812 }
2813
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002814 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002815
Willy Tarreau7d562212016-11-25 16:10:05 +01002816 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2817 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002818
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002819 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002820
2821 if (stkctr == &tmpstkctr)
2822 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002823 }
2824 return 1;
2825}
2826
2827/* set <smp> to the number of kbytes received from clients, as found in the
2828 * stream's tracked frontend counters. Supports being called as
2829 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2830 */
2831static int
2832smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2833{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002834 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002835 struct stkctr *stkctr;
2836
Emeric Brun819fc6f2017-06-13 19:37:32 +02002837 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002838 if (!stkctr)
2839 return 0;
2840
2841 smp->flags = SMP_F_VOL_TEST;
2842 smp->data.type = SMP_T_SINT;
2843 smp->data.u.sint = 0;
2844 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002845 void *ptr;
2846
2847 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2848 if (!ptr) {
2849 if (stkctr == &tmpstkctr)
2850 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002851 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002852 }
2853
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002854 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002855
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002857
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002858 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002859
2860 if (stkctr == &tmpstkctr)
2861 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002862 }
2863 return 1;
2864}
2865
2866/* set <smp> to the data rate received from clients in bytes/s, as found
2867 * in the stream's tracked frontend counters. Supports being called as
2868 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2869 */
2870static int
2871smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2872{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002873 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002874 struct stkctr *stkctr;
2875
Emeric Brun819fc6f2017-06-13 19:37:32 +02002876 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002877 if (!stkctr)
2878 return 0;
2879
2880 smp->flags = SMP_F_VOL_TEST;
2881 smp->data.type = SMP_T_SINT;
2882 smp->data.u.sint = 0;
2883 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002884 void *ptr;
2885
2886 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2887 if (!ptr) {
2888 if (stkctr == &tmpstkctr)
2889 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002890 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002891 }
2892
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002893 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002894
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2896 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002897
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002898 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002899
2900 if (stkctr == &tmpstkctr)
2901 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002902 }
2903 return 1;
2904}
2905
2906/* set <smp> to the number of kbytes sent to clients, as found in the
2907 * stream's tracked frontend counters. Supports being called as
2908 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2909 */
2910static int
2911smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2912{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002913 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002914 struct stkctr *stkctr;
2915
Emeric Brun819fc6f2017-06-13 19:37:32 +02002916 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002917 if (!stkctr)
2918 return 0;
2919
2920 smp->flags = SMP_F_VOL_TEST;
2921 smp->data.type = SMP_T_SINT;
2922 smp->data.u.sint = 0;
2923 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002924 void *ptr;
2925
2926 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2927 if (!ptr) {
2928 if (stkctr == &tmpstkctr)
2929 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002930 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931 }
2932
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002933 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002934
Willy Tarreau7d562212016-11-25 16:10:05 +01002935 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002936
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002937 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002938
2939 if (stkctr == &tmpstkctr)
2940 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002941 }
2942 return 1;
2943}
2944
2945/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2946 * stream's tracked frontend counters. Supports being called as
2947 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2948 */
2949static int
2950smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2951{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002952 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002953 struct stkctr *stkctr;
2954
Emeric Brun819fc6f2017-06-13 19:37:32 +02002955 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002956 if (!stkctr)
2957 return 0;
2958
2959 smp->flags = SMP_F_VOL_TEST;
2960 smp->data.type = SMP_T_SINT;
2961 smp->data.u.sint = 0;
2962 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002963 void *ptr;
2964
2965 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2966 if (!ptr) {
2967 if (stkctr == &tmpstkctr)
2968 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002969 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002970 }
2971
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002972 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002973
Willy Tarreau7d562212016-11-25 16:10:05 +01002974 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2975 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002976
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002977 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978
2979 if (stkctr == &tmpstkctr)
2980 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002981 }
2982 return 1;
2983}
2984
2985/* set <smp> to the number of active trackers on the SC entry in the stream's
2986 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2987 */
2988static int
2989smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2990{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002991 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002992 struct stkctr *stkctr;
2993
Emeric Brun819fc6f2017-06-13 19:37:32 +02002994 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002995 if (!stkctr)
2996 return 0;
2997
2998 smp->flags = SMP_F_VOL_TEST;
2999 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003000 if (stkctr == &tmpstkctr) {
3001 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3002 stktable_release(stkctr->table, stkctr_entry(stkctr));
3003 }
3004 else {
3005 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3006 }
3007
Willy Tarreau7d562212016-11-25 16:10:05 +01003008 return 1;
3009}
3010
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003011
3012/* The functions below are used to manipulate table contents from the CLI.
3013 * There are 3 main actions, "clear", "set" and "show". The code is shared
3014 * between all actions, and the action is encoded in the void *private in
3015 * the appctx as well as in the keyword registration, among one of the
3016 * following values.
3017 */
3018
3019enum {
3020 STK_CLI_ACT_CLR,
3021 STK_CLI_ACT_SET,
3022 STK_CLI_ACT_SHOW,
3023};
3024
3025/* Dump the status of a table to a stream interface's
3026 * read buffer. It returns 0 if the output buffer is full
3027 * and needs to be called again, otherwise non-zero.
3028 */
3029static int table_dump_head_to_buffer(struct chunk *msg, struct stream_interface *si,
3030 struct proxy *proxy, struct proxy *target)
3031{
3032 struct stream *s = si_strm(si);
3033
3034 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3035 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3036
3037 /* any other information should be dumped here */
3038
William Lallemand07a62f72017-05-24 00:57:40 +02003039 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003040 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3041
Willy Tarreau06d80a92017-10-19 14:32:15 +02003042 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003043 si_applet_cant_put(si);
3044 return 0;
3045 }
3046
3047 return 1;
3048}
3049
3050/* Dump a table entry to a stream interface's
3051 * read buffer. It returns 0 if the output buffer is full
3052 * and needs to be called again, otherwise non-zero.
3053 */
3054static int table_dump_entry_to_buffer(struct chunk *msg, struct stream_interface *si,
3055 struct proxy *proxy, struct stksess *entry)
3056{
3057 int dt;
3058
3059 chunk_appendf(msg, "%p:", entry);
3060
3061 if (proxy->table.type == SMP_T_IPV4) {
3062 char addr[INET_ADDRSTRLEN];
3063 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3064 chunk_appendf(msg, " key=%s", addr);
3065 }
3066 else if (proxy->table.type == SMP_T_IPV6) {
3067 char addr[INET6_ADDRSTRLEN];
3068 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3069 chunk_appendf(msg, " key=%s", addr);
3070 }
3071 else if (proxy->table.type == SMP_T_SINT) {
3072 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3073 }
3074 else if (proxy->table.type == SMP_T_STR) {
3075 chunk_appendf(msg, " key=");
3076 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3077 }
3078 else {
3079 chunk_appendf(msg, " key=");
3080 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3081 }
3082
3083 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3084
3085 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3086 void *ptr;
3087
3088 if (proxy->table.data_ofs[dt] == 0)
3089 continue;
3090 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3091 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3092 else
3093 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3094
3095 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3096 switch (stktable_data_types[dt].std_type) {
3097 case STD_T_SINT:
3098 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3099 break;
3100 case STD_T_UINT:
3101 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3102 break;
3103 case STD_T_ULL:
3104 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3105 break;
3106 case STD_T_FRQP:
3107 chunk_appendf(msg, "%d",
3108 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3109 proxy->table.data_arg[dt].u));
3110 break;
3111 }
3112 }
3113 chunk_appendf(msg, "\n");
3114
Willy Tarreau06d80a92017-10-19 14:32:15 +02003115 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003116 si_applet_cant_put(si);
3117 return 0;
3118 }
3119
3120 return 1;
3121}
3122
3123
3124/* Processes a single table entry matching a specific key passed in argument.
3125 * returns 0 if wants to be called again, 1 if has ended processing.
3126 */
3127static int table_process_entry_per_key(struct appctx *appctx, char **args)
3128{
3129 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003130 struct proxy *px = appctx->ctx.table.target;
3131 struct stksess *ts;
3132 uint32_t uint32_key;
3133 unsigned char ip6_key[sizeof(struct in6_addr)];
3134 long long value;
3135 int data_type;
3136 int cur_arg;
3137 void *ptr;
3138 struct freq_ctr_period *frqp;
3139
3140 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003141 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003142 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003143 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003144 return 1;
3145 }
3146
3147 switch (px->table.type) {
3148 case SMP_T_IPV4:
3149 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003150 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003151 break;
3152 case SMP_T_IPV6:
3153 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003154 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003155 break;
3156 case SMP_T_SINT:
3157 {
3158 char *endptr;
3159 unsigned long val;
3160 errno = 0;
3161 val = strtoul(args[4], &endptr, 10);
3162 if ((errno == ERANGE && val == ULONG_MAX) ||
3163 (errno != 0 && val == 0) || endptr == args[4] ||
3164 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003165 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003166 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003167 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003168 return 1;
3169 }
3170 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003171 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003172 break;
3173 }
3174 break;
3175 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003176 static_table_key.key = args[4];
3177 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003178 break;
3179 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003180 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003181 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003182 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003183 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3184 break;
3185 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003186 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003187 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3188 break;
3189 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003190 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003191 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3192 break;
3193 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003194 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003195 appctx->ctx.cli.msg = "Unknown action\n";
3196 break;
3197 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003198 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003199 return 1;
3200 }
3201
3202 /* check permissions */
3203 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3204 return 1;
3205
Willy Tarreaua24bc782016-12-14 15:50:35 +01003206 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003207 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003208 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003209 if (!ts)
3210 return 1;
3211 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003212 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3213 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003214 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003215 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003216 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003218 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003220 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003221 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003222 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003223 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003224 break;
3225
3226 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003228 if (!ts)
3229 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230
3231 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003232 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003233 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003234 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003235 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003236 return 1;
3237 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003238
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003239 break;
3240
3241 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003242 ts = stktable_get_entry(&px->table, &static_table_key);
3243 if (!ts) {
3244 /* don't delete an entry which is currently referenced */
3245 appctx->ctx.cli.severity = LOG_ERR;
3246 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3247 appctx->st0 = CLI_ST_PRINT;
3248 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003249 }
3250
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003251 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003252 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3253 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003254 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003255 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003256 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003257 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003258 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003259 return 1;
3260 }
3261
3262 data_type = stktable_get_data_type(args[cur_arg] + 5);
3263 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003264 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003265 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003266 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003267 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003268 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003269 return 1;
3270 }
3271
3272 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003273 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003274 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003275 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003276 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003277 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003278 return 1;
3279 }
3280
3281 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003282 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003283 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003284 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003285 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003286 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003287 return 1;
3288 }
3289
3290 ptr = stktable_data_ptr(&px->table, ts, data_type);
3291
3292 switch (stktable_data_types[data_type].std_type) {
3293 case STD_T_SINT:
3294 stktable_data_cast(ptr, std_t_sint) = value;
3295 break;
3296 case STD_T_UINT:
3297 stktable_data_cast(ptr, std_t_uint) = value;
3298 break;
3299 case STD_T_ULL:
3300 stktable_data_cast(ptr, std_t_ull) = value;
3301 break;
3302 case STD_T_FRQP:
3303 /* We set both the current and previous values. That way
3304 * the reported frequency is stable during all the period
3305 * then slowly fades out. This allows external tools to
3306 * push measures without having to update them too often.
3307 */
3308 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003309 /* First bit is reserved for the freq_ctr_period lock
3310 Note: here we're still protected by the stksess lock
3311 so we don't need to update the update the freq_ctr_period
3312 using its internal lock */
3313 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003314 frqp->prev_ctr = 0;
3315 frqp->curr_ctr = value;
3316 break;
3317 }
3318 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003319 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003320 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003321 break;
3322
3323 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003324 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003325 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003326 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003327 break;
3328 }
3329 return 1;
3330}
3331
3332/* Prepares the appctx fields with the data-based filters from the command line.
3333 * Returns 0 if the dump can proceed, 1 if has ended processing.
3334 */
3335static int table_prepare_data_request(struct appctx *appctx, char **args)
3336{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003337 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003338 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003339 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003340 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003341 return 1;
3342 }
3343
3344 /* condition on stored data value */
3345 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3346 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003347 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003348 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003349 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003350 return 1;
3351 }
3352
3353 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003354 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003355 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003356 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003357 return 1;
3358 }
3359
3360 appctx->ctx.table.data_op = get_std_op(args[4]);
3361 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003362 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003363 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003364 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003365 return 1;
3366 }
3367
3368 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003369 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003370 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003371 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003372 return 1;
3373 }
3374
3375 /* OK we're done, all the fields are set */
3376 return 0;
3377}
3378
3379/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003380static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003381{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003382 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003383 appctx->ctx.table.target = NULL;
3384 appctx->ctx.table.proxy = NULL;
3385 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003386 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003387
3388 if (*args[2]) {
3389 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3390 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003391 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003392 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003393 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003394 return 1;
3395 }
3396 }
3397 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003398 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003399 goto err_args;
3400 return 0;
3401 }
3402
3403 if (strcmp(args[3], "key") == 0)
3404 return table_process_entry_per_key(appctx, args);
3405 else if (strncmp(args[3], "data.", 5) == 0)
3406 return table_prepare_data_request(appctx, args);
3407 else if (*args[3])
3408 goto err_args;
3409
3410 return 0;
3411
3412err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003413 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003414 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003415 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003416 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3417 break;
3418 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003419 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003420 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3421 break;
3422 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003423 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003424 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3425 break;
3426 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003427 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003428 appctx->ctx.cli.msg = "Unknown action\n";
3429 break;
3430 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003431 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003432 return 1;
3433}
3434
3435/* This function is used to deal with table operations (dump or clear depending
3436 * on the action stored in appctx->private). It returns 0 if the output buffer is
3437 * full and it needs to be called again, otherwise non-zero.
3438 */
3439static int cli_io_handler_table(struct appctx *appctx)
3440{
3441 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003442 struct stream *s = si_strm(si);
3443 struct ebmb_node *eb;
3444 int dt;
3445 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003446 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003447
3448 /*
3449 * We have 3 possible states in appctx->st2 :
3450 * - STAT_ST_INIT : the first call
3451 * - STAT_ST_INFO : the proxy pointer points to the next table to
3452 * dump, the entry pointer is NULL ;
3453 * - STAT_ST_LIST : the proxy pointer points to the current table
3454 * and the entry pointer points to the next entry to be dumped,
3455 * and the refcount on the next entry is held ;
3456 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3457 * data though.
3458 */
3459
3460 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3461 /* in case of abort, remove any refcount we might have set on an entry */
3462 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003463 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003464 }
3465 return 1;
3466 }
3467
3468 chunk_reset(&trash);
3469
3470 while (appctx->st2 != STAT_ST_FIN) {
3471 switch (appctx->st2) {
3472 case STAT_ST_INIT:
3473 appctx->ctx.table.proxy = appctx->ctx.table.target;
3474 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003475 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003476
3477 appctx->ctx.table.entry = NULL;
3478 appctx->st2 = STAT_ST_INFO;
3479 break;
3480
3481 case STAT_ST_INFO:
3482 if (!appctx->ctx.table.proxy ||
3483 (appctx->ctx.table.target &&
3484 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3485 appctx->st2 = STAT_ST_END;
3486 break;
3487 }
3488
3489 if (appctx->ctx.table.proxy->table.size) {
3490 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3491 return 0;
3492
3493 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003494 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003495 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003496 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003497 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3498 if (eb) {
3499 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3500 appctx->ctx.table.entry->ref_cnt++;
3501 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003502 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003503 break;
3504 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003505 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003506 }
3507 }
3508 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3509 break;
3510
3511 case STAT_ST_LIST:
3512 skip_entry = 0;
3513
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003514 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003515
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003516 if (appctx->ctx.table.data_type >= 0) {
3517 /* we're filtering on some data contents */
3518 void *ptr;
3519 long long data;
3520
Emeric Brun819fc6f2017-06-13 19:37:32 +02003521
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003522 dt = appctx->ctx.table.data_type;
3523 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3524 appctx->ctx.table.entry,
3525 dt);
3526
3527 data = 0;
3528 switch (stktable_data_types[dt].std_type) {
3529 case STD_T_SINT:
3530 data = stktable_data_cast(ptr, std_t_sint);
3531 break;
3532 case STD_T_UINT:
3533 data = stktable_data_cast(ptr, std_t_uint);
3534 break;
3535 case STD_T_ULL:
3536 data = stktable_data_cast(ptr, std_t_ull);
3537 break;
3538 case STD_T_FRQP:
3539 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3540 appctx->ctx.table.proxy->table.data_arg[dt].u);
3541 break;
3542 }
3543
3544 /* skip the entry if the data does not match the test and the value */
3545 if ((data < appctx->ctx.table.value &&
3546 (appctx->ctx.table.data_op == STD_OP_EQ ||
3547 appctx->ctx.table.data_op == STD_OP_GT ||
3548 appctx->ctx.table.data_op == STD_OP_GE)) ||
3549 (data == appctx->ctx.table.value &&
3550 (appctx->ctx.table.data_op == STD_OP_NE ||
3551 appctx->ctx.table.data_op == STD_OP_GT ||
3552 appctx->ctx.table.data_op == STD_OP_LT)) ||
3553 (data > appctx->ctx.table.value &&
3554 (appctx->ctx.table.data_op == STD_OP_EQ ||
3555 appctx->ctx.table.data_op == STD_OP_LT ||
3556 appctx->ctx.table.data_op == STD_OP_LE)))
3557 skip_entry = 1;
3558 }
3559
3560 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003561 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003562 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003563 return 0;
3564 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003565
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003566 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003567
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003568 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003569 appctx->ctx.table.entry->ref_cnt--;
3570
3571 eb = ebmb_next(&appctx->ctx.table.entry->key);
3572 if (eb) {
3573 struct stksess *old = appctx->ctx.table.entry;
3574 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3575 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003576 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003577 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003578 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003579 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003580 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003581 break;
3582 }
3583
3584
3585 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003586 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003587 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003588 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3589
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003590 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003591
3592 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3593 appctx->st2 = STAT_ST_INFO;
3594 break;
3595
3596 case STAT_ST_END:
3597 appctx->st2 = STAT_ST_FIN;
3598 break;
3599 }
3600 }
3601 return 1;
3602}
3603
3604static void cli_release_show_table(struct appctx *appctx)
3605{
3606 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003607 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003608 }
3609}
3610
3611/* register cli keywords */
3612static struct cli_kw_list cli_kws = {{ },{
3613 { { "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 },
3614 { { "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 },
3615 { { "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 },
3616 {{},}
3617}};
3618
3619
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003620static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003621 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003622 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003623 { "sc-set-gpt0", parse_set_gpt0, 1 },
3624 { /* END */ }
3625}};
3626
Willy Tarreau620408f2016-10-21 16:37:51 +02003627static struct action_kw_list tcp_sess_kws = { { }, {
3628 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003629 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003630 { "sc-set-gpt0", parse_set_gpt0, 1 },
3631 { /* END */ }
3632}};
3633
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003634static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003635 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003636 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003637 { "sc-set-gpt0", parse_set_gpt0, 1 },
3638 { /* END */ }
3639}};
3640
3641static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003642 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003643 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003644 { "sc-set-gpt0", parse_set_gpt0, 1 },
3645 { /* END */ }
3646}};
3647
3648static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003649 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003650 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003651 { "sc-set-gpt0", parse_set_gpt0, 1 },
3652 { /* END */ }
3653}};
3654
3655static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003656 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003657 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003658 { "sc-set-gpt0", parse_set_gpt0, 1 },
3659 { /* END */ }
3660}};
3661
Willy Tarreau7d562212016-11-25 16:10:05 +01003662///* Note: must not be declared <const> as its list will be overwritten.
3663// * Please take care of keeping this list alphabetically sorted.
3664// */
3665//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3666// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3667// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3668// { /* END */ },
3669//}};
3670/* Note: must not be declared <const> as its list will be overwritten.
3671 * Please take care of keeping this list alphabetically sorted.
3672 */
3673static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3674 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3675 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3676 { "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 +01003677 { "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 +01003678 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3679 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3680 { "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 +01003681 { "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 +01003682 { "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 +01003683 { "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 +01003684 { "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 +01003685 { "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 +01003686 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3687 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3688 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3689 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3690 { "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 +01003691 { "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 +01003692 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3693 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3694 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3695 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3696 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3697 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3698 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3699 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3700 { "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 +01003701 { "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 +01003702 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3703 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3704 { "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 +01003705 { "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 +01003706 { "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 +01003707 { "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 +01003708 { "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 +01003709 { "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 +01003710 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3711 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3712 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3713 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3714 { "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 +01003715 { "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 +01003716 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3717 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3718 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3719 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3720 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3721 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3722 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3723 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3724 { "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 +01003725 { "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 +01003726 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3727 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3728 { "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 +01003729 { "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 +01003730 { "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 +01003731 { "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 +01003732 { "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 +01003733 { "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 +01003734 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3735 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3736 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3737 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3738 { "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 +01003739 { "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 +01003740 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3741 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3742 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3743 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3744 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3745 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3746 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3747 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3748 { "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 +01003749 { "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 +01003750 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3751 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3752 { "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 +01003753 { "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 +01003754 { "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 +01003755 { "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 +01003756 { "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 +01003757 { "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 +01003758 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3759 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3760 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3761 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3762 { "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 +01003763 { "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 +01003764 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3765 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3766 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3767 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3768 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3769 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3770 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3771 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3772 { "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 +01003773 { "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 +01003774 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3775 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3776 { "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 +01003777 { "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 +01003778 { "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 +01003779 { "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 +01003780 { "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 +01003781 { "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 +01003782 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3783 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3784 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3785 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3786 { "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 +01003787 { "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 +01003788 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3789 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3790 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3791 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3792 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3793 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3794 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3795 { /* END */ },
3796}};
3797
3798
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003799/* Note: must not be declared <const> as its list will be overwritten */
3800static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003801 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3802 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3803 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3804 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3805 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3806 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3807 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3808 { "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 +01003809 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003810 { "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 +01003811 { "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 +02003812 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3813 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3814 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3815 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3816 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3817 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3818 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3819 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3820 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3821 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003822 { /* END */ },
3823}};
3824
3825__attribute__((constructor))
3826static void __stick_table_init(void)
3827{
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003828 /* register som action keywords. */
3829 tcp_req_conn_keywords_register(&tcp_conn_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +02003830 tcp_req_sess_keywords_register(&tcp_sess_kws);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003831 tcp_req_cont_keywords_register(&tcp_req_kws);
3832 tcp_res_cont_keywords_register(&tcp_res_kws);
3833 http_req_keywords_register(&http_req_kws);
3834 http_res_keywords_register(&http_res_kws);
3835
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003836 /* register sample fetch and format conversion keywords */
Willy Tarreau7d562212016-11-25 16:10:05 +01003837 sample_register_fetches(&smp_fetch_keywords);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003838 sample_register_convs(&sample_conv_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003839 cli_register_kw(&cli_kws);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003840}