blob: e8d4f3a6038b4a21cda2b7c8d27ae3e5f0ad44e3 [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}
Willy Tarreau43e90352018-06-27 06:25:57 +0200415/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
416static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200417{
Willy Tarreau43e90352018-06-27 06:25:57 +0200418 if (!ts)
419 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100420 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200421 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100422 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200423}
424
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200425/* Insert new sticky session <ts> in the table. It is assumed that it does not
426 * yet exist (the caller must check this). The table's timeout is updated if it
427 * is set. <ts> is returned.
428 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200429void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200430{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100431
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200432 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200433 ts->exp.key = ts->expire;
434 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200435 if (t->expire) {
436 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
437 task_queue(t->exp_task);
438 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200439}
440
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200441/* Returns a valid or initialized stksess for the specified stktable_key in the
442 * specified table, or NULL if the key was NULL, or if no entry was found nor
443 * could be created. The entry's expiration is updated.
444 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200445struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200446{
447 struct stksess *ts;
448
449 if (!key)
450 return NULL;
451
Emeric Brun819fc6f2017-06-13 19:37:32 +0200452 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200453 if (ts == NULL) {
454 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200455 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200456 if (!ts)
457 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200458 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200459 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200460 return ts;
461}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200462/* Returns a valid or initialized stksess for the specified stktable_key in the
463 * specified table, or NULL if the key was NULL, or if no entry was found nor
464 * could be created. The entry's expiration is updated.
465 * This function locks the table, and the refcount of the entry is increased.
466 */
467struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
468{
469 struct stksess *ts;
470
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100471 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200472 ts = __stktable_get_entry(table, key);
473 if (ts)
474 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100475 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200476
477 return ts;
478}
479
480/* Lookup for an entry with the same key and store the submitted
481 * stksess if not found.
482 */
483struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
484{
485 struct stksess *ts;
486
487 ts = __stktable_lookup(table, nts);
488 if (ts == NULL) {
489 ts = nts;
490 __stktable_store(table, ts);
491 }
492 return ts;
493}
494
495/* Lookup for an entry with the same key and store the submitted
496 * stksess if not found.
497 * This function locks the table, and the refcount of the entry is increased.
498 */
499struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
500{
501 struct stksess *ts;
502
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100503 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200504 ts = __stktable_set_entry(table, nts);
505 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100506 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200507
Emeric Brun819fc6f2017-06-13 19:37:32 +0200508 return ts;
509}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100510/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200511 * Trash expired sticky sessions from table <t>. The next expiration date is
512 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100513 */
514static int stktable_trash_expired(struct stktable *t)
515{
516 struct stksess *ts;
517 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200518 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100519
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100520 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100521 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
522
523 while (1) {
524 if (unlikely(!eb)) {
525 /* we might have reached the end of the tree, typically because
526 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200527 * half. Let's loop back to the beginning of the tree now if we
528 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100529 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200530 if (looped)
531 break;
532 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100533 eb = eb32_first(&t->exps);
534 if (likely(!eb))
535 break;
536 }
537
538 if (likely(tick_is_lt(now_ms, eb->key))) {
539 /* timer not expired yet, revisit it later */
540 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100541 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100542 }
543
544 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200545 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100546 eb = eb32_next(eb);
547
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200548 /* don't delete an entry which is currently referenced */
549 if (ts->ref_cnt)
550 continue;
551
Willy Tarreau86257dc2010-06-06 12:57:10 +0200552 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100553
554 if (!tick_is_expired(ts->expire, now_ms)) {
555 if (!tick_isset(ts->expire))
556 continue;
557
Willy Tarreau86257dc2010-06-06 12:57:10 +0200558 ts->exp.key = ts->expire;
559 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100560
Willy Tarreau86257dc2010-06-06 12:57:10 +0200561 if (!eb || eb->key > ts->exp.key)
562 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100563 continue;
564 }
565
566 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200567 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200568 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200569 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100570 }
571
572 /* We have found no task to expire in any tree */
573 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100574out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100575 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100576 return t->exp_next;
577}
578
579/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200580 * Task processing function to trash expired sticky sessions. A pointer to the
581 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100582 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200583static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100584{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200585 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100586
587 task->expire = stktable_trash_expired(t);
588 return task;
589}
590
Willy Tarreauaea940e2010-06-06 11:56:36 +0200591/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100592int stktable_init(struct stktable *t)
593{
594 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200595 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100596 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100597 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100598 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
Willy Tarreau393379c2010-06-06 12:11:37 +0200600 t->pool = create_pool("sticktables", sizeof(struct stksess) + t->data_size + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100601
602 t->exp_next = TICK_ETERNITY;
603 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200604 t->exp_task = task_new(MAX_THREADS_MASK);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100605 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100606 t->exp_task->context = (void *)t;
607 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200608 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200609 peers_register_table(t->peers.p, t);
610 }
611
Emeric Brun3bd697e2010-01-04 15:23:48 +0100612 return t->pool != NULL;
613 }
614 return 1;
615}
616
617/*
618 * Configuration keywords of known table types
619 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200620struct stktable_type stktable_types[SMP_TYPES] = {
621 [SMP_T_SINT] = { "integer", 0, 4 },
622 [SMP_T_IPV4] = { "ip", 0, 4 },
623 [SMP_T_IPV6] = { "ipv6", 0, 16 },
624 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
625 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
626};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100627
628/*
629 * Parse table type configuration.
630 * Returns 0 on successful parsing, else 1.
631 * <myidx> is set at next configuration <args> index.
632 */
633int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
634{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200635 for (*type = 0; *type < SMP_TYPES; (*type)++) {
636 if (!stktable_types[*type].kw)
637 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100638 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
639 continue;
640
641 *key_size = stktable_types[*type].default_size;
642 (*myidx)++;
643
Willy Tarreauaea940e2010-06-06 11:56:36 +0200644 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100645 if (strcmp("len", args[*myidx]) == 0) {
646 (*myidx)++;
647 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200648 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100649 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200650 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200651 /* null terminated string needs +1 for '\0'. */
652 (*key_size)++;
653 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100654 (*myidx)++;
655 }
656 }
657 return 0;
658 }
659 return 1;
660}
661
Willy Tarreau8fed9032014-07-03 17:02:46 +0200662/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200663 * Note that the sample *is* modified and that the returned key may point
664 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200665 * Returns NULL if the sample could not be converted (eg: no matching type),
666 * otherwise a pointer to the static stktable_key filled with what is needed
667 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200668 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200669struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200670{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200671 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200672 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200673 return NULL;
674
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200675 /* Fill static_table_key. */
676 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200677
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200678 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200679 static_table_key.key = &smp->data.u.ipv4;
680 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200681 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200682
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200683 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200684 static_table_key.key = &smp->data.u.ipv6;
685 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200686 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200687
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200688 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200689 /* The stick table require a 32bit unsigned int, "sint" is a
690 * signed 64 it, so we can convert it inplace.
691 */
692 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200693 static_table_key.key = &smp->data.u.sint;
694 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200695 break;
696
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200697 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200698 if (!smp_make_safe(smp))
699 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200700 static_table_key.key = smp->data.u.str.area;
701 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200702 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200703
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200704 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200705 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200706 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200707 if (!smp_make_rw(smp))
708 return NULL;
709
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200710 if (smp->data.u.str.size < t->key_size)
711 if (!smp_dup(smp))
712 return NULL;
713 if (smp->data.u.str.size < t->key_size)
714 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200715 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
716 t->key_size - smp->data.u.str.data);
717 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200718 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200719 static_table_key.key = smp->data.u.str.area;
720 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200721 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200722
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200723 default: /* impossible case. */
724 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200725 }
726
Christopher Fauletca20d022017-08-29 15:30:31 +0200727 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200728}
729
730/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200731 * Process a fetch + format conversion as defined by the sample expression <expr>
732 * on request or response considering the <opt> parameter. Returns either NULL if
733 * no key could be extracted, or a pointer to the converted result stored in
734 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
735 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200736 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
737 * without SMP_OPT_FINAL). The output will be usable like this :
738 *
739 * return MAY_CHANGE FINAL Meaning for the sample
740 * NULL 0 * Not present and will never be (eg: header)
741 * NULL 1 0 Not present or unstable, could change (eg: req_len)
742 * NULL 1 1 Not present, will not change anymore
743 * smp 0 * Present and will not change (eg: header)
744 * smp 1 0 not possible
745 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200746 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200747struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200748 unsigned int opt, struct sample_expr *expr, struct sample *smp)
749{
750 if (smp)
751 memset(smp, 0, sizeof(*smp));
752
Willy Tarreau192252e2015-04-04 01:47:55 +0200753 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200754 if (!smp)
755 return NULL;
756
757 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
758 return NULL; /* we can only use stable samples */
759
760 return smp_to_stkey(smp, t);
761}
762
763/*
Willy Tarreau12785782012-04-27 21:37:17 +0200764 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200765 * type <table_type>, otherwise zero. Used in configuration check.
766 */
Willy Tarreau12785782012-04-27 21:37:17 +0200767int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200768{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100769 int out_type;
770
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200771 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200772 return 0;
773
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100774 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200775
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200776 /* Convert sample. */
777 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100778 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200779
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200780 return 1;
781}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100782
Willy Tarreauedee1d62014-07-15 16:44:27 +0200783/* Extra data types processing : after the last one, some room may remain
784 * before STKTABLE_DATA_TYPES that may be used to register extra data types
785 * at run time.
786 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200787struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200788 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200789 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200790 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200791 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200792 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
793 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
794 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
795 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
796 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
797 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
798 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
799 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
800 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
801 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
802 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
803 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
804 [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 +0100805 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
806 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +0200807};
808
Willy Tarreauedee1d62014-07-15 16:44:27 +0200809/* Registers stick-table extra data type with index <idx>, name <name>, type
810 * <std_type> and arg type <arg_type>. If the index is negative, the next free
811 * index is automatically allocated. The allocated index is returned, or -1 if
812 * no free index was found or <name> was already registered. The <name> is used
813 * directly as a pointer, so if it's not stable, the caller must allocate it.
814 */
815int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
816{
817 if (idx < 0) {
818 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
819 if (!stktable_data_types[idx].name)
820 break;
821
822 if (strcmp(stktable_data_types[idx].name, name) == 0)
823 return -1;
824 }
825 }
826
827 if (idx >= STKTABLE_DATA_TYPES)
828 return -1;
829
830 if (stktable_data_types[idx].name != NULL)
831 return -1;
832
833 stktable_data_types[idx].name = name;
834 stktable_data_types[idx].std_type = std_type;
835 stktable_data_types[idx].arg_type = arg_type;
836 return idx;
837}
838
Willy Tarreau08d5f982010-06-06 13:34:54 +0200839/*
840 * Returns the data type number for the stktable_data_type whose name is <name>,
841 * or <0 if not found.
842 */
843int stktable_get_data_type(char *name)
844{
845 int type;
846
847 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +0200848 if (!stktable_data_types[type].name)
849 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +0200850 if (strcmp(name, stktable_data_types[type].name) == 0)
851 return type;
852 }
853 return -1;
854}
855
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200856/* Casts sample <smp> to the type of the table specified in arg(0), and looks
857 * it up into this table. Returns true if found, false otherwise. The input
858 * type is STR so that input samples are converted to string (since all types
859 * can be converted to strings), then the function casts the string again into
860 * the table's type. This is a double conversion, but in the future we might
861 * support automatic input types to perform the cast on the fly.
862 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200863static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200864{
865 struct stktable *t;
866 struct stktable_key *key;
867 struct stksess *ts;
868
869 t = &arg_p[0].data.prx->table;
870
871 key = smp_to_stkey(smp, t);
872 if (!key)
873 return 0;
874
875 ts = stktable_lookup_key(t, key);
876
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200877 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200878 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200879 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +0200880 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200881 return 1;
882}
883
884/* Casts sample <smp> to the type of the table specified in arg(0), and looks
885 * it up into this table. Returns the data rate received from clients in bytes/s
886 * if the key is present in the table, otherwise zero, so that comparisons can
887 * be easily performed. If the inspected parameter is not stored in the table,
888 * <not found> is returned.
889 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200890static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200891{
892 struct stktable *t;
893 struct stktable_key *key;
894 struct stksess *ts;
895 void *ptr;
896
897 t = &arg_p[0].data.prx->table;
898
899 key = smp_to_stkey(smp, t);
900 if (!key)
901 return 0;
902
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200903 ts = stktable_lookup_key(t, key);
904
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200905 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200906 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200907 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200908
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200909 if (!ts) /* key not present */
910 return 1;
911
912 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400913 if (ptr)
914 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
915 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200916
Daniel Corbett3e60b112018-05-27 09:47:12 -0400917 stktable_release(t, ts);
918 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200919}
920
921/* Casts sample <smp> to the type of the table specified in arg(0), and looks
922 * it up into this table. Returns the cumulated number of connections for the key
923 * if the key is present in the table, otherwise zero, so that comparisons can
924 * be easily performed. If the inspected parameter is not stored in the table,
925 * <not found> is returned.
926 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200927static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200928{
929 struct stktable *t;
930 struct stktable_key *key;
931 struct stksess *ts;
932 void *ptr;
933
934 t = &arg_p[0].data.prx->table;
935
936 key = smp_to_stkey(smp, t);
937 if (!key)
938 return 0;
939
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200940 ts = stktable_lookup_key(t, key);
941
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200942 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200943 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200944 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200945
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200946 if (!ts) /* key not present */
947 return 1;
948
949 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400950 if (ptr)
951 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200952
Daniel Corbett3e60b112018-05-27 09:47:12 -0400953 stktable_release(t, ts);
954 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200955}
956
957/* Casts sample <smp> to the type of the table specified in arg(0), and looks
958 * it up into this table. Returns the number of concurrent connections for the
959 * key if the key is present in the table, otherwise zero, so that comparisons
960 * can be easily performed. If the inspected parameter is not stored in the
961 * table, <not found> is returned.
962 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200963static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200964{
965 struct stktable *t;
966 struct stktable_key *key;
967 struct stksess *ts;
968 void *ptr;
969
970 t = &arg_p[0].data.prx->table;
971
972 key = smp_to_stkey(smp, t);
973 if (!key)
974 return 0;
975
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200976 ts = stktable_lookup_key(t, key);
977
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200978 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200979 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200980 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200981
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200982 if (!ts) /* key not present */
983 return 1;
984
985 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400986 if (ptr)
987 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200988
Daniel Corbett3e60b112018-05-27 09:47:12 -0400989 stktable_release(t, ts);
990 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200991}
992
993/* Casts sample <smp> to the type of the table specified in arg(0), and looks
994 * it up into this table. Returns the rate of incoming connections from the key
995 * if the key is present in the table, otherwise zero, so that comparisons can
996 * be easily performed. If the inspected parameter is not stored in the table,
997 * <not found> is returned.
998 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200999static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001000{
1001 struct stktable *t;
1002 struct stktable_key *key;
1003 struct stksess *ts;
1004 void *ptr;
1005
1006 t = &arg_p[0].data.prx->table;
1007
1008 key = smp_to_stkey(smp, t);
1009 if (!key)
1010 return 0;
1011
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001012 ts = stktable_lookup_key(t, key);
1013
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001014 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001015 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001016 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001017
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001018 if (!ts) /* key not present */
1019 return 1;
1020
1021 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001022 if (ptr)
1023 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1024 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001025
Daniel Corbett3e60b112018-05-27 09:47:12 -04001026 stktable_release(t, ts);
1027 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001028}
1029
1030/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1031 * it up into this table. Returns the data rate sent to clients in bytes/s
1032 * if the key is present in the table, otherwise zero, so that comparisons can
1033 * be easily performed. If the inspected parameter is not stored in the table,
1034 * <not found> is returned.
1035 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001036static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001037{
1038 struct stktable *t;
1039 struct stktable_key *key;
1040 struct stksess *ts;
1041 void *ptr;
1042
1043 t = &arg_p[0].data.prx->table;
1044
1045 key = smp_to_stkey(smp, t);
1046 if (!key)
1047 return 0;
1048
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001049 ts = stktable_lookup_key(t, key);
1050
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001051 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001052 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001053 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001054
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001055 if (!ts) /* key not present */
1056 return 1;
1057
1058 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001059 if (ptr)
1060 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1061 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001062
Daniel Corbett3e60b112018-05-27 09:47:12 -04001063 stktable_release(t, ts);
1064 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001065}
1066
1067/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001068 * it up into this table. Returns the value of the GPT0 tag for the key
1069 * if the key is present in the table, otherwise false, so that comparisons can
1070 * be easily performed. If the inspected parameter is not stored in the table,
1071 * <not found> is returned.
1072 */
1073static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1074{
1075 struct stktable *t;
1076 struct stktable_key *key;
1077 struct stksess *ts;
1078 void *ptr;
1079
1080 t = &arg_p[0].data.prx->table;
1081
1082 key = smp_to_stkey(smp, t);
1083 if (!key)
1084 return 0;
1085
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001086 ts = stktable_lookup_key(t, key);
1087
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001088 smp->flags = SMP_F_VOL_TEST;
1089 smp->data.type = SMP_T_SINT;
1090 smp->data.u.sint = 0;
1091
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001092 if (!ts) /* key not present */
1093 return 1;
1094
1095 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001096 if (ptr)
1097 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001098
Daniel Corbett3e60b112018-05-27 09:47:12 -04001099 stktable_release(t, ts);
1100 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001101}
1102
1103/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001104 * it up into this table. Returns the value of the GPC0 counter for the key
1105 * if the key is present in the table, otherwise zero, so that comparisons can
1106 * be easily performed. If the inspected parameter is not stored in the table,
1107 * <not found> is returned.
1108 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001109static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001110{
1111 struct stktable *t;
1112 struct stktable_key *key;
1113 struct stksess *ts;
1114 void *ptr;
1115
1116 t = &arg_p[0].data.prx->table;
1117
1118 key = smp_to_stkey(smp, t);
1119 if (!key)
1120 return 0;
1121
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001122 ts = stktable_lookup_key(t, key);
1123
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001124 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001125 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001126 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001127
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001128 if (!ts) /* key not present */
1129 return 1;
1130
1131 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001132 if (ptr)
1133 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001134
Daniel Corbett3e60b112018-05-27 09:47:12 -04001135 stktable_release(t, ts);
1136 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001137}
1138
1139/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1140 * it up into this table. Returns the event rate of the GPC0 counter for the key
1141 * if the key is present in the table, otherwise zero, so that comparisons can
1142 * be easily performed. If the inspected parameter is not stored in the table,
1143 * <not found> is returned.
1144 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001145static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001146{
1147 struct stktable *t;
1148 struct stktable_key *key;
1149 struct stksess *ts;
1150 void *ptr;
1151
1152 t = &arg_p[0].data.prx->table;
1153
1154 key = smp_to_stkey(smp, t);
1155 if (!key)
1156 return 0;
1157
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001158 ts = stktable_lookup_key(t, key);
1159
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001160 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001161 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001162 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001163
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001164 if (!ts) /* key not present */
1165 return 1;
1166
1167 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001168 if (ptr)
1169 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1170 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001171
Daniel Corbett3e60b112018-05-27 09:47:12 -04001172 stktable_release(t, ts);
1173 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001174}
1175
1176/* 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 +01001177 * it up into this table. Returns the value of the GPC1 counter for the key
1178 * if the key is present in the table, otherwise zero, so that comparisons can
1179 * be easily performed. If the inspected parameter is not stored in the table,
1180 * <not found> is returned.
1181 */
1182static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1183{
1184 struct stktable *t;
1185 struct stktable_key *key;
1186 struct stksess *ts;
1187 void *ptr;
1188
1189 t = &arg_p[0].data.prx->table;
1190
1191 key = smp_to_stkey(smp, t);
1192 if (!key)
1193 return 0;
1194
1195 ts = stktable_lookup_key(t, key);
1196
1197 smp->flags = SMP_F_VOL_TEST;
1198 smp->data.type = SMP_T_SINT;
1199 smp->data.u.sint = 0;
1200
1201 if (!ts) /* key not present */
1202 return 1;
1203
1204 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001205 if (ptr)
1206 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001207
Daniel Corbett3e60b112018-05-27 09:47:12 -04001208 stktable_release(t, ts);
1209 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001210}
1211
1212/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1213 * it up into this table. Returns the event rate of the GPC1 counter for the key
1214 * if the key is present in the table, otherwise zero, so that comparisons can
1215 * be easily performed. If the inspected parameter is not stored in the table,
1216 * <not found> is returned.
1217 */
1218static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1219{
1220 struct stktable *t;
1221 struct stktable_key *key;
1222 struct stksess *ts;
1223 void *ptr;
1224
1225 t = &arg_p[0].data.prx->table;
1226
1227 key = smp_to_stkey(smp, t);
1228 if (!key)
1229 return 0;
1230
1231 ts = stktable_lookup_key(t, key);
1232
1233 smp->flags = SMP_F_VOL_TEST;
1234 smp->data.type = SMP_T_SINT;
1235 smp->data.u.sint = 0;
1236
1237 if (!ts) /* key not present */
1238 return 1;
1239
1240 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001241 if (ptr)
1242 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1243 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001244
Daniel Corbett3e60b112018-05-27 09:47:12 -04001245 stktable_release(t, ts);
1246 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001247}
1248
1249/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001250 * it up into this table. Returns the cumulated number of HTTP request errors
1251 * for the key if the key is present in the table, otherwise zero, so that
1252 * comparisons can be easily performed. If the inspected parameter is not stored
1253 * in the table, <not found> is returned.
1254 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001255static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001256{
1257 struct stktable *t;
1258 struct stktable_key *key;
1259 struct stksess *ts;
1260 void *ptr;
1261
1262 t = &arg_p[0].data.prx->table;
1263
1264 key = smp_to_stkey(smp, t);
1265 if (!key)
1266 return 0;
1267
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001268 ts = stktable_lookup_key(t, key);
1269
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001270 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001271 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001272 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001273
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001274 if (!ts) /* key not present */
1275 return 1;
1276
1277 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001278 if (ptr)
1279 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001280
Daniel Corbett3e60b112018-05-27 09:47:12 -04001281 stktable_release(t, ts);
1282 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001283}
1284
1285/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1286 * it up into this table. Returns the HTTP request error rate the key
1287 * if the key is present in the table, otherwise zero, so that comparisons can
1288 * be easily performed. If the inspected parameter is not stored in the table,
1289 * <not found> is returned.
1290 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001291static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001292{
1293 struct stktable *t;
1294 struct stktable_key *key;
1295 struct stksess *ts;
1296 void *ptr;
1297
1298 t = &arg_p[0].data.prx->table;
1299
1300 key = smp_to_stkey(smp, t);
1301 if (!key)
1302 return 0;
1303
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001304 ts = stktable_lookup_key(t, key);
1305
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001306 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001307 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001308 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001309
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310 if (!ts) /* key not present */
1311 return 1;
1312
1313 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001314 if (ptr)
1315 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1316 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001317
Daniel Corbett3e60b112018-05-27 09:47:12 -04001318 stktable_release(t, ts);
1319 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001320}
1321
1322/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1323 * it up into this table. Returns the cumulated number of HTTP request for the
1324 * key if the key is present in the table, otherwise zero, so that comparisons
1325 * can be easily performed. If the inspected parameter is not stored in the
1326 * table, <not found> is returned.
1327 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001328static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001329{
1330 struct stktable *t;
1331 struct stktable_key *key;
1332 struct stksess *ts;
1333 void *ptr;
1334
1335 t = &arg_p[0].data.prx->table;
1336
1337 key = smp_to_stkey(smp, t);
1338 if (!key)
1339 return 0;
1340
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001341 ts = stktable_lookup_key(t, key);
1342
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001343 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001344 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001345 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347 if (!ts) /* key not present */
1348 return 1;
1349
1350 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001351 if (ptr)
1352 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001353
Daniel Corbett3e60b112018-05-27 09:47:12 -04001354 stktable_release(t, ts);
1355 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356}
1357
1358/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1359 * it up into this table. Returns the HTTP request rate the key if the key is
1360 * present in the table, otherwise zero, so that comparisons can be easily
1361 * performed. If the inspected parameter is not stored in the table, <not found>
1362 * is returned.
1363 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001364static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001365{
1366 struct stktable *t;
1367 struct stktable_key *key;
1368 struct stksess *ts;
1369 void *ptr;
1370
1371 t = &arg_p[0].data.prx->table;
1372
1373 key = smp_to_stkey(smp, t);
1374 if (!key)
1375 return 0;
1376
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001377 ts = stktable_lookup_key(t, key);
1378
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001379 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001380 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001381 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001383 if (!ts) /* key not present */
1384 return 1;
1385
1386 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001387 if (ptr)
1388 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1389 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001390
Daniel Corbett3e60b112018-05-27 09:47:12 -04001391 stktable_release(t, ts);
1392 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393}
1394
1395/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1396 * it up into this table. Returns the volume of datareceived from clients in kbytes
1397 * if the key is present in the table, otherwise zero, so that comparisons can
1398 * be easily performed. If the inspected parameter is not stored in the table,
1399 * <not found> is returned.
1400 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001401static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001402{
1403 struct stktable *t;
1404 struct stktable_key *key;
1405 struct stksess *ts;
1406 void *ptr;
1407
1408 t = &arg_p[0].data.prx->table;
1409
1410 key = smp_to_stkey(smp, t);
1411 if (!key)
1412 return 0;
1413
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001414 ts = stktable_lookup_key(t, key);
1415
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001416 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001417 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001418 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001419
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420 if (!ts) /* key not present */
1421 return 1;
1422
1423 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001424 if (ptr)
1425 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001426
Daniel Corbett3e60b112018-05-27 09:47:12 -04001427 stktable_release(t, ts);
1428 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001429}
1430
1431/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1432 * it up into this table. Returns the volume of data sent to clients in kbytes
1433 * if the key is present in the table, otherwise zero, so that comparisons can
1434 * be easily performed. If the inspected parameter is not stored in the table,
1435 * <not found> is returned.
1436 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001437static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001438{
1439 struct stktable *t;
1440 struct stktable_key *key;
1441 struct stksess *ts;
1442 void *ptr;
1443
1444 t = &arg_p[0].data.prx->table;
1445
1446 key = smp_to_stkey(smp, t);
1447 if (!key)
1448 return 0;
1449
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001450 ts = stktable_lookup_key(t, key);
1451
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001452 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001453 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001454 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001455
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001456 if (!ts) /* key not present */
1457 return 1;
1458
1459 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001460 if (ptr)
1461 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001462
Daniel Corbett3e60b112018-05-27 09:47:12 -04001463 stktable_release(t, ts);
1464 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001465}
1466
1467/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1468 * it up into this table. Returns the server ID associated with the key if the
1469 * key is present in the table, otherwise zero, so that comparisons can be
1470 * easily performed. If the inspected parameter is not stored in the table,
1471 * <not found> is returned.
1472 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001473static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001474{
1475 struct stktable *t;
1476 struct stktable_key *key;
1477 struct stksess *ts;
1478 void *ptr;
1479
1480 t = &arg_p[0].data.prx->table;
1481
1482 key = smp_to_stkey(smp, t);
1483 if (!key)
1484 return 0;
1485
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001486 ts = stktable_lookup_key(t, key);
1487
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001488 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001489 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001490 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001491
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001492 if (!ts) /* key not present */
1493 return 1;
1494
1495 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001496 if (ptr)
1497 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001498
Daniel Corbett3e60b112018-05-27 09:47:12 -04001499 stktable_release(t, ts);
1500 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001501}
1502
1503/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1504 * it up into this table. Returns the cumulated number of sessions for the
1505 * key if the key is present in the table, otherwise zero, so that comparisons
1506 * can be easily performed. If the inspected parameter is not stored in the
1507 * table, <not found> is returned.
1508 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001509static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001510{
1511 struct stktable *t;
1512 struct stktable_key *key;
1513 struct stksess *ts;
1514 void *ptr;
1515
1516 t = &arg_p[0].data.prx->table;
1517
1518 key = smp_to_stkey(smp, t);
1519 if (!key)
1520 return 0;
1521
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001522 ts = stktable_lookup_key(t, key);
1523
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001524 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001525 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001526 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001527
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001528 if (!ts) /* key not present */
1529 return 1;
1530
1531 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001532 if (ptr)
1533 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001534
Daniel Corbett3e60b112018-05-27 09:47:12 -04001535 stktable_release(t, ts);
1536 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001537}
1538
1539/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1540 * it up into this table. Returns the session rate the key if the key is
1541 * present in the table, otherwise zero, so that comparisons can be easily
1542 * performed. If the inspected parameter is not stored in the table, <not found>
1543 * is returned.
1544 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001545static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001546{
1547 struct stktable *t;
1548 struct stktable_key *key;
1549 struct stksess *ts;
1550 void *ptr;
1551
1552 t = &arg_p[0].data.prx->table;
1553
1554 key = smp_to_stkey(smp, t);
1555 if (!key)
1556 return 0;
1557
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001558 ts = stktable_lookup_key(t, key);
1559
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001560 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001561 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001562 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001563
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001564 if (!ts) /* key not present */
1565 return 1;
1566
1567 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001568 if (ptr)
1569 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1570 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001571
Daniel Corbett3e60b112018-05-27 09:47:12 -04001572 stktable_release(t, ts);
1573 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001574}
1575
1576/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1577 * it up into this table. Returns the amount of concurrent connections tracking
1578 * the same key if the key is present in the table, otherwise zero, so that
1579 * comparisons can be easily performed. If the inspected parameter is not
1580 * stored in the table, <not found> is returned.
1581 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001582static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001583{
1584 struct stktable *t;
1585 struct stktable_key *key;
1586 struct stksess *ts;
1587
1588 t = &arg_p[0].data.prx->table;
1589
1590 key = smp_to_stkey(smp, t);
1591 if (!key)
1592 return 0;
1593
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001594 ts = stktable_lookup_key(t, key);
1595
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001596 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001597 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001598 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599
Tim Duesterhus65189c12018-06-26 15:57:29 +02001600 if (!ts)
1601 return 1;
1602
1603 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001604
Daniel Corbett3e60b112018-05-27 09:47:12 -04001605 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001606 return 1;
1607}
1608
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001609/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001610static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001611 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001612{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001613 struct stksess *ts;
1614 struct stkctr *stkctr;
1615
1616 /* Extract the stksess, return OK if no stksess available. */
1617 if (s)
1618 stkctr = &s->stkctr[rule->arg.gpc.sc];
1619 else
1620 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001621
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001622 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001623 if (ts) {
1624 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001625
Willy Tarreau79c1e912016-01-25 14:54:45 +01001626 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1627 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001628 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1629 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001630 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001631
1632 if (ptr1)
1633 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001634 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001635
Emeric Brun819fc6f2017-06-13 19:37:32 +02001636 if (ptr2)
1637 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001638
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001639 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001640
1641 /* If data was modified, we need to touch to re-schedule sync */
1642 stktable_touch_local(stkctr->table, ts, 0);
1643 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001644 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001645 return ACT_RET_CONT;
1646}
1647
1648/* This function is a common parser for using variables. It understands
1649 * the formats:
1650 *
1651 * sc-inc-gpc0(<stick-table ID>)
1652 *
1653 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1654 * it returns 1 and the variable <expr> is filled with the pointer to the
1655 * expression to execute.
1656 */
1657static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1658 struct act_rule *rule, char **err)
1659{
1660 const char *cmd_name = args[*arg-1];
1661 char *error;
1662
1663 cmd_name += strlen("sc-inc-gpc0");
1664 if (*cmd_name == '\0') {
1665 /* default stick table id. */
1666 rule->arg.gpc.sc = 0;
1667 } else {
1668 /* parse the stick table id. */
1669 if (*cmd_name != '(') {
1670 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1671 return ACT_RET_PRS_ERR;
1672 }
1673 cmd_name++; /* jump the '(' */
1674 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1675 if (*error != ')') {
1676 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1677 return ACT_RET_PRS_ERR;
1678 }
1679
1680 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1681 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1682 ACT_ACTION_TRK_SCMAX-1);
1683 return ACT_RET_PRS_ERR;
1684 }
1685 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001686 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001687 rule->action_ptr = action_inc_gpc0;
1688 return ACT_RET_PRS_OK;
1689}
1690
1691/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001692static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1693 struct session *sess, struct stream *s, int flags)
1694{
1695 struct stksess *ts;
1696 struct stkctr *stkctr;
1697
1698 /* Extract the stksess, return OK if no stksess available. */
1699 if (s)
1700 stkctr = &s->stkctr[rule->arg.gpc.sc];
1701 else
1702 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1703
1704 ts = stkctr_entry(stkctr);
1705 if (ts) {
1706 void *ptr1, *ptr2;
1707
1708 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1709 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1710 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1711 if (ptr1 || ptr2) {
1712 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1713
1714 if (ptr1)
1715 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1716 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1717
1718 if (ptr2)
1719 stktable_data_cast(ptr2, gpc1)++;
1720
1721 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1722
1723 /* If data was modified, we need to touch to re-schedule sync */
1724 stktable_touch_local(stkctr->table, ts, 0);
1725 }
1726 }
1727 return ACT_RET_CONT;
1728}
1729
1730/* This function is a common parser for using variables. It understands
1731 * the formats:
1732 *
1733 * sc-inc-gpc1(<stick-table ID>)
1734 *
1735 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1736 * it returns 1 and the variable <expr> is filled with the pointer to the
1737 * expression to execute.
1738 */
1739static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1740 struct act_rule *rule, char **err)
1741{
1742 const char *cmd_name = args[*arg-1];
1743 char *error;
1744
1745 cmd_name += strlen("sc-inc-gpc1");
1746 if (*cmd_name == '\0') {
1747 /* default stick table id. */
1748 rule->arg.gpc.sc = 0;
1749 } else {
1750 /* parse the stick table id. */
1751 if (*cmd_name != '(') {
1752 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1753 return ACT_RET_PRS_ERR;
1754 }
1755 cmd_name++; /* jump the '(' */
1756 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1757 if (*error != ')') {
1758 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1759 return ACT_RET_PRS_ERR;
1760 }
1761
1762 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1763 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1764 ACT_ACTION_TRK_SCMAX-1);
1765 return ACT_RET_PRS_ERR;
1766 }
1767 }
1768 rule->action = ACT_CUSTOM;
1769 rule->action_ptr = action_inc_gpc1;
1770 return ACT_RET_PRS_OK;
1771}
1772
1773/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001774static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001775 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001776{
1777 void *ptr;
1778 struct stksess *ts;
1779 struct stkctr *stkctr;
1780
1781 /* Extract the stksess, return OK if no stksess available. */
1782 if (s)
1783 stkctr = &s->stkctr[rule->arg.gpt.sc];
1784 else
1785 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001786
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001787 ts = stkctr_entry(stkctr);
1788 if (!ts)
1789 return ACT_RET_CONT;
1790
1791 /* Store the sample in the required sc, and ignore errors. */
1792 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001793 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001794 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001795
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001796 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001797
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001798 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001799
1800 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001801 }
1802
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001803 return ACT_RET_CONT;
1804}
1805
1806/* This function is a common parser for using variables. It understands
1807 * the format:
1808 *
1809 * set-gpt0(<stick-table ID>) <expression>
1810 *
1811 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1812 * it returns 1 and the variable <expr> is filled with the pointer to the
1813 * expression to execute.
1814 */
1815static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1816 struct act_rule *rule, char **err)
1817
1818
1819{
1820 const char *cmd_name = args[*arg-1];
1821 char *error;
1822
1823 cmd_name += strlen("sc-set-gpt0");
1824 if (*cmd_name == '\0') {
1825 /* default stick table id. */
1826 rule->arg.gpt.sc = 0;
1827 } else {
1828 /* parse the stick table id. */
1829 if (*cmd_name != '(') {
1830 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1831 return ACT_RET_PRS_ERR;
1832 }
1833 cmd_name++; /* jump the '(' */
1834 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1835 if (*error != ')') {
1836 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1837 return ACT_RET_PRS_ERR;
1838 }
1839
1840 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1841 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1842 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1843 return ACT_RET_PRS_ERR;
1844 }
1845 }
1846
1847 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1848 if (*error != '\0') {
1849 memprintf(err, "invalid integer value '%s'", args[*arg]);
1850 return ACT_RET_PRS_ERR;
1851 }
1852 (*arg)++;
1853
Thierry FOURNIER42148732015-09-02 17:17:33 +02001854 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001855 rule->action_ptr = action_set_gpt0;
1856
1857 return ACT_RET_PRS_OK;
1858}
1859
Willy Tarreau7d562212016-11-25 16:10:05 +01001860/* set temp integer to the number of used entries in the table pointed to by expr.
1861 * Accepts exactly 1 argument of type table.
1862 */
1863static int
1864smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1865{
1866 smp->flags = SMP_F_VOL_TEST;
1867 smp->data.type = SMP_T_SINT;
1868 smp->data.u.sint = args->data.prx->table.current;
1869 return 1;
1870}
1871
1872/* set temp integer to the number of free entries in the table pointed to by expr.
1873 * Accepts exactly 1 argument of type table.
1874 */
1875static int
1876smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1877{
1878 struct proxy *px;
1879
1880 px = args->data.prx;
1881 smp->flags = SMP_F_VOL_TEST;
1882 smp->data.type = SMP_T_SINT;
1883 smp->data.u.sint = px->table.size - px->table.current;
1884 return 1;
1885}
1886
1887/* Returns a pointer to a stkctr depending on the fetch keyword name.
1888 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1889 * sc[0-9]_* will return a pointer to the respective field in the
1890 * stream <l4>. sc_* requires an UINT argument specifying the stick
1891 * counter number. src_* will fill a locally allocated structure with
1892 * the table and entry corresponding to what is specified with src_*.
1893 * NULL may be returned if the designated stkctr is not tracked. For
1894 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1895 * passed. When present, the currently tracked key is then looked up
1896 * in the specified table instead of the current table. The purpose is
1897 * to be able to convery multiple values per key (eg: have gpc0 from
1898 * multiple tables). <strm> is allowed to be NULL, in which case only
1899 * the session will be consulted.
1900 */
1901struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001902smp_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 +01001903{
Willy Tarreau7d562212016-11-25 16:10:05 +01001904 struct stkctr *stkptr;
1905 struct stksess *stksess;
1906 unsigned int num = kw[2] - '0';
1907 int arg = 0;
1908
1909 if (num == '_' - '0') {
1910 /* sc_* variant, args[0] = ctr# (mandatory) */
1911 num = args[arg++].data.sint;
1912 if (num >= MAX_SESS_STKCTR)
1913 return NULL;
1914 }
1915 else if (num > 9) { /* src_* variant, args[0] = table */
1916 struct stktable_key *key;
1917 struct connection *conn = objt_conn(sess->origin);
1918 struct sample smp;
1919
1920 if (!conn)
1921 return NULL;
1922
1923 /* Fetch source adress in a sample. */
1924 smp.px = NULL;
1925 smp.sess = sess;
1926 smp.strm = strm;
1927 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1928 return NULL;
1929
1930 /* Converts into key. */
1931 key = smp_to_stkey(&smp, &args->data.prx->table);
1932 if (!key)
1933 return NULL;
1934
Emeric Brun819fc6f2017-06-13 19:37:32 +02001935 stkctr->table = &args->data.prx->table;
1936 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1937 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001938 }
1939
1940 /* Here, <num> contains the counter number from 0 to 9 for
1941 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1942 * args[arg] is the first optional argument. We first lookup the
1943 * ctr form the stream, then from the session if it was not there.
1944 */
1945
1946 if (strm)
1947 stkptr = &strm->stkctr[num];
1948 if (!strm || !stkctr_entry(stkptr)) {
1949 stkptr = &sess->stkctr[num];
1950 if (!stkctr_entry(stkptr))
1951 return NULL;
1952 }
1953
1954 stksess = stkctr_entry(stkptr);
1955 if (!stksess)
1956 return NULL;
1957
1958 if (unlikely(args[arg].type == ARGT_TAB)) {
1959 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001960 stkctr->table = &args[arg].data.prx->table;
1961 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1962 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001963 }
1964 return stkptr;
1965}
1966
1967/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1968 * the entry if it doesn't exist yet. This is needed for a few fetch
1969 * functions which need to create an entry, such as src_inc_gpc* and
1970 * src_clr_gpc*.
1971 */
1972struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001973smp_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 +01001974{
Willy Tarreau7d562212016-11-25 16:10:05 +01001975 struct stktable_key *key;
1976 struct connection *conn = objt_conn(sess->origin);
1977 struct sample smp;
1978
1979 if (strncmp(kw, "src_", 4) != 0)
1980 return NULL;
1981
1982 if (!conn)
1983 return NULL;
1984
1985 /* Fetch source adress in a sample. */
1986 smp.px = NULL;
1987 smp.sess = sess;
1988 smp.strm = strm;
1989 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1990 return NULL;
1991
1992 /* Converts into key. */
1993 key = smp_to_stkey(&smp, &args->data.prx->table);
1994 if (!key)
1995 return NULL;
1996
Emeric Brun819fc6f2017-06-13 19:37:32 +02001997 stkctr->table = &args->data.prx->table;
1998 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
1999 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002000}
2001
2002/* set return a boolean indicating if the requested stream counter is
2003 * currently being tracked or not.
2004 * Supports being called as "sc[0-9]_tracked" only.
2005 */
2006static int
2007smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2008{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002009 struct stkctr tmpstkctr;
2010 struct stkctr *stkctr;
2011
Willy Tarreau7d562212016-11-25 16:10:05 +01002012 smp->flags = SMP_F_VOL_TEST;
2013 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002014 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2015 smp->data.u.sint = !!stkctr;
2016
2017 /* release the ref count */
Willy Tarreau43e90352018-06-27 06:25:57 +02002018 if ((stkctr == &tmpstkctr))
Emeric Brun819fc6f2017-06-13 19:37:32 +02002019 stktable_release(stkctr->table, stkctr_entry(stkctr));
2020
Willy Tarreau7d562212016-11-25 16:10:05 +01002021 return 1;
2022}
2023
2024/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2025 * frontend counters or from the src.
2026 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2027 * zero is returned if the key is new.
2028 */
2029static int
2030smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2031{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002032 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002033 struct stkctr *stkctr;
2034
Emeric Brun819fc6f2017-06-13 19:37:32 +02002035 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002036 if (!stkctr)
2037 return 0;
2038
2039 smp->flags = SMP_F_VOL_TEST;
2040 smp->data.type = SMP_T_SINT;
2041 smp->data.u.sint = 0;
2042
Emeric Brun819fc6f2017-06-13 19:37:32 +02002043 if (stkctr_entry(stkctr)) {
2044 void *ptr;
2045
2046 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2047 if (!ptr) {
2048 if (stkctr == &tmpstkctr)
2049 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002050 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002051 }
2052
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002053 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002054
Willy Tarreau7d562212016-11-25 16:10:05 +01002055 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002056
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002057 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002058
2059 if (stkctr == &tmpstkctr)
2060 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002061 }
2062 return 1;
2063}
2064
2065/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2066 * frontend counters or from the src.
2067 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2068 * zero is returned if the key is new.
2069 */
2070static int
2071smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2072{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002073 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002074 struct stkctr *stkctr;
2075
Emeric Brun819fc6f2017-06-13 19:37:32 +02002076 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002077 if (!stkctr)
2078 return 0;
2079
2080 smp->flags = SMP_F_VOL_TEST;
2081 smp->data.type = SMP_T_SINT;
2082 smp->data.u.sint = 0;
2083
2084 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002085 void *ptr;
2086
2087 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2088 if (!ptr) {
2089 if (stkctr == &tmpstkctr)
2090 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002091 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002092 }
2093
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002094 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002095
Willy Tarreau7d562212016-11-25 16:10:05 +01002096 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002097
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002098 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002099
2100 if (stkctr == &tmpstkctr)
2101 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002102 }
2103 return 1;
2104}
2105
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002106/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2107 * frontend counters or from the src.
2108 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2109 * zero is returned if the key is new.
2110 */
2111static int
2112smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2113{
2114 struct stkctr tmpstkctr;
2115 struct stkctr *stkctr;
2116
2117 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2118 if (!stkctr)
2119 return 0;
2120
2121 smp->flags = SMP_F_VOL_TEST;
2122 smp->data.type = SMP_T_SINT;
2123 smp->data.u.sint = 0;
2124
2125 if (stkctr_entry(stkctr) != NULL) {
2126 void *ptr;
2127
2128 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2129 if (!ptr) {
2130 if (stkctr == &tmpstkctr)
2131 stktable_release(stkctr->table, stkctr_entry(stkctr));
2132 return 0; /* parameter not stored */
2133 }
2134
2135 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2136
2137 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2138
2139 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2140
2141 if (stkctr == &tmpstkctr)
2142 stktable_release(stkctr->table, stkctr_entry(stkctr));
2143 }
2144 return 1;
2145}
2146
Willy Tarreau7d562212016-11-25 16:10:05 +01002147/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2148 * tracked frontend counters or from the src.
2149 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2150 * Value zero is returned if the key is new.
2151 */
2152static int
2153smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2154{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002155 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002156 struct stkctr *stkctr;
2157
Emeric Brun819fc6f2017-06-13 19:37:32 +02002158 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002159 if (!stkctr)
2160 return 0;
2161
2162 smp->flags = SMP_F_VOL_TEST;
2163 smp->data.type = SMP_T_SINT;
2164 smp->data.u.sint = 0;
2165 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002166 void *ptr;
2167
2168 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2169 if (!ptr) {
2170 if (stkctr == &tmpstkctr)
2171 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002172 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002173 }
2174
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002175 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002176
Willy Tarreau7d562212016-11-25 16:10:05 +01002177 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2178 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002179
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002180 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002181
2182 if (stkctr == &tmpstkctr)
2183 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002184 }
2185 return 1;
2186}
2187
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002188/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2189 * tracked frontend counters or from the src.
2190 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2191 * Value zero is returned if the key is new.
2192 */
2193static int
2194smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2195{
2196 struct stkctr tmpstkctr;
2197 struct stkctr *stkctr;
2198
2199 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2200 if (!stkctr)
2201 return 0;
2202
2203 smp->flags = SMP_F_VOL_TEST;
2204 smp->data.type = SMP_T_SINT;
2205 smp->data.u.sint = 0;
2206 if (stkctr_entry(stkctr) != NULL) {
2207 void *ptr;
2208
2209 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2210 if (!ptr) {
2211 if (stkctr == &tmpstkctr)
2212 stktable_release(stkctr->table, stkctr_entry(stkctr));
2213 return 0; /* parameter not stored */
2214 }
2215
2216 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2217
2218 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2219 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2220
2221 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2222
2223 if (stkctr == &tmpstkctr)
2224 stktable_release(stkctr->table, stkctr_entry(stkctr));
2225 }
2226 return 1;
2227}
2228
Willy Tarreau7d562212016-11-25 16:10:05 +01002229/* Increment the General Purpose Counter 0 value from the stream's tracked
2230 * frontend counters and return it into temp integer.
2231 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2232 */
2233static int
2234smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2235{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002236 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002237 struct stkctr *stkctr;
2238
Emeric Brun819fc6f2017-06-13 19:37:32 +02002239 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002240 if (!stkctr)
2241 return 0;
2242
2243 smp->flags = SMP_F_VOL_TEST;
2244 smp->data.type = SMP_T_SINT;
2245 smp->data.u.sint = 0;
2246
Emeric Brun819fc6f2017-06-13 19:37:32 +02002247 if (!stkctr_entry(stkctr))
2248 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002249
2250 if (stkctr && stkctr_entry(stkctr)) {
2251 void *ptr1,*ptr2;
2252
Emeric Brun819fc6f2017-06-13 19:37:32 +02002253
Willy Tarreau7d562212016-11-25 16:10:05 +01002254 /* First, update gpc0_rate if it's tracked. Second, update its
2255 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2256 */
2257 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002258 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002259 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002260 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002261
Emeric Brun819fc6f2017-06-13 19:37:32 +02002262 if (ptr1) {
2263 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2264 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2265 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2266 }
2267
2268 if (ptr2)
2269 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2270
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002271 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002272
2273 /* If data was modified, we need to touch to re-schedule sync */
2274 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2275 }
2276 else if (stkctr == &tmpstkctr)
2277 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002278 }
2279 return 1;
2280}
2281
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002282/* Increment the General Purpose Counter 1 value from the stream's tracked
2283 * frontend counters and return it into temp integer.
2284 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2285 */
2286static int
2287smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2288{
2289 struct stkctr tmpstkctr;
2290 struct stkctr *stkctr;
2291
2292 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2293 if (!stkctr)
2294 return 0;
2295
2296 smp->flags = SMP_F_VOL_TEST;
2297 smp->data.type = SMP_T_SINT;
2298 smp->data.u.sint = 0;
2299
2300 if (!stkctr_entry(stkctr))
2301 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2302
2303 if (stkctr && stkctr_entry(stkctr)) {
2304 void *ptr1,*ptr2;
2305
2306
2307 /* First, update gpc1_rate if it's tracked. Second, update its
2308 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2309 */
2310 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2311 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2312 if (ptr1 || ptr2) {
2313 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2314
2315 if (ptr1) {
2316 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2317 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2318 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2319 }
2320
2321 if (ptr2)
2322 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2323
2324 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2325
2326 /* If data was modified, we need to touch to re-schedule sync */
2327 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2328 }
2329 else if (stkctr == &tmpstkctr)
2330 stktable_release(stkctr->table, stkctr_entry(stkctr));
2331 }
2332 return 1;
2333}
2334
Willy Tarreau7d562212016-11-25 16:10:05 +01002335/* Clear the General Purpose Counter 0 value from the stream's tracked
2336 * frontend counters and return its previous value into temp integer.
2337 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2338 */
2339static int
2340smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2341{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002342 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002343 struct stkctr *stkctr;
2344
Emeric Brun819fc6f2017-06-13 19:37:32 +02002345 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002346 if (!stkctr)
2347 return 0;
2348
2349 smp->flags = SMP_F_VOL_TEST;
2350 smp->data.type = SMP_T_SINT;
2351 smp->data.u.sint = 0;
2352
Emeric Brun819fc6f2017-06-13 19:37:32 +02002353 if (!stkctr_entry(stkctr))
2354 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002355
Emeric Brun819fc6f2017-06-13 19:37:32 +02002356 if (stkctr && stkctr_entry(stkctr)) {
2357 void *ptr;
2358
2359 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2360 if (!ptr) {
2361 if (stkctr == &tmpstkctr)
2362 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002363 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002364 }
2365
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002366 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002367
Willy Tarreau7d562212016-11-25 16:10:05 +01002368 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2369 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002370
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002371 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002372
Willy Tarreau7d562212016-11-25 16:10:05 +01002373 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002374 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002375 }
2376 return 1;
2377}
2378
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002379/* Clear the General Purpose Counter 1 value from the stream's tracked
2380 * frontend counters and return its previous value into temp integer.
2381 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2382 */
2383static int
2384smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2385{
2386 struct stkctr tmpstkctr;
2387 struct stkctr *stkctr;
2388
2389 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2390 if (!stkctr)
2391 return 0;
2392
2393 smp->flags = SMP_F_VOL_TEST;
2394 smp->data.type = SMP_T_SINT;
2395 smp->data.u.sint = 0;
2396
2397 if (!stkctr_entry(stkctr))
2398 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2399
2400 if (stkctr && stkctr_entry(stkctr)) {
2401 void *ptr;
2402
2403 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2404 if (!ptr) {
2405 if (stkctr == &tmpstkctr)
2406 stktable_release(stkctr->table, stkctr_entry(stkctr));
2407 return 0; /* parameter not stored */
2408 }
2409
2410 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2411
2412 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2413 stktable_data_cast(ptr, gpc1) = 0;
2414
2415 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2416
2417 /* If data was modified, we need to touch to re-schedule sync */
2418 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2419 }
2420 return 1;
2421}
2422
Willy Tarreau7d562212016-11-25 16:10:05 +01002423/* set <smp> to the cumulated number of connections from the stream's tracked
2424 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2425 * "src_conn_cnt" only.
2426 */
2427static int
2428smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2429{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002430 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002431 struct stkctr *stkctr;
2432
Emeric Brun819fc6f2017-06-13 19:37:32 +02002433 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002434 if (!stkctr)
2435 return 0;
2436
2437 smp->flags = SMP_F_VOL_TEST;
2438 smp->data.type = SMP_T_SINT;
2439 smp->data.u.sint = 0;
2440 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002441 void *ptr;
2442
2443 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2444 if (!ptr) {
2445 if (stkctr == &tmpstkctr)
2446 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002447 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002448 }
2449
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002450 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002451
Willy Tarreau7d562212016-11-25 16:10:05 +01002452 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002453
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002454 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002455
2456 if (stkctr == &tmpstkctr)
2457 stktable_release(stkctr->table, stkctr_entry(stkctr));
2458
2459
Willy Tarreau7d562212016-11-25 16:10:05 +01002460 }
2461 return 1;
2462}
2463
2464/* set <smp> to the connection rate from the stream's tracked frontend
2465 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2466 * only.
2467 */
2468static int
2469smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2470{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002471 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002472 struct stkctr *stkctr;
2473
Emeric Brun819fc6f2017-06-13 19:37:32 +02002474 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002475 if (!stkctr)
2476 return 0;
2477
2478 smp->flags = SMP_F_VOL_TEST;
2479 smp->data.type = SMP_T_SINT;
2480 smp->data.u.sint = 0;
2481 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002482 void *ptr;
2483
2484 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2485 if (!ptr) {
2486 if (stkctr == &tmpstkctr)
2487 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002488 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002489 }
2490
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002491 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002492
Willy Tarreau7d562212016-11-25 16:10:05 +01002493 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2494 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002495
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002496 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002497
2498 if (stkctr == &tmpstkctr)
2499 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002500 }
2501 return 1;
2502}
2503
2504/* set temp integer to the number of connections from the stream's source address
2505 * in the table pointed to by expr, after updating it.
2506 * Accepts exactly 1 argument of type table.
2507 */
2508static int
2509smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2510{
2511 struct connection *conn = objt_conn(smp->sess->origin);
2512 struct stksess *ts;
2513 struct stktable_key *key;
2514 void *ptr;
2515 struct proxy *px;
2516
2517 if (!conn)
2518 return 0;
2519
2520 /* Fetch source adress in a sample. */
2521 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2522 return 0;
2523
2524 /* Converts into key. */
2525 key = smp_to_stkey(smp, &args->data.prx->table);
2526 if (!key)
2527 return 0;
2528
2529 px = args->data.prx;
2530
Emeric Brun819fc6f2017-06-13 19:37:32 +02002531 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002532 /* entry does not exist and could not be created */
2533 return 0;
2534
2535 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002536 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002537 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002538 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002539
2540 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002541
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002542 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002543
Willy Tarreau7d562212016-11-25 16:10:05 +01002544 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002545
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002546 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002547
Willy Tarreau7d562212016-11-25 16:10:05 +01002548 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002549
2550 stktable_touch_local(&px->table, ts, 1);
2551
2552 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002553 return 1;
2554}
2555
2556/* set <smp> to the number of concurrent connections from the stream's tracked
2557 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2558 * "src_conn_cur" only.
2559 */
2560static int
2561smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2562{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002563 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002564 struct stkctr *stkctr;
2565
Emeric Brun819fc6f2017-06-13 19:37:32 +02002566 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002567 if (!stkctr)
2568 return 0;
2569
2570 smp->flags = SMP_F_VOL_TEST;
2571 smp->data.type = SMP_T_SINT;
2572 smp->data.u.sint = 0;
2573 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002574 void *ptr;
2575
2576 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2577 if (!ptr) {
2578 if (stkctr == &tmpstkctr)
2579 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002580 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002581 }
2582
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002583 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002584
Willy Tarreau7d562212016-11-25 16:10:05 +01002585 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002586
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002587 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002588
2589 if (stkctr == &tmpstkctr)
2590 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002591 }
2592 return 1;
2593}
2594
2595/* set <smp> to the cumulated number of streams from the stream's tracked
2596 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2597 * "src_sess_cnt" only.
2598 */
2599static int
2600smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2601{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002602 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002603 struct stkctr *stkctr;
2604
Emeric Brun819fc6f2017-06-13 19:37:32 +02002605 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002606 if (!stkctr)
2607 return 0;
2608
2609 smp->flags = SMP_F_VOL_TEST;
2610 smp->data.type = SMP_T_SINT;
2611 smp->data.u.sint = 0;
2612 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002613 void *ptr;
2614
2615 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2616 if (!ptr) {
2617 if (stkctr == &tmpstkctr)
2618 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002619 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002620 }
2621
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002622 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002623
Willy Tarreau7d562212016-11-25 16:10:05 +01002624 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002625
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002626 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002627
2628 if (stkctr == &tmpstkctr)
2629 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002630 }
2631 return 1;
2632}
2633
2634/* set <smp> to the stream rate from the stream's tracked frontend counters.
2635 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2636 */
2637static int
2638smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2639{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002640 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002641 struct stkctr *stkctr;
2642
Emeric Brun819fc6f2017-06-13 19:37:32 +02002643 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002644 if (!stkctr)
2645 return 0;
2646
2647 smp->flags = SMP_F_VOL_TEST;
2648 smp->data.type = SMP_T_SINT;
2649 smp->data.u.sint = 0;
2650 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002651 void *ptr;
2652
2653 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2654 if (!ptr) {
2655 if (stkctr == &tmpstkctr)
2656 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002657 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002658 }
2659
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002660 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002661
Willy Tarreau7d562212016-11-25 16:10:05 +01002662 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2663 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002664
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002665 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002666
2667 if (stkctr == &tmpstkctr)
2668 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002669 }
2670 return 1;
2671}
2672
2673/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2674 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2675 * "src_http_req_cnt" only.
2676 */
2677static int
2678smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2679{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002680 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002681 struct stkctr *stkctr;
2682
Emeric Brun819fc6f2017-06-13 19:37:32 +02002683 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002684 if (!stkctr)
2685 return 0;
2686
2687 smp->flags = SMP_F_VOL_TEST;
2688 smp->data.type = SMP_T_SINT;
2689 smp->data.u.sint = 0;
2690 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002691 void *ptr;
2692
2693 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2694 if (!ptr) {
2695 if (stkctr == &tmpstkctr)
2696 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002697 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002698 }
2699
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002700 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002701
Willy Tarreau7d562212016-11-25 16:10:05 +01002702 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002703
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002704 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002705
2706 if (stkctr == &tmpstkctr)
2707 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002708 }
2709 return 1;
2710}
2711
2712/* set <smp> to the HTTP request rate from the stream's tracked frontend
2713 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2714 * "src_http_req_rate" only.
2715 */
2716static int
2717smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2718{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002719 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002720 struct stkctr *stkctr;
2721
Emeric Brun819fc6f2017-06-13 19:37:32 +02002722 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002723 if (!stkctr)
2724 return 0;
2725
2726 smp->flags = SMP_F_VOL_TEST;
2727 smp->data.type = SMP_T_SINT;
2728 smp->data.u.sint = 0;
2729 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002730 void *ptr;
2731
2732 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2733 if (!ptr) {
2734 if (stkctr == &tmpstkctr)
2735 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002736 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002737 }
2738
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002739 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002740
Willy Tarreau7d562212016-11-25 16:10:05 +01002741 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2742 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002743
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002744 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002745
2746 if (stkctr == &tmpstkctr)
2747 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002748 }
2749 return 1;
2750}
2751
2752/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2753 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2754 * "src_http_err_cnt" only.
2755 */
2756static int
2757smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2758{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002759 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002760 struct stkctr *stkctr;
2761
Emeric Brun819fc6f2017-06-13 19:37:32 +02002762 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002763 if (!stkctr)
2764 return 0;
2765
2766 smp->flags = SMP_F_VOL_TEST;
2767 smp->data.type = SMP_T_SINT;
2768 smp->data.u.sint = 0;
2769 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002770 void *ptr;
2771
2772 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2773 if (!ptr) {
2774 if (stkctr == &tmpstkctr)
2775 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002776 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002777 }
2778
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002779 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780
Willy Tarreau7d562212016-11-25 16:10:05 +01002781 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002782
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002783 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002784
2785 if (stkctr == &tmpstkctr)
2786 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002787 }
2788 return 1;
2789}
2790
2791/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2792 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2793 * "src_http_err_rate" only.
2794 */
2795static int
2796smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2797{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002798 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002799 struct stkctr *stkctr;
2800
Emeric Brun819fc6f2017-06-13 19:37:32 +02002801 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002802 if (!stkctr)
2803 return 0;
2804
2805 smp->flags = SMP_F_VOL_TEST;
2806 smp->data.type = SMP_T_SINT;
2807 smp->data.u.sint = 0;
2808 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002809 void *ptr;
2810
2811 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2812 if (!ptr) {
2813 if (stkctr == &tmpstkctr)
2814 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002815 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002816 }
2817
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002818 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002819
Willy Tarreau7d562212016-11-25 16:10:05 +01002820 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2821 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002822
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002823 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002824
2825 if (stkctr == &tmpstkctr)
2826 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002827 }
2828 return 1;
2829}
2830
2831/* set <smp> to the number of kbytes received from clients, as found in the
2832 * stream's tracked frontend counters. Supports being called as
2833 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2834 */
2835static int
2836smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2837{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002838 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002839 struct stkctr *stkctr;
2840
Emeric Brun819fc6f2017-06-13 19:37:32 +02002841 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002842 if (!stkctr)
2843 return 0;
2844
2845 smp->flags = SMP_F_VOL_TEST;
2846 smp->data.type = SMP_T_SINT;
2847 smp->data.u.sint = 0;
2848 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002849 void *ptr;
2850
2851 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2852 if (!ptr) {
2853 if (stkctr == &tmpstkctr)
2854 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002855 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002856 }
2857
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002858 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002859
Willy Tarreau7d562212016-11-25 16:10:05 +01002860 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002861
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002862 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002863
2864 if (stkctr == &tmpstkctr)
2865 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002866 }
2867 return 1;
2868}
2869
2870/* set <smp> to the data rate received from clients in bytes/s, as found
2871 * in the stream's tracked frontend counters. Supports being called as
2872 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2873 */
2874static int
2875smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2876{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002878 struct stkctr *stkctr;
2879
Emeric Brun819fc6f2017-06-13 19:37:32 +02002880 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002881 if (!stkctr)
2882 return 0;
2883
2884 smp->flags = SMP_F_VOL_TEST;
2885 smp->data.type = SMP_T_SINT;
2886 smp->data.u.sint = 0;
2887 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002888 void *ptr;
2889
2890 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2891 if (!ptr) {
2892 if (stkctr == &tmpstkctr)
2893 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002894 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002895 }
2896
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002897 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002898
Willy Tarreau7d562212016-11-25 16:10:05 +01002899 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2900 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002901
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002902 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002903
2904 if (stkctr == &tmpstkctr)
2905 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002906 }
2907 return 1;
2908}
2909
2910/* set <smp> to the number of kbytes sent to clients, as found in the
2911 * stream's tracked frontend counters. Supports being called as
2912 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2913 */
2914static int
2915smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2916{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002917 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002918 struct stkctr *stkctr;
2919
Emeric Brun819fc6f2017-06-13 19:37:32 +02002920 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002921 if (!stkctr)
2922 return 0;
2923
2924 smp->flags = SMP_F_VOL_TEST;
2925 smp->data.type = SMP_T_SINT;
2926 smp->data.u.sint = 0;
2927 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002928 void *ptr;
2929
2930 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2931 if (!ptr) {
2932 if (stkctr == &tmpstkctr)
2933 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002934 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002935 }
2936
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002937 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002938
Willy Tarreau7d562212016-11-25 16:10:05 +01002939 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002940
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002941 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002942
2943 if (stkctr == &tmpstkctr)
2944 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002945 }
2946 return 1;
2947}
2948
2949/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2950 * stream's tracked frontend counters. Supports being called as
2951 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2952 */
2953static int
2954smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2955{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002956 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002957 struct stkctr *stkctr;
2958
Emeric Brun819fc6f2017-06-13 19:37:32 +02002959 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002960 if (!stkctr)
2961 return 0;
2962
2963 smp->flags = SMP_F_VOL_TEST;
2964 smp->data.type = SMP_T_SINT;
2965 smp->data.u.sint = 0;
2966 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002967 void *ptr;
2968
2969 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2970 if (!ptr) {
2971 if (stkctr == &tmpstkctr)
2972 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002973 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002974 }
2975
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002976 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002977
Willy Tarreau7d562212016-11-25 16:10:05 +01002978 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2979 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002980
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002981 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002982
2983 if (stkctr == &tmpstkctr)
2984 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002985 }
2986 return 1;
2987}
2988
2989/* set <smp> to the number of active trackers on the SC entry in the stream's
2990 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2991 */
2992static int
2993smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2994{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002995 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002996 struct stkctr *stkctr;
2997
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 if (!stkctr)
3000 return 0;
3001
3002 smp->flags = SMP_F_VOL_TEST;
3003 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003004 if (stkctr == &tmpstkctr) {
3005 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3006 stktable_release(stkctr->table, stkctr_entry(stkctr));
3007 }
3008 else {
3009 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3010 }
3011
Willy Tarreau7d562212016-11-25 16:10:05 +01003012 return 1;
3013}
3014
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003015
3016/* The functions below are used to manipulate table contents from the CLI.
3017 * There are 3 main actions, "clear", "set" and "show". The code is shared
3018 * between all actions, and the action is encoded in the void *private in
3019 * the appctx as well as in the keyword registration, among one of the
3020 * following values.
3021 */
3022
3023enum {
3024 STK_CLI_ACT_CLR,
3025 STK_CLI_ACT_SET,
3026 STK_CLI_ACT_SHOW,
3027};
3028
3029/* Dump the status of a table to a stream interface's
3030 * read buffer. It returns 0 if the output buffer is full
3031 * and needs to be called again, otherwise non-zero.
3032 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003033static int table_dump_head_to_buffer(struct buffer *msg,
3034 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003035 struct proxy *proxy, struct proxy *target)
3036{
3037 struct stream *s = si_strm(si);
3038
3039 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3040 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3041
3042 /* any other information should be dumped here */
3043
William Lallemand07a62f72017-05-24 00:57:40 +02003044 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003045 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3046
Willy Tarreau06d80a92017-10-19 14:32:15 +02003047 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003048 si_applet_cant_put(si);
3049 return 0;
3050 }
3051
3052 return 1;
3053}
3054
3055/* Dump a table entry to a stream interface's
3056 * read buffer. It returns 0 if the output buffer is full
3057 * and needs to be called again, otherwise non-zero.
3058 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003059static int table_dump_entry_to_buffer(struct buffer *msg,
3060 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003061 struct proxy *proxy, struct stksess *entry)
3062{
3063 int dt;
3064
3065 chunk_appendf(msg, "%p:", entry);
3066
3067 if (proxy->table.type == SMP_T_IPV4) {
3068 char addr[INET_ADDRSTRLEN];
3069 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3070 chunk_appendf(msg, " key=%s", addr);
3071 }
3072 else if (proxy->table.type == SMP_T_IPV6) {
3073 char addr[INET6_ADDRSTRLEN];
3074 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3075 chunk_appendf(msg, " key=%s", addr);
3076 }
3077 else if (proxy->table.type == SMP_T_SINT) {
3078 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3079 }
3080 else if (proxy->table.type == SMP_T_STR) {
3081 chunk_appendf(msg, " key=");
3082 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3083 }
3084 else {
3085 chunk_appendf(msg, " key=");
3086 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3087 }
3088
3089 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3090
3091 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3092 void *ptr;
3093
3094 if (proxy->table.data_ofs[dt] == 0)
3095 continue;
3096 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3097 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3098 else
3099 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3100
3101 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3102 switch (stktable_data_types[dt].std_type) {
3103 case STD_T_SINT:
3104 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3105 break;
3106 case STD_T_UINT:
3107 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3108 break;
3109 case STD_T_ULL:
3110 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3111 break;
3112 case STD_T_FRQP:
3113 chunk_appendf(msg, "%d",
3114 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3115 proxy->table.data_arg[dt].u));
3116 break;
3117 }
3118 }
3119 chunk_appendf(msg, "\n");
3120
Willy Tarreau06d80a92017-10-19 14:32:15 +02003121 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003122 si_applet_cant_put(si);
3123 return 0;
3124 }
3125
3126 return 1;
3127}
3128
3129
3130/* Processes a single table entry matching a specific key passed in argument.
3131 * returns 0 if wants to be called again, 1 if has ended processing.
3132 */
3133static int table_process_entry_per_key(struct appctx *appctx, char **args)
3134{
3135 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003136 struct proxy *px = appctx->ctx.table.target;
3137 struct stksess *ts;
3138 uint32_t uint32_key;
3139 unsigned char ip6_key[sizeof(struct in6_addr)];
3140 long long value;
3141 int data_type;
3142 int cur_arg;
3143 void *ptr;
3144 struct freq_ctr_period *frqp;
3145
3146 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003147 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003148 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003149 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003150 return 1;
3151 }
3152
3153 switch (px->table.type) {
3154 case SMP_T_IPV4:
3155 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003156 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003157 break;
3158 case SMP_T_IPV6:
3159 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003160 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003161 break;
3162 case SMP_T_SINT:
3163 {
3164 char *endptr;
3165 unsigned long val;
3166 errno = 0;
3167 val = strtoul(args[4], &endptr, 10);
3168 if ((errno == ERANGE && val == ULONG_MAX) ||
3169 (errno != 0 && val == 0) || endptr == args[4] ||
3170 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003171 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003172 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003173 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003174 return 1;
3175 }
3176 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003177 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003178 break;
3179 }
3180 break;
3181 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003182 static_table_key.key = args[4];
3183 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003184 break;
3185 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003186 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003187 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003188 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003189 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3190 break;
3191 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003192 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003193 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3194 break;
3195 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003196 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003197 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3198 break;
3199 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003200 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003201 appctx->ctx.cli.msg = "Unknown action\n";
3202 break;
3203 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003204 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003205 return 1;
3206 }
3207
3208 /* check permissions */
3209 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3210 return 1;
3211
Willy Tarreaua24bc782016-12-14 15:50:35 +01003212 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003213 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003214 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003215 if (!ts)
3216 return 1;
3217 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003218 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3219 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_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003223 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003224 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003225 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003226 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003227 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003228 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003229 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003230 break;
3231
3232 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003233 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003234 if (!ts)
3235 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236
3237 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003238 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003239 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003240 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003241 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003242 return 1;
3243 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003244
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003245 break;
3246
3247 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003248 ts = stktable_get_entry(&px->table, &static_table_key);
3249 if (!ts) {
3250 /* don't delete an entry which is currently referenced */
3251 appctx->ctx.cli.severity = LOG_ERR;
3252 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3253 appctx->st0 = CLI_ST_PRINT;
3254 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003255 }
3256
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003257 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003258 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3259 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003260 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003261 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003262 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003263 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003264 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003265 return 1;
3266 }
3267
3268 data_type = stktable_get_data_type(args[cur_arg] + 5);
3269 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003270 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003271 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003272 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003273 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003274 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003275 return 1;
3276 }
3277
3278 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003279 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003280 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003281 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003282 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003283 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003284 return 1;
3285 }
3286
3287 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003288 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003289 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003290 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003291 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003292 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003293 return 1;
3294 }
3295
3296 ptr = stktable_data_ptr(&px->table, ts, data_type);
3297
3298 switch (stktable_data_types[data_type].std_type) {
3299 case STD_T_SINT:
3300 stktable_data_cast(ptr, std_t_sint) = value;
3301 break;
3302 case STD_T_UINT:
3303 stktable_data_cast(ptr, std_t_uint) = value;
3304 break;
3305 case STD_T_ULL:
3306 stktable_data_cast(ptr, std_t_ull) = value;
3307 break;
3308 case STD_T_FRQP:
3309 /* We set both the current and previous values. That way
3310 * the reported frequency is stable during all the period
3311 * then slowly fades out. This allows external tools to
3312 * push measures without having to update them too often.
3313 */
3314 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003315 /* First bit is reserved for the freq_ctr_period lock
3316 Note: here we're still protected by the stksess lock
3317 so we don't need to update the update the freq_ctr_period
3318 using its internal lock */
3319 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003320 frqp->prev_ctr = 0;
3321 frqp->curr_ctr = value;
3322 break;
3323 }
3324 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003325 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003326 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003327 break;
3328
3329 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003330 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003331 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003332 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003333 break;
3334 }
3335 return 1;
3336}
3337
3338/* Prepares the appctx fields with the data-based filters from the command line.
3339 * Returns 0 if the dump can proceed, 1 if has ended processing.
3340 */
3341static int table_prepare_data_request(struct appctx *appctx, char **args)
3342{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003343 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003344 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003345 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003346 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003347 return 1;
3348 }
3349
3350 /* condition on stored data value */
3351 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3352 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003353 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003354 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003355 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003356 return 1;
3357 }
3358
3359 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003360 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003361 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003362 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003363 return 1;
3364 }
3365
3366 appctx->ctx.table.data_op = get_std_op(args[4]);
3367 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003368 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003369 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003370 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003371 return 1;
3372 }
3373
3374 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003375 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003376 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003377 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003378 return 1;
3379 }
3380
3381 /* OK we're done, all the fields are set */
3382 return 0;
3383}
3384
3385/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003386static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003387{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003388 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003389 appctx->ctx.table.target = NULL;
3390 appctx->ctx.table.proxy = NULL;
3391 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003392 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003393
3394 if (*args[2]) {
3395 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3396 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003397 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003398 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003399 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003400 return 1;
3401 }
3402 }
3403 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003404 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003405 goto err_args;
3406 return 0;
3407 }
3408
3409 if (strcmp(args[3], "key") == 0)
3410 return table_process_entry_per_key(appctx, args);
3411 else if (strncmp(args[3], "data.", 5) == 0)
3412 return table_prepare_data_request(appctx, args);
3413 else if (*args[3])
3414 goto err_args;
3415
3416 return 0;
3417
3418err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003419 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003420 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003421 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003422 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3423 break;
3424 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003425 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003426 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3427 break;
3428 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003429 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003430 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3431 break;
3432 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003433 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003434 appctx->ctx.cli.msg = "Unknown action\n";
3435 break;
3436 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003437 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003438 return 1;
3439}
3440
3441/* This function is used to deal with table operations (dump or clear depending
3442 * on the action stored in appctx->private). It returns 0 if the output buffer is
3443 * full and it needs to be called again, otherwise non-zero.
3444 */
3445static int cli_io_handler_table(struct appctx *appctx)
3446{
3447 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003448 struct stream *s = si_strm(si);
3449 struct ebmb_node *eb;
3450 int dt;
3451 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003452 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003453
3454 /*
3455 * We have 3 possible states in appctx->st2 :
3456 * - STAT_ST_INIT : the first call
3457 * - STAT_ST_INFO : the proxy pointer points to the next table to
3458 * dump, the entry pointer is NULL ;
3459 * - STAT_ST_LIST : the proxy pointer points to the current table
3460 * and the entry pointer points to the next entry to be dumped,
3461 * and the refcount on the next entry is held ;
3462 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3463 * data though.
3464 */
3465
3466 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3467 /* in case of abort, remove any refcount we might have set on an entry */
3468 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003469 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003470 }
3471 return 1;
3472 }
3473
3474 chunk_reset(&trash);
3475
3476 while (appctx->st2 != STAT_ST_FIN) {
3477 switch (appctx->st2) {
3478 case STAT_ST_INIT:
3479 appctx->ctx.table.proxy = appctx->ctx.table.target;
3480 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003481 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003482
3483 appctx->ctx.table.entry = NULL;
3484 appctx->st2 = STAT_ST_INFO;
3485 break;
3486
3487 case STAT_ST_INFO:
3488 if (!appctx->ctx.table.proxy ||
3489 (appctx->ctx.table.target &&
3490 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3491 appctx->st2 = STAT_ST_END;
3492 break;
3493 }
3494
3495 if (appctx->ctx.table.proxy->table.size) {
3496 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3497 return 0;
3498
3499 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003500 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003501 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003502 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003503 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3504 if (eb) {
3505 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3506 appctx->ctx.table.entry->ref_cnt++;
3507 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003508 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003509 break;
3510 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003511 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003512 }
3513 }
3514 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3515 break;
3516
3517 case STAT_ST_LIST:
3518 skip_entry = 0;
3519
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003520 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003521
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003522 if (appctx->ctx.table.data_type >= 0) {
3523 /* we're filtering on some data contents */
3524 void *ptr;
3525 long long data;
3526
Emeric Brun819fc6f2017-06-13 19:37:32 +02003527
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003528 dt = appctx->ctx.table.data_type;
3529 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3530 appctx->ctx.table.entry,
3531 dt);
3532
3533 data = 0;
3534 switch (stktable_data_types[dt].std_type) {
3535 case STD_T_SINT:
3536 data = stktable_data_cast(ptr, std_t_sint);
3537 break;
3538 case STD_T_UINT:
3539 data = stktable_data_cast(ptr, std_t_uint);
3540 break;
3541 case STD_T_ULL:
3542 data = stktable_data_cast(ptr, std_t_ull);
3543 break;
3544 case STD_T_FRQP:
3545 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3546 appctx->ctx.table.proxy->table.data_arg[dt].u);
3547 break;
3548 }
3549
3550 /* skip the entry if the data does not match the test and the value */
3551 if ((data < appctx->ctx.table.value &&
3552 (appctx->ctx.table.data_op == STD_OP_EQ ||
3553 appctx->ctx.table.data_op == STD_OP_GT ||
3554 appctx->ctx.table.data_op == STD_OP_GE)) ||
3555 (data == appctx->ctx.table.value &&
3556 (appctx->ctx.table.data_op == STD_OP_NE ||
3557 appctx->ctx.table.data_op == STD_OP_GT ||
3558 appctx->ctx.table.data_op == STD_OP_LT)) ||
3559 (data > appctx->ctx.table.value &&
3560 (appctx->ctx.table.data_op == STD_OP_EQ ||
3561 appctx->ctx.table.data_op == STD_OP_LT ||
3562 appctx->ctx.table.data_op == STD_OP_LE)))
3563 skip_entry = 1;
3564 }
3565
3566 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003567 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003568 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003569 return 0;
3570 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003571
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003572 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003573
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003574 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003575 appctx->ctx.table.entry->ref_cnt--;
3576
3577 eb = ebmb_next(&appctx->ctx.table.entry->key);
3578 if (eb) {
3579 struct stksess *old = appctx->ctx.table.entry;
3580 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3581 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003582 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003583 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003584 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003585 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003586 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003587 break;
3588 }
3589
3590
3591 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003592 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003593 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003594 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3595
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003596 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003597
3598 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3599 appctx->st2 = STAT_ST_INFO;
3600 break;
3601
3602 case STAT_ST_END:
3603 appctx->st2 = STAT_ST_FIN;
3604 break;
3605 }
3606 }
3607 return 1;
3608}
3609
3610static void cli_release_show_table(struct appctx *appctx)
3611{
3612 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003613 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003614 }
3615}
3616
3617/* register cli keywords */
3618static struct cli_kw_list cli_kws = {{ },{
3619 { { "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 },
3620 { { "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 },
3621 { { "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 },
3622 {{},}
3623}};
3624
3625
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003626static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003627 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003628 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003629 { "sc-set-gpt0", parse_set_gpt0, 1 },
3630 { /* END */ }
3631}};
3632
Willy Tarreau620408f2016-10-21 16:37:51 +02003633static struct action_kw_list tcp_sess_kws = { { }, {
3634 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003635 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003636 { "sc-set-gpt0", parse_set_gpt0, 1 },
3637 { /* END */ }
3638}};
3639
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003640static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003641 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003642 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003643 { "sc-set-gpt0", parse_set_gpt0, 1 },
3644 { /* END */ }
3645}};
3646
3647static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003648 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003649 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003650 { "sc-set-gpt0", parse_set_gpt0, 1 },
3651 { /* END */ }
3652}};
3653
3654static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003655 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003656 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003657 { "sc-set-gpt0", parse_set_gpt0, 1 },
3658 { /* END */ }
3659}};
3660
3661static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003662 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003663 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003664 { "sc-set-gpt0", parse_set_gpt0, 1 },
3665 { /* END */ }
3666}};
3667
Willy Tarreau7d562212016-11-25 16:10:05 +01003668///* Note: must not be declared <const> as its list will be overwritten.
3669// * Please take care of keeping this list alphabetically sorted.
3670// */
3671//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3672// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3673// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3674// { /* END */ },
3675//}};
3676/* Note: must not be declared <const> as its list will be overwritten.
3677 * Please take care of keeping this list alphabetically sorted.
3678 */
3679static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3680 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3681 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3682 { "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 +01003683 { "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 +01003684 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3685 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3686 { "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 +01003687 { "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 +01003688 { "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 +01003689 { "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 +01003690 { "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 +01003691 { "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 +01003692 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3693 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3694 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3695 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3696 { "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 +01003697 { "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 +01003698 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3699 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3700 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3701 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3702 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3703 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3704 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3705 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3706 { "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 +01003707 { "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 +01003708 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3709 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3710 { "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 +01003711 { "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 +01003712 { "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 +01003713 { "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 +01003714 { "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 +01003715 { "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 +01003716 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3717 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3718 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3719 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3720 { "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 +01003721 { "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 +01003722 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3723 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3724 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3725 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3726 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3727 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3728 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3729 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3730 { "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 +01003731 { "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 +01003732 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3733 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3734 { "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 +01003735 { "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 +01003736 { "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 +01003737 { "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 +01003738 { "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 +01003739 { "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 +01003740 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3741 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3742 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3743 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3744 { "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 +01003745 { "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 +01003746 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3747 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3748 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3749 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3750 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3751 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3752 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3753 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3754 { "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 +01003755 { "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 +01003756 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3757 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3758 { "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 +01003759 { "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 +01003760 { "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 +01003761 { "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 +01003762 { "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 +01003763 { "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 +01003764 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3765 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3766 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3767 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3768 { "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 +01003769 { "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 +01003770 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3771 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3772 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3773 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3774 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3775 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3776 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3777 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3778 { "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 +01003779 { "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 +01003780 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3781 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3782 { "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 +01003783 { "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 +01003784 { "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 +01003785 { "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 +01003786 { "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 +01003787 { "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 +01003788 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3789 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3790 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3791 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3792 { "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 +01003793 { "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 +01003794 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3795 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3796 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3797 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3798 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3799 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3800 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3801 { /* END */ },
3802}};
3803
3804
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003805/* Note: must not be declared <const> as its list will be overwritten */
3806static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003807 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3808 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3809 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3810 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3811 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3812 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3813 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3814 { "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 +01003815 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003816 { "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 +01003817 { "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 +02003818 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3819 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3820 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3821 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3822 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3823 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3824 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3825 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3826 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3827 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003828 { /* END */ },
3829}};
3830
3831__attribute__((constructor))
3832static void __stick_table_init(void)
3833{
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003834 /* register som action keywords. */
3835 tcp_req_conn_keywords_register(&tcp_conn_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +02003836 tcp_req_sess_keywords_register(&tcp_sess_kws);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003837 tcp_req_cont_keywords_register(&tcp_req_kws);
3838 tcp_res_cont_keywords_register(&tcp_res_kws);
3839 http_req_keywords_register(&http_req_kws);
3840 http_res_keywords_register(&http_res_kws);
3841
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003842 /* register sample fetch and format conversion keywords */
Willy Tarreau7d562212016-11-25 16:10:05 +01003843 sample_register_fetches(&smp_fetch_keywords);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003844 sample_register_convs(&sample_conv_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003845 cli_register_kw(&cli_kws);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003846}