blob: 0e84102f6c5ab864bf5c0afdf0c0dde808af4c67 [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 Tarreau393379c2010-06-06 12:11:37 +020054 pool_free2(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{
64 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
65 __stksess_free(t, ts);
66 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
67}
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
93 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
94 if (decrefcnt)
95 ts->ref_cnt--;
96 ret = __stksess_kill(t, ts);
97 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
98
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));
129 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
204 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
205 ret = __stktable_trash_oldest(t, to_batch);
206 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
207
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
Vincent Bernatef8f4fe2016-11-17 15:42:40 +0100229 ts = pool_alloc2(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
252 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
253 ts = __stksess_new(t, key);
254 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
255
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
Emeric Brun819fc6f2017-06-13 19:37:32 +0200290 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
291 ts = __stktable_lookup_key(t, key);
292 if (ts)
293 ts->ref_cnt++;
294 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
328 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
329 lts = __stktable_lookup(t, ts);
330 if (lts)
331 lts->ref_cnt++;
332 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
333
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{
392 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
393 __stktable_touch_with_exp(t, ts, 0, ts->expire);
394 if (decrefcnt)
395 ts->ref_cnt--;
396 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
397}
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
Emeric Brun819fc6f2017-06-13 19:37:32 +0200409 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
410 __stktable_touch_with_exp(t, ts, 1, expire);
411 if (decrefcnt)
412 ts->ref_cnt--;
413 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
414}
415/* Just decrease the ref_cnt of the current session */
416void stktable_release(struct stktable *t, struct stksess *ts)
417{
418 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
419 ts->ref_cnt--;
420 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200421}
422
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200423/* Insert new sticky session <ts> in the table. It is assumed that it does not
424 * yet exist (the caller must check this). The table's timeout is updated if it
425 * is set. <ts> is returned.
426 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200427void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200428{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100429
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200430 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200431 ts->exp.key = ts->expire;
432 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200433 if (t->expire) {
434 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
435 task_queue(t->exp_task);
436 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200437}
438
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200439/* Returns a valid or initialized stksess for the specified stktable_key in the
440 * specified table, or NULL if the key was NULL, or if no entry was found nor
441 * could be created. The entry's expiration is updated.
442 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200443struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200444{
445 struct stksess *ts;
446
447 if (!key)
448 return NULL;
449
Emeric Brun819fc6f2017-06-13 19:37:32 +0200450 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200451 if (ts == NULL) {
452 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200454 if (!ts)
455 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200457 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200458 return ts;
459}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200460/* Returns a valid or initialized stksess for the specified stktable_key in the
461 * specified table, or NULL if the key was NULL, or if no entry was found nor
462 * could be created. The entry's expiration is updated.
463 * This function locks the table, and the refcount of the entry is increased.
464 */
465struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
466{
467 struct stksess *ts;
468
469 SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
470 ts = __stktable_get_entry(table, key);
471 if (ts)
472 ts->ref_cnt++;
473 SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
474
475 return ts;
476}
477
478/* Lookup for an entry with the same key and store the submitted
479 * stksess if not found.
480 */
481struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
482{
483 struct stksess *ts;
484
485 ts = __stktable_lookup(table, nts);
486 if (ts == NULL) {
487 ts = nts;
488 __stktable_store(table, ts);
489 }
490 return ts;
491}
492
493/* Lookup for an entry with the same key and store the submitted
494 * stksess if not found.
495 * This function locks the table, and the refcount of the entry is increased.
496 */
497struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
498{
499 struct stksess *ts;
500
501 SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
502 ts = __stktable_set_entry(table, nts);
503 ts->ref_cnt++;
504 SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200505
Emeric Brun819fc6f2017-06-13 19:37:32 +0200506 return ts;
507}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100508/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200509 * Trash expired sticky sessions from table <t>. The next expiration date is
510 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100511 */
512static int stktable_trash_expired(struct stktable *t)
513{
514 struct stksess *ts;
515 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200516 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100517
Emeric Brun819fc6f2017-06-13 19:37:32 +0200518 SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100519 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
520
521 while (1) {
522 if (unlikely(!eb)) {
523 /* we might have reached the end of the tree, typically because
524 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200525 * half. Let's loop back to the beginning of the tree now if we
526 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100527 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200528 if (looped)
529 break;
530 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100531 eb = eb32_first(&t->exps);
532 if (likely(!eb))
533 break;
534 }
535
536 if (likely(tick_is_lt(now_ms, eb->key))) {
537 /* timer not expired yet, revisit it later */
538 t->exp_next = eb->key;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200539 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100540 return t->exp_next;
541 }
542
543 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200544 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100545 eb = eb32_next(eb);
546
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200547 /* don't delete an entry which is currently referenced */
548 if (ts->ref_cnt)
549 continue;
550
Willy Tarreau86257dc2010-06-06 12:57:10 +0200551 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100552
553 if (!tick_is_expired(ts->expire, now_ms)) {
554 if (!tick_isset(ts->expire))
555 continue;
556
Willy Tarreau86257dc2010-06-06 12:57:10 +0200557 ts->exp.key = ts->expire;
558 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100559
Willy Tarreau86257dc2010-06-06 12:57:10 +0200560 if (!eb || eb->key > ts->exp.key)
561 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100562 continue;
563 }
564
565 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200566 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200567 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200568 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100569 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200570 SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100571
572 /* We have found no task to expire in any tree */
573 t->exp_next = TICK_ETERNITY;
574 return t->exp_next;
575}
576
577/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200578 * Task processing function to trash expired sticky sessions. A pointer to the
579 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100580 */
Willy Tarreauaea940e2010-06-06 11:56:36 +0200581static struct task *process_table_expire(struct task *task)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100582{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200583 struct stktable *t = task->context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100584
585 task->expire = stktable_trash_expired(t);
586 return task;
587}
588
Willy Tarreauaea940e2010-06-06 11:56:36 +0200589/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100590int stktable_init(struct stktable *t)
591{
592 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200593 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100594 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100595 t->updates = EB_ROOT_UNIQUE;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200596 SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100597
Willy Tarreau393379c2010-06-06 12:11:37 +0200598 t->pool = create_pool("sticktables", sizeof(struct stksess) + t->data_size + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100599
600 t->exp_next = TICK_ETERNITY;
601 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200602 t->exp_task = task_new(MAX_THREADS_MASK);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100603 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100604 t->exp_task->context = (void *)t;
605 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200606 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200607 peers_register_table(t->peers.p, t);
608 }
609
Emeric Brun3bd697e2010-01-04 15:23:48 +0100610 return t->pool != NULL;
611 }
612 return 1;
613}
614
615/*
616 * Configuration keywords of known table types
617 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200618struct stktable_type stktable_types[SMP_TYPES] = {
619 [SMP_T_SINT] = { "integer", 0, 4 },
620 [SMP_T_IPV4] = { "ip", 0, 4 },
621 [SMP_T_IPV6] = { "ipv6", 0, 16 },
622 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
623 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
624};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100625
626/*
627 * Parse table type configuration.
628 * Returns 0 on successful parsing, else 1.
629 * <myidx> is set at next configuration <args> index.
630 */
631int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
632{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200633 for (*type = 0; *type < SMP_TYPES; (*type)++) {
634 if (!stktable_types[*type].kw)
635 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100636 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
637 continue;
638
639 *key_size = stktable_types[*type].default_size;
640 (*myidx)++;
641
Willy Tarreauaea940e2010-06-06 11:56:36 +0200642 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100643 if (strcmp("len", args[*myidx]) == 0) {
644 (*myidx)++;
645 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200646 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100647 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200648 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200649 /* null terminated string needs +1 for '\0'. */
650 (*key_size)++;
651 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100652 (*myidx)++;
653 }
654 }
655 return 0;
656 }
657 return 1;
658}
659
Willy Tarreau8fed9032014-07-03 17:02:46 +0200660/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200661 * Note that the sample *is* modified and that the returned key may point
662 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200663 * Returns NULL if the sample could not be converted (eg: no matching type),
664 * otherwise a pointer to the static stktable_key filled with what is needed
665 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200666 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200667struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200668{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200669 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200670 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200671 return NULL;
672
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200673 /* Fill static_table_key. */
674 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200675
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200676 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200677 static_table_key.key = &smp->data.u.ipv4;
678 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200679 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200680
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200681 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200682 static_table_key.key = &smp->data.u.ipv6;
683 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200684 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200685
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200686 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200687 /* The stick table require a 32bit unsigned int, "sint" is a
688 * signed 64 it, so we can convert it inplace.
689 */
690 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200691 static_table_key.key = &smp->data.u.sint;
692 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200693 break;
694
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200695 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200696 if (!smp_make_safe(smp))
697 return NULL;
Christopher Fauletca20d022017-08-29 15:30:31 +0200698 static_table_key.key = smp->data.u.str.str;
699 static_table_key.key_len = smp->data.u.str.len;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200700 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200701
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200702 case SMP_T_BIN:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200703 if (smp->data.u.str.len < t->key_size) {
704 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200705 if (!smp_make_rw(smp))
706 return NULL;
707
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200708 if (smp->data.u.str.size < t->key_size)
709 if (!smp_dup(smp))
710 return NULL;
711 if (smp->data.u.str.size < t->key_size)
712 return NULL;
713 memset(smp->data.u.str.str + smp->data.u.str.len, 0,
714 t->key_size - smp->data.u.str.len);
715 smp->data.u.str.len = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200716 }
Christopher Fauletca20d022017-08-29 15:30:31 +0200717 static_table_key.key = smp->data.u.str.str;
718 static_table_key.key_len = smp->data.u.str.len;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200719 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200720
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200721 default: /* impossible case. */
722 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200723 }
724
Christopher Fauletca20d022017-08-29 15:30:31 +0200725 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200726}
727
728/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200729 * Process a fetch + format conversion as defined by the sample expression <expr>
730 * on request or response considering the <opt> parameter. Returns either NULL if
731 * no key could be extracted, or a pointer to the converted result stored in
732 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
733 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200734 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
735 * without SMP_OPT_FINAL). The output will be usable like this :
736 *
737 * return MAY_CHANGE FINAL Meaning for the sample
738 * NULL 0 * Not present and will never be (eg: header)
739 * NULL 1 0 Not present or unstable, could change (eg: req_len)
740 * NULL 1 1 Not present, will not change anymore
741 * smp 0 * Present and will not change (eg: header)
742 * smp 1 0 not possible
743 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200744 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200745struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200746 unsigned int opt, struct sample_expr *expr, struct sample *smp)
747{
748 if (smp)
749 memset(smp, 0, sizeof(*smp));
750
Willy Tarreau192252e2015-04-04 01:47:55 +0200751 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200752 if (!smp)
753 return NULL;
754
755 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
756 return NULL; /* we can only use stable samples */
757
758 return smp_to_stkey(smp, t);
759}
760
761/*
Willy Tarreau12785782012-04-27 21:37:17 +0200762 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200763 * type <table_type>, otherwise zero. Used in configuration check.
764 */
Willy Tarreau12785782012-04-27 21:37:17 +0200765int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200766{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100767 int out_type;
768
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200769 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200770 return 0;
771
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100772 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200773
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200774 /* Convert sample. */
775 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100776 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200777
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200778 return 1;
779}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100780
Willy Tarreauedee1d62014-07-15 16:44:27 +0200781/* Extra data types processing : after the last one, some room may remain
782 * before STKTABLE_DATA_TYPES that may be used to register extra data types
783 * at run time.
784 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200785struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200786 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200787 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200788 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200789 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200790 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
791 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
792 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
793 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
794 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
795 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
796 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
797 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
798 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
799 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
800 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
801 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
802 [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +0200803};
804
Willy Tarreauedee1d62014-07-15 16:44:27 +0200805/* Registers stick-table extra data type with index <idx>, name <name>, type
806 * <std_type> and arg type <arg_type>. If the index is negative, the next free
807 * index is automatically allocated. The allocated index is returned, or -1 if
808 * no free index was found or <name> was already registered. The <name> is used
809 * directly as a pointer, so if it's not stable, the caller must allocate it.
810 */
811int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
812{
813 if (idx < 0) {
814 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
815 if (!stktable_data_types[idx].name)
816 break;
817
818 if (strcmp(stktable_data_types[idx].name, name) == 0)
819 return -1;
820 }
821 }
822
823 if (idx >= STKTABLE_DATA_TYPES)
824 return -1;
825
826 if (stktable_data_types[idx].name != NULL)
827 return -1;
828
829 stktable_data_types[idx].name = name;
830 stktable_data_types[idx].std_type = std_type;
831 stktable_data_types[idx].arg_type = arg_type;
832 return idx;
833}
834
Willy Tarreau08d5f982010-06-06 13:34:54 +0200835/*
836 * Returns the data type number for the stktable_data_type whose name is <name>,
837 * or <0 if not found.
838 */
839int stktable_get_data_type(char *name)
840{
841 int type;
842
843 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +0200844 if (!stktable_data_types[type].name)
845 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +0200846 if (strcmp(name, stktable_data_types[type].name) == 0)
847 return type;
848 }
849 return -1;
850}
851
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200852/* Casts sample <smp> to the type of the table specified in arg(0), and looks
853 * it up into this table. Returns true if found, false otherwise. The input
854 * type is STR so that input samples are converted to string (since all types
855 * can be converted to strings), then the function casts the string again into
856 * the table's type. This is a double conversion, but in the future we might
857 * support automatic input types to perform the cast on the fly.
858 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200859static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200860{
861 struct stktable *t;
862 struct stktable_key *key;
863 struct stksess *ts;
864
865 t = &arg_p[0].data.prx->table;
866
867 key = smp_to_stkey(smp, t);
868 if (!key)
869 return 0;
870
871 ts = stktable_lookup_key(t, key);
872
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200873 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200874 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200875 smp->flags = SMP_F_VOL_TEST;
876 return 1;
877}
878
879/* Casts sample <smp> to the type of the table specified in arg(0), and looks
880 * it up into this table. Returns the data rate received from clients in bytes/s
881 * if the key is present in the table, otherwise zero, so that comparisons can
882 * be easily performed. If the inspected parameter is not stored in the table,
883 * <not found> is returned.
884 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200885static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200886{
887 struct stktable *t;
888 struct stktable_key *key;
889 struct stksess *ts;
890 void *ptr;
891
892 t = &arg_p[0].data.prx->table;
893
894 key = smp_to_stkey(smp, t);
895 if (!key)
896 return 0;
897
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200898 ts = stktable_lookup_key(t, key);
899
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200900 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200901 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200902 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200903
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200904 if (!ts) /* key not present */
905 return 1;
906
907 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
908 if (!ptr)
909 return 0; /* parameter not stored */
910
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200911 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200912 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
913 return 1;
914}
915
916/* Casts sample <smp> to the type of the table specified in arg(0), and looks
917 * it up into this table. Returns the cumulated number of connections for the key
918 * if the key is present in the table, otherwise zero, so that comparisons can
919 * be easily performed. If the inspected parameter is not stored in the table,
920 * <not found> is returned.
921 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200922static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200923{
924 struct stktable *t;
925 struct stktable_key *key;
926 struct stksess *ts;
927 void *ptr;
928
929 t = &arg_p[0].data.prx->table;
930
931 key = smp_to_stkey(smp, t);
932 if (!key)
933 return 0;
934
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200935 ts = stktable_lookup_key(t, key);
936
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200937 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200938 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200939 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200940
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200941 if (!ts) /* key not present */
942 return 1;
943
944 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
945 if (!ptr)
946 return 0; /* parameter not stored */
947
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200948 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200949 return 1;
950}
951
952/* Casts sample <smp> to the type of the table specified in arg(0), and looks
953 * it up into this table. Returns the number of concurrent connections for the
954 * key if the key is present in the table, otherwise zero, so that comparisons
955 * can be easily performed. If the inspected parameter is not stored in the
956 * table, <not found> is returned.
957 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200958static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200959{
960 struct stktable *t;
961 struct stktable_key *key;
962 struct stksess *ts;
963 void *ptr;
964
965 t = &arg_p[0].data.prx->table;
966
967 key = smp_to_stkey(smp, t);
968 if (!key)
969 return 0;
970
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200971 ts = stktable_lookup_key(t, key);
972
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200973 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200974 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200975 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200976
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200977 if (!ts) /* key not present */
978 return 1;
979
980 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
981 if (!ptr)
982 return 0; /* parameter not stored */
983
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200984 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200985 return 1;
986}
987
988/* Casts sample <smp> to the type of the table specified in arg(0), and looks
989 * it up into this table. Returns the rate of incoming connections from the key
990 * if the key is present in the table, otherwise zero, so that comparisons can
991 * be easily performed. If the inspected parameter is not stored in the table,
992 * <not found> is returned.
993 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200994static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200995{
996 struct stktable *t;
997 struct stktable_key *key;
998 struct stksess *ts;
999 void *ptr;
1000
1001 t = &arg_p[0].data.prx->table;
1002
1003 key = smp_to_stkey(smp, t);
1004 if (!key)
1005 return 0;
1006
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001007 ts = stktable_lookup_key(t, key);
1008
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001009 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001010 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001011 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001012
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001013 if (!ts) /* key not present */
1014 return 1;
1015
1016 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
1017 if (!ptr)
1018 return 0; /* parameter not stored */
1019
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001020 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001021 t->data_arg[STKTABLE_DT_CONN_RATE].u);
1022 return 1;
1023}
1024
1025/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1026 * it up into this table. Returns the data rate sent to clients in bytes/s
1027 * if the key is present in the table, otherwise zero, so that comparisons can
1028 * be easily performed. If the inspected parameter is not stored in the table,
1029 * <not found> is returned.
1030 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001031static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001032{
1033 struct stktable *t;
1034 struct stktable_key *key;
1035 struct stksess *ts;
1036 void *ptr;
1037
1038 t = &arg_p[0].data.prx->table;
1039
1040 key = smp_to_stkey(smp, t);
1041 if (!key)
1042 return 0;
1043
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001044 ts = stktable_lookup_key(t, key);
1045
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001046 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001047 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001048 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001049
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001050 if (!ts) /* key not present */
1051 return 1;
1052
1053 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
1054 if (!ptr)
1055 return 0; /* parameter not stored */
1056
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001057 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001058 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
1059 return 1;
1060}
1061
1062/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001063 * it up into this table. Returns the value of the GPT0 tag for the key
1064 * if the key is present in the table, otherwise false, so that comparisons can
1065 * be easily performed. If the inspected parameter is not stored in the table,
1066 * <not found> is returned.
1067 */
1068static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1069{
1070 struct stktable *t;
1071 struct stktable_key *key;
1072 struct stksess *ts;
1073 void *ptr;
1074
1075 t = &arg_p[0].data.prx->table;
1076
1077 key = smp_to_stkey(smp, t);
1078 if (!key)
1079 return 0;
1080
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001081 ts = stktable_lookup_key(t, key);
1082
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001083 smp->flags = SMP_F_VOL_TEST;
1084 smp->data.type = SMP_T_SINT;
1085 smp->data.u.sint = 0;
1086
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001087 if (!ts) /* key not present */
1088 return 1;
1089
1090 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
1091 if (!ptr)
1092 return 0; /* parameter not stored */
1093
1094 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
1095 return 1;
1096}
1097
1098/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001099 * it up into this table. Returns the value of the GPC0 counter for the key
1100 * if the key is present in the table, otherwise zero, so that comparisons can
1101 * be easily performed. If the inspected parameter is not stored in the table,
1102 * <not found> is returned.
1103 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001104static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001105{
1106 struct stktable *t;
1107 struct stktable_key *key;
1108 struct stksess *ts;
1109 void *ptr;
1110
1111 t = &arg_p[0].data.prx->table;
1112
1113 key = smp_to_stkey(smp, t);
1114 if (!key)
1115 return 0;
1116
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001117 ts = stktable_lookup_key(t, key);
1118
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001119 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001120 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001121 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001122
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001123 if (!ts) /* key not present */
1124 return 1;
1125
1126 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
1127 if (!ptr)
1128 return 0; /* parameter not stored */
1129
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001130 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001131 return 1;
1132}
1133
1134/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1135 * it up into this table. Returns the event rate of the GPC0 counter for the key
1136 * if the key is present in the table, otherwise zero, so that comparisons can
1137 * be easily performed. If the inspected parameter is not stored in the table,
1138 * <not found> is returned.
1139 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001140static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001141{
1142 struct stktable *t;
1143 struct stktable_key *key;
1144 struct stksess *ts;
1145 void *ptr;
1146
1147 t = &arg_p[0].data.prx->table;
1148
1149 key = smp_to_stkey(smp, t);
1150 if (!key)
1151 return 0;
1152
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001153 ts = stktable_lookup_key(t, key);
1154
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001155 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001156 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001157 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001158
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001159 if (!ts) /* key not present */
1160 return 1;
1161
1162 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
1163 if (!ptr)
1164 return 0; /* parameter not stored */
1165
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001166 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001167 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
1168 return 1;
1169}
1170
1171/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1172 * it up into this table. Returns the cumulated number of HTTP request errors
1173 * for the key if the key is present in the table, otherwise zero, so that
1174 * comparisons can be easily performed. If the inspected parameter is not stored
1175 * in the table, <not found> is returned.
1176 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001177static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001178{
1179 struct stktable *t;
1180 struct stktable_key *key;
1181 struct stksess *ts;
1182 void *ptr;
1183
1184 t = &arg_p[0].data.prx->table;
1185
1186 key = smp_to_stkey(smp, t);
1187 if (!key)
1188 return 0;
1189
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001190 ts = stktable_lookup_key(t, key);
1191
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001192 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001193 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001194 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001195
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001196 if (!ts) /* key not present */
1197 return 1;
1198
1199 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
1200 if (!ptr)
1201 return 0; /* parameter not stored */
1202
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001203 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001204 return 1;
1205}
1206
1207/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1208 * it up into this table. Returns the HTTP request error rate the key
1209 * if the key is present in the table, otherwise zero, so that comparisons can
1210 * be easily performed. If the inspected parameter is not stored in the table,
1211 * <not found> is returned.
1212 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001213static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001214{
1215 struct stktable *t;
1216 struct stktable_key *key;
1217 struct stksess *ts;
1218 void *ptr;
1219
1220 t = &arg_p[0].data.prx->table;
1221
1222 key = smp_to_stkey(smp, t);
1223 if (!key)
1224 return 0;
1225
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001226 ts = stktable_lookup_key(t, key);
1227
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001228 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001229 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001230 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001231
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001232 if (!ts) /* key not present */
1233 return 1;
1234
1235 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
1236 if (!ptr)
1237 return 0; /* parameter not stored */
1238
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001239 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001240 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
1241 return 1;
1242}
1243
1244/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1245 * it up into this table. Returns the cumulated number of HTTP request for the
1246 * key if the key is present in the table, otherwise zero, so that comparisons
1247 * can be easily performed. If the inspected parameter is not stored in the
1248 * table, <not found> is returned.
1249 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001250static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251{
1252 struct stktable *t;
1253 struct stktable_key *key;
1254 struct stksess *ts;
1255 void *ptr;
1256
1257 t = &arg_p[0].data.prx->table;
1258
1259 key = smp_to_stkey(smp, t);
1260 if (!key)
1261 return 0;
1262
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001263 ts = stktable_lookup_key(t, key);
1264
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001265 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001266 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001267 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001268
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001269 if (!ts) /* key not present */
1270 return 1;
1271
1272 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
1273 if (!ptr)
1274 return 0; /* parameter not stored */
1275
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001276 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001277 return 1;
1278}
1279
1280/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1281 * it up into this table. Returns the HTTP request rate the key if the key is
1282 * present in the table, otherwise zero, so that comparisons can be easily
1283 * performed. If the inspected parameter is not stored in the table, <not found>
1284 * is returned.
1285 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001286static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001287{
1288 struct stktable *t;
1289 struct stktable_key *key;
1290 struct stksess *ts;
1291 void *ptr;
1292
1293 t = &arg_p[0].data.prx->table;
1294
1295 key = smp_to_stkey(smp, t);
1296 if (!key)
1297 return 0;
1298
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001299 ts = stktable_lookup_key(t, key);
1300
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001301 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001302 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001303 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001304
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001305 if (!ts) /* key not present */
1306 return 1;
1307
1308 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
1309 if (!ptr)
1310 return 0; /* parameter not stored */
1311
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001312 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001313 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
1314 return 1;
1315}
1316
1317/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1318 * it up into this table. Returns the volume of datareceived from clients in kbytes
1319 * if the key is present in the table, otherwise zero, so that comparisons can
1320 * be easily performed. If the inspected parameter is not stored in the table,
1321 * <not found> is returned.
1322 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001323static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001324{
1325 struct stktable *t;
1326 struct stktable_key *key;
1327 struct stksess *ts;
1328 void *ptr;
1329
1330 t = &arg_p[0].data.prx->table;
1331
1332 key = smp_to_stkey(smp, t);
1333 if (!key)
1334 return 0;
1335
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001336 ts = stktable_lookup_key(t, key);
1337
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001338 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001339 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001340 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001341
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001342 if (!ts) /* key not present */
1343 return 1;
1344
1345 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
1346 if (!ptr)
1347 return 0; /* parameter not stored */
1348
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001349 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350 return 1;
1351}
1352
1353/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1354 * it up into this table. Returns the volume of data sent to clients in kbytes
1355 * if the key is present in the table, otherwise zero, so that comparisons can
1356 * be easily performed. If the inspected parameter is not stored in the table,
1357 * <not found> is returned.
1358 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001359static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001360{
1361 struct stktable *t;
1362 struct stktable_key *key;
1363 struct stksess *ts;
1364 void *ptr;
1365
1366 t = &arg_p[0].data.prx->table;
1367
1368 key = smp_to_stkey(smp, t);
1369 if (!key)
1370 return 0;
1371
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001372 ts = stktable_lookup_key(t, key);
1373
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001374 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001375 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001376 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001377
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001378 if (!ts) /* key not present */
1379 return 1;
1380
1381 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
1382 if (!ptr)
1383 return 0; /* parameter not stored */
1384
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001385 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386 return 1;
1387}
1388
1389/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1390 * it up into this table. Returns the server ID associated with the key if the
1391 * key is present in the table, otherwise zero, so that comparisons can be
1392 * easily performed. If the inspected parameter is not stored in the table,
1393 * <not found> is returned.
1394 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001395static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001396{
1397 struct stktable *t;
1398 struct stktable_key *key;
1399 struct stksess *ts;
1400 void *ptr;
1401
1402 t = &arg_p[0].data.prx->table;
1403
1404 key = smp_to_stkey(smp, t);
1405 if (!key)
1406 return 0;
1407
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001408 ts = stktable_lookup_key(t, key);
1409
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001410 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001411 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001412 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001413
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001414 if (!ts) /* key not present */
1415 return 1;
1416
1417 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
1418 if (!ptr)
1419 return 0; /* parameter not stored */
1420
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001421 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001422 return 1;
1423}
1424
1425/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1426 * it up into this table. Returns the cumulated number of sessions for the
1427 * key if the key is present in the table, otherwise zero, so that comparisons
1428 * can be easily performed. If the inspected parameter is not stored in the
1429 * table, <not found> is returned.
1430 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001431static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001432{
1433 struct stktable *t;
1434 struct stktable_key *key;
1435 struct stksess *ts;
1436 void *ptr;
1437
1438 t = &arg_p[0].data.prx->table;
1439
1440 key = smp_to_stkey(smp, t);
1441 if (!key)
1442 return 0;
1443
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001444 ts = stktable_lookup_key(t, key);
1445
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001446 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001447 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001448 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001449
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001450 if (!ts) /* key not present */
1451 return 1;
1452
1453 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
1454 if (!ptr)
1455 return 0; /* parameter not stored */
1456
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001457 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001458 return 1;
1459}
1460
1461/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1462 * it up into this table. Returns the session rate the key if the key is
1463 * present in the table, otherwise zero, so that comparisons can be easily
1464 * performed. If the inspected parameter is not stored in the table, <not found>
1465 * is returned.
1466 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001467static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001468{
1469 struct stktable *t;
1470 struct stktable_key *key;
1471 struct stksess *ts;
1472 void *ptr;
1473
1474 t = &arg_p[0].data.prx->table;
1475
1476 key = smp_to_stkey(smp, t);
1477 if (!key)
1478 return 0;
1479
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001480 ts = stktable_lookup_key(t, key);
1481
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001482 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001483 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001484 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001485
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001486 if (!ts) /* key not present */
1487 return 1;
1488
1489 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
1490 if (!ptr)
1491 return 0; /* parameter not stored */
1492
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001493 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001494 t->data_arg[STKTABLE_DT_SESS_RATE].u);
1495 return 1;
1496}
1497
1498/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1499 * it up into this table. Returns the amount of concurrent connections tracking
1500 * the same key if the key is present in the table, otherwise zero, so that
1501 * comparisons can be easily performed. If the inspected parameter is not
1502 * stored in the table, <not found> is returned.
1503 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001504static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001505{
1506 struct stktable *t;
1507 struct stktable_key *key;
1508 struct stksess *ts;
1509
1510 t = &arg_p[0].data.prx->table;
1511
1512 key = smp_to_stkey(smp, t);
1513 if (!key)
1514 return 0;
1515
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001516 ts = stktable_lookup_key(t, key);
1517
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001518 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001519 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001520 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001521
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001522 if (ts)
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001523 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001524
1525 return 1;
1526}
1527
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001528/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001529static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001530 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001531{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001532 struct stksess *ts;
1533 struct stkctr *stkctr;
1534
1535 /* Extract the stksess, return OK if no stksess available. */
1536 if (s)
1537 stkctr = &s->stkctr[rule->arg.gpc.sc];
1538 else
1539 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001540
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001541 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001542 if (ts) {
1543 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001544
Willy Tarreau79c1e912016-01-25 14:54:45 +01001545 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1546 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001547 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1548 if (ptr1 || ptr2) {
1549 RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1550
1551 if (ptr1)
1552 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001553 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001554
Emeric Brun819fc6f2017-06-13 19:37:32 +02001555 if (ptr2)
1556 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001557
Emeric Brun819fc6f2017-06-13 19:37:32 +02001558 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1559
1560 /* If data was modified, we need to touch to re-schedule sync */
1561 stktable_touch_local(stkctr->table, ts, 0);
1562 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001563 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001564 return ACT_RET_CONT;
1565}
1566
1567/* This function is a common parser for using variables. It understands
1568 * the formats:
1569 *
1570 * sc-inc-gpc0(<stick-table ID>)
1571 *
1572 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1573 * it returns 1 and the variable <expr> is filled with the pointer to the
1574 * expression to execute.
1575 */
1576static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1577 struct act_rule *rule, char **err)
1578{
1579 const char *cmd_name = args[*arg-1];
1580 char *error;
1581
1582 cmd_name += strlen("sc-inc-gpc0");
1583 if (*cmd_name == '\0') {
1584 /* default stick table id. */
1585 rule->arg.gpc.sc = 0;
1586 } else {
1587 /* parse the stick table id. */
1588 if (*cmd_name != '(') {
1589 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1590 return ACT_RET_PRS_ERR;
1591 }
1592 cmd_name++; /* jump the '(' */
1593 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1594 if (*error != ')') {
1595 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1596 return ACT_RET_PRS_ERR;
1597 }
1598
1599 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1600 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1601 ACT_ACTION_TRK_SCMAX-1);
1602 return ACT_RET_PRS_ERR;
1603 }
1604 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001605 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001606 rule->action_ptr = action_inc_gpc0;
1607 return ACT_RET_PRS_OK;
1608}
1609
1610/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001611static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001612 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001613{
1614 void *ptr;
1615 struct stksess *ts;
1616 struct stkctr *stkctr;
1617
1618 /* Extract the stksess, return OK if no stksess available. */
1619 if (s)
1620 stkctr = &s->stkctr[rule->arg.gpt.sc];
1621 else
1622 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001623
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001624 ts = stkctr_entry(stkctr);
1625 if (!ts)
1626 return ACT_RET_CONT;
1627
1628 /* Store the sample in the required sc, and ignore errors. */
1629 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001630 if (ptr) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02001631 RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1632
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001633 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001634
1635 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1636
1637 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001638 }
1639
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001640 return ACT_RET_CONT;
1641}
1642
1643/* This function is a common parser for using variables. It understands
1644 * the format:
1645 *
1646 * set-gpt0(<stick-table ID>) <expression>
1647 *
1648 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1649 * it returns 1 and the variable <expr> is filled with the pointer to the
1650 * expression to execute.
1651 */
1652static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1653 struct act_rule *rule, char **err)
1654
1655
1656{
1657 const char *cmd_name = args[*arg-1];
1658 char *error;
1659
1660 cmd_name += strlen("sc-set-gpt0");
1661 if (*cmd_name == '\0') {
1662 /* default stick table id. */
1663 rule->arg.gpt.sc = 0;
1664 } else {
1665 /* parse the stick table id. */
1666 if (*cmd_name != '(') {
1667 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1668 return ACT_RET_PRS_ERR;
1669 }
1670 cmd_name++; /* jump the '(' */
1671 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1672 if (*error != ')') {
1673 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1674 return ACT_RET_PRS_ERR;
1675 }
1676
1677 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1678 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1679 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1680 return ACT_RET_PRS_ERR;
1681 }
1682 }
1683
1684 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1685 if (*error != '\0') {
1686 memprintf(err, "invalid integer value '%s'", args[*arg]);
1687 return ACT_RET_PRS_ERR;
1688 }
1689 (*arg)++;
1690
Thierry FOURNIER42148732015-09-02 17:17:33 +02001691 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001692 rule->action_ptr = action_set_gpt0;
1693
1694 return ACT_RET_PRS_OK;
1695}
1696
Willy Tarreau7d562212016-11-25 16:10:05 +01001697/* set temp integer to the number of used entries in the table pointed to by expr.
1698 * Accepts exactly 1 argument of type table.
1699 */
1700static int
1701smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1702{
1703 smp->flags = SMP_F_VOL_TEST;
1704 smp->data.type = SMP_T_SINT;
1705 smp->data.u.sint = args->data.prx->table.current;
1706 return 1;
1707}
1708
1709/* set temp integer to the number of free entries in the table pointed to by expr.
1710 * Accepts exactly 1 argument of type table.
1711 */
1712static int
1713smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1714{
1715 struct proxy *px;
1716
1717 px = args->data.prx;
1718 smp->flags = SMP_F_VOL_TEST;
1719 smp->data.type = SMP_T_SINT;
1720 smp->data.u.sint = px->table.size - px->table.current;
1721 return 1;
1722}
1723
1724/* Returns a pointer to a stkctr depending on the fetch keyword name.
1725 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1726 * sc[0-9]_* will return a pointer to the respective field in the
1727 * stream <l4>. sc_* requires an UINT argument specifying the stick
1728 * counter number. src_* will fill a locally allocated structure with
1729 * the table and entry corresponding to what is specified with src_*.
1730 * NULL may be returned if the designated stkctr is not tracked. For
1731 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1732 * passed. When present, the currently tracked key is then looked up
1733 * in the specified table instead of the current table. The purpose is
1734 * to be able to convery multiple values per key (eg: have gpc0 from
1735 * multiple tables). <strm> is allowed to be NULL, in which case only
1736 * the session will be consulted.
1737 */
1738struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001739smp_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 +01001740{
Willy Tarreau7d562212016-11-25 16:10:05 +01001741 struct stkctr *stkptr;
1742 struct stksess *stksess;
1743 unsigned int num = kw[2] - '0';
1744 int arg = 0;
1745
1746 if (num == '_' - '0') {
1747 /* sc_* variant, args[0] = ctr# (mandatory) */
1748 num = args[arg++].data.sint;
1749 if (num >= MAX_SESS_STKCTR)
1750 return NULL;
1751 }
1752 else if (num > 9) { /* src_* variant, args[0] = table */
1753 struct stktable_key *key;
1754 struct connection *conn = objt_conn(sess->origin);
1755 struct sample smp;
1756
1757 if (!conn)
1758 return NULL;
1759
1760 /* Fetch source adress in a sample. */
1761 smp.px = NULL;
1762 smp.sess = sess;
1763 smp.strm = strm;
1764 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1765 return NULL;
1766
1767 /* Converts into key. */
1768 key = smp_to_stkey(&smp, &args->data.prx->table);
1769 if (!key)
1770 return NULL;
1771
Emeric Brun819fc6f2017-06-13 19:37:32 +02001772 stkctr->table = &args->data.prx->table;
1773 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1774 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001775 }
1776
1777 /* Here, <num> contains the counter number from 0 to 9 for
1778 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1779 * args[arg] is the first optional argument. We first lookup the
1780 * ctr form the stream, then from the session if it was not there.
1781 */
1782
1783 if (strm)
1784 stkptr = &strm->stkctr[num];
1785 if (!strm || !stkctr_entry(stkptr)) {
1786 stkptr = &sess->stkctr[num];
1787 if (!stkctr_entry(stkptr))
1788 return NULL;
1789 }
1790
1791 stksess = stkctr_entry(stkptr);
1792 if (!stksess)
1793 return NULL;
1794
1795 if (unlikely(args[arg].type == ARGT_TAB)) {
1796 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001797 stkctr->table = &args[arg].data.prx->table;
1798 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1799 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001800 }
1801 return stkptr;
1802}
1803
1804/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1805 * the entry if it doesn't exist yet. This is needed for a few fetch
1806 * functions which need to create an entry, such as src_inc_gpc* and
1807 * src_clr_gpc*.
1808 */
1809struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001810smp_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 +01001811{
Willy Tarreau7d562212016-11-25 16:10:05 +01001812 struct stktable_key *key;
1813 struct connection *conn = objt_conn(sess->origin);
1814 struct sample smp;
1815
1816 if (strncmp(kw, "src_", 4) != 0)
1817 return NULL;
1818
1819 if (!conn)
1820 return NULL;
1821
1822 /* Fetch source adress in a sample. */
1823 smp.px = NULL;
1824 smp.sess = sess;
1825 smp.strm = strm;
1826 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1827 return NULL;
1828
1829 /* Converts into key. */
1830 key = smp_to_stkey(&smp, &args->data.prx->table);
1831 if (!key)
1832 return NULL;
1833
Emeric Brun819fc6f2017-06-13 19:37:32 +02001834 stkctr->table = &args->data.prx->table;
1835 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
1836 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001837}
1838
1839/* set return a boolean indicating if the requested stream counter is
1840 * currently being tracked or not.
1841 * Supports being called as "sc[0-9]_tracked" only.
1842 */
1843static int
1844smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
1845{
Emeric Brun819fc6f2017-06-13 19:37:32 +02001846 struct stkctr tmpstkctr;
1847 struct stkctr *stkctr;
1848
Willy Tarreau7d562212016-11-25 16:10:05 +01001849 smp->flags = SMP_F_VOL_TEST;
1850 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001851 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
1852 smp->data.u.sint = !!stkctr;
1853
1854 /* release the ref count */
1855 if ((stkctr == &tmpstkctr) && stkctr_entry(stkctr))
1856 stktable_release(stkctr->table, stkctr_entry(stkctr));
1857
Willy Tarreau7d562212016-11-25 16:10:05 +01001858 return 1;
1859}
1860
1861/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
1862 * frontend counters or from the src.
1863 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
1864 * zero is returned if the key is new.
1865 */
1866static int
1867smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
1868{
Emeric Brun819fc6f2017-06-13 19:37:32 +02001869 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001870 struct stkctr *stkctr;
1871
Emeric Brun819fc6f2017-06-13 19:37:32 +02001872 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01001873 if (!stkctr)
1874 return 0;
1875
1876 smp->flags = SMP_F_VOL_TEST;
1877 smp->data.type = SMP_T_SINT;
1878 smp->data.u.sint = 0;
1879
Emeric Brun819fc6f2017-06-13 19:37:32 +02001880 if (stkctr_entry(stkctr)) {
1881 void *ptr;
1882
1883 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
1884 if (!ptr) {
1885 if (stkctr == &tmpstkctr)
1886 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01001887 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001888 }
1889
1890 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1891
Willy Tarreau7d562212016-11-25 16:10:05 +01001892 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001893
1894 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1895
1896 if (stkctr == &tmpstkctr)
1897 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01001898 }
1899 return 1;
1900}
1901
1902/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
1903 * frontend counters or from the src.
1904 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
1905 * zero is returned if the key is new.
1906 */
1907static int
1908smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
1909{
Emeric Brun819fc6f2017-06-13 19:37:32 +02001910 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001911 struct stkctr *stkctr;
1912
Emeric Brun819fc6f2017-06-13 19:37:32 +02001913 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01001914 if (!stkctr)
1915 return 0;
1916
1917 smp->flags = SMP_F_VOL_TEST;
1918 smp->data.type = SMP_T_SINT;
1919 smp->data.u.sint = 0;
1920
1921 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02001922 void *ptr;
1923
1924 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
1925 if (!ptr) {
1926 if (stkctr == &tmpstkctr)
1927 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01001928 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001929 }
1930
1931 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1932
Willy Tarreau7d562212016-11-25 16:10:05 +01001933 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001934
1935 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1936
1937 if (stkctr == &tmpstkctr)
1938 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01001939 }
1940 return 1;
1941}
1942
1943/* set <smp> to the General Purpose Counter 0's event rate from the stream's
1944 * tracked frontend counters or from the src.
1945 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
1946 * Value zero is returned if the key is new.
1947 */
1948static int
1949smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
1950{
Emeric Brun819fc6f2017-06-13 19:37:32 +02001951 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001952 struct stkctr *stkctr;
1953
Emeric Brun819fc6f2017-06-13 19:37:32 +02001954 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01001955 if (!stkctr)
1956 return 0;
1957
1958 smp->flags = SMP_F_VOL_TEST;
1959 smp->data.type = SMP_T_SINT;
1960 smp->data.u.sint = 0;
1961 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02001962 void *ptr;
1963
1964 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
1965 if (!ptr) {
1966 if (stkctr == &tmpstkctr)
1967 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01001968 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001969 }
1970
1971 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1972
Willy Tarreau7d562212016-11-25 16:10:05 +01001973 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1974 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001975
1976 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1977
1978 if (stkctr == &tmpstkctr)
1979 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01001980 }
1981 return 1;
1982}
1983
1984/* Increment the General Purpose Counter 0 value from the stream's tracked
1985 * frontend counters and return it into temp integer.
1986 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
1987 */
1988static int
1989smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
1990{
Emeric Brun819fc6f2017-06-13 19:37:32 +02001991 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001992 struct stkctr *stkctr;
1993
Emeric Brun819fc6f2017-06-13 19:37:32 +02001994 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01001995 if (!stkctr)
1996 return 0;
1997
1998 smp->flags = SMP_F_VOL_TEST;
1999 smp->data.type = SMP_T_SINT;
2000 smp->data.u.sint = 0;
2001
Emeric Brun819fc6f2017-06-13 19:37:32 +02002002 if (!stkctr_entry(stkctr))
2003 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002004
2005 if (stkctr && stkctr_entry(stkctr)) {
2006 void *ptr1,*ptr2;
2007
Emeric Brun819fc6f2017-06-13 19:37:32 +02002008
Willy Tarreau7d562212016-11-25 16:10:05 +01002009 /* First, update gpc0_rate if it's tracked. Second, update its
2010 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2011 */
2012 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002013 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002014 if (ptr1 || ptr2) {
2015 RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002016
Emeric Brun819fc6f2017-06-13 19:37:32 +02002017 if (ptr1) {
2018 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2019 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2020 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2021 }
2022
2023 if (ptr2)
2024 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2025
2026 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2027
2028 /* If data was modified, we need to touch to re-schedule sync */
2029 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2030 }
2031 else if (stkctr == &tmpstkctr)
2032 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002033 }
2034 return 1;
2035}
2036
2037/* Clear the General Purpose Counter 0 value from the stream's tracked
2038 * frontend counters and return its previous value into temp integer.
2039 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2040 */
2041static int
2042smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2043{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002044 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002045 struct stkctr *stkctr;
2046
Emeric Brun819fc6f2017-06-13 19:37:32 +02002047 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002048 if (!stkctr)
2049 return 0;
2050
2051 smp->flags = SMP_F_VOL_TEST;
2052 smp->data.type = SMP_T_SINT;
2053 smp->data.u.sint = 0;
2054
Emeric Brun819fc6f2017-06-13 19:37:32 +02002055 if (!stkctr_entry(stkctr))
2056 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002057
Emeric Brun819fc6f2017-06-13 19:37:32 +02002058 if (stkctr && stkctr_entry(stkctr)) {
2059 void *ptr;
2060
2061 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2062 if (!ptr) {
2063 if (stkctr == &tmpstkctr)
2064 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002065 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002066 }
2067
2068 RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2069
Willy Tarreau7d562212016-11-25 16:10:05 +01002070 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2071 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002072
2073 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2074
Willy Tarreau7d562212016-11-25 16:10:05 +01002075 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002076 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002077 }
2078 return 1;
2079}
2080
2081/* set <smp> to the cumulated number of connections from the stream's tracked
2082 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2083 * "src_conn_cnt" only.
2084 */
2085static int
2086smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2087{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002088 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002089 struct stkctr *stkctr;
2090
Emeric Brun819fc6f2017-06-13 19:37:32 +02002091 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002092 if (!stkctr)
2093 return 0;
2094
2095 smp->flags = SMP_F_VOL_TEST;
2096 smp->data.type = SMP_T_SINT;
2097 smp->data.u.sint = 0;
2098 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002099 void *ptr;
2100
2101 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2102 if (!ptr) {
2103 if (stkctr == &tmpstkctr)
2104 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002105 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002106 }
2107
2108 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2109
Willy Tarreau7d562212016-11-25 16:10:05 +01002110 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002111
2112 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2113
2114 if (stkctr == &tmpstkctr)
2115 stktable_release(stkctr->table, stkctr_entry(stkctr));
2116
2117
Willy Tarreau7d562212016-11-25 16:10:05 +01002118 }
2119 return 1;
2120}
2121
2122/* set <smp> to the connection rate from the stream's tracked frontend
2123 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2124 * only.
2125 */
2126static int
2127smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2128{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002129 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002130 struct stkctr *stkctr;
2131
Emeric Brun819fc6f2017-06-13 19:37:32 +02002132 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002133 if (!stkctr)
2134 return 0;
2135
2136 smp->flags = SMP_F_VOL_TEST;
2137 smp->data.type = SMP_T_SINT;
2138 smp->data.u.sint = 0;
2139 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002140 void *ptr;
2141
2142 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2143 if (!ptr) {
2144 if (stkctr == &tmpstkctr)
2145 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002146 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002147 }
2148
2149 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2150
Willy Tarreau7d562212016-11-25 16:10:05 +01002151 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2152 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002153
2154 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2155
2156 if (stkctr == &tmpstkctr)
2157 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002158 }
2159 return 1;
2160}
2161
2162/* set temp integer to the number of connections from the stream's source address
2163 * in the table pointed to by expr, after updating it.
2164 * Accepts exactly 1 argument of type table.
2165 */
2166static int
2167smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2168{
2169 struct connection *conn = objt_conn(smp->sess->origin);
2170 struct stksess *ts;
2171 struct stktable_key *key;
2172 void *ptr;
2173 struct proxy *px;
2174
2175 if (!conn)
2176 return 0;
2177
2178 /* Fetch source adress in a sample. */
2179 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2180 return 0;
2181
2182 /* Converts into key. */
2183 key = smp_to_stkey(smp, &args->data.prx->table);
2184 if (!key)
2185 return 0;
2186
2187 px = args->data.prx;
2188
Emeric Brun819fc6f2017-06-13 19:37:32 +02002189 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002190 /* entry does not exist and could not be created */
2191 return 0;
2192
2193 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002194 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002195 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002196 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002197
2198 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002199
2200 RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2201
Willy Tarreau7d562212016-11-25 16:10:05 +01002202 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002203
2204 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2205
Willy Tarreau7d562212016-11-25 16:10:05 +01002206 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002207
2208 stktable_touch_local(&px->table, ts, 1);
2209
2210 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002211 return 1;
2212}
2213
2214/* set <smp> to the number of concurrent connections from the stream's tracked
2215 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2216 * "src_conn_cur" only.
2217 */
2218static int
2219smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2220{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002221 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002222 struct stkctr *stkctr;
2223
Emeric Brun819fc6f2017-06-13 19:37:32 +02002224 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002225 if (!stkctr)
2226 return 0;
2227
2228 smp->flags = SMP_F_VOL_TEST;
2229 smp->data.type = SMP_T_SINT;
2230 smp->data.u.sint = 0;
2231 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002232 void *ptr;
2233
2234 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2235 if (!ptr) {
2236 if (stkctr == &tmpstkctr)
2237 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002238 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002239 }
2240
2241 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2242
Willy Tarreau7d562212016-11-25 16:10:05 +01002243 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002244
2245 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2246
2247 if (stkctr == &tmpstkctr)
2248 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002249 }
2250 return 1;
2251}
2252
2253/* set <smp> to the cumulated number of streams from the stream's tracked
2254 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2255 * "src_sess_cnt" only.
2256 */
2257static int
2258smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2259{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002260 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002261 struct stkctr *stkctr;
2262
Emeric Brun819fc6f2017-06-13 19:37:32 +02002263 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002264 if (!stkctr)
2265 return 0;
2266
2267 smp->flags = SMP_F_VOL_TEST;
2268 smp->data.type = SMP_T_SINT;
2269 smp->data.u.sint = 0;
2270 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002271 void *ptr;
2272
2273 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2274 if (!ptr) {
2275 if (stkctr == &tmpstkctr)
2276 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002277 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002278 }
2279
2280 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2281
Willy Tarreau7d562212016-11-25 16:10:05 +01002282 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002283
2284 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2285
2286 if (stkctr == &tmpstkctr)
2287 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002288 }
2289 return 1;
2290}
2291
2292/* set <smp> to the stream rate from the stream's tracked frontend counters.
2293 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2294 */
2295static int
2296smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2297{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002298 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002299 struct stkctr *stkctr;
2300
Emeric Brun819fc6f2017-06-13 19:37:32 +02002301 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002302 if (!stkctr)
2303 return 0;
2304
2305 smp->flags = SMP_F_VOL_TEST;
2306 smp->data.type = SMP_T_SINT;
2307 smp->data.u.sint = 0;
2308 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002309 void *ptr;
2310
2311 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2312 if (!ptr) {
2313 if (stkctr == &tmpstkctr)
2314 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002315 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002316 }
2317
2318 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2319
Willy Tarreau7d562212016-11-25 16:10:05 +01002320 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2321 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002322
2323 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2324
2325 if (stkctr == &tmpstkctr)
2326 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002327 }
2328 return 1;
2329}
2330
2331/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2332 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2333 * "src_http_req_cnt" only.
2334 */
2335static int
2336smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2337{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002338 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002339 struct stkctr *stkctr;
2340
Emeric Brun819fc6f2017-06-13 19:37:32 +02002341 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002342 if (!stkctr)
2343 return 0;
2344
2345 smp->flags = SMP_F_VOL_TEST;
2346 smp->data.type = SMP_T_SINT;
2347 smp->data.u.sint = 0;
2348 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002349 void *ptr;
2350
2351 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2352 if (!ptr) {
2353 if (stkctr == &tmpstkctr)
2354 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002355 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002356 }
2357
2358 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2359
Willy Tarreau7d562212016-11-25 16:10:05 +01002360 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002361
2362 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2363
2364 if (stkctr == &tmpstkctr)
2365 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002366 }
2367 return 1;
2368}
2369
2370/* set <smp> to the HTTP request rate from the stream's tracked frontend
2371 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2372 * "src_http_req_rate" only.
2373 */
2374static int
2375smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2376{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002377 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002378 struct stkctr *stkctr;
2379
Emeric Brun819fc6f2017-06-13 19:37:32 +02002380 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002381 if (!stkctr)
2382 return 0;
2383
2384 smp->flags = SMP_F_VOL_TEST;
2385 smp->data.type = SMP_T_SINT;
2386 smp->data.u.sint = 0;
2387 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002388 void *ptr;
2389
2390 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2391 if (!ptr) {
2392 if (stkctr == &tmpstkctr)
2393 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002394 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002395 }
2396
2397 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2398
Willy Tarreau7d562212016-11-25 16:10:05 +01002399 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2400 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002401
2402 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2403
2404 if (stkctr == &tmpstkctr)
2405 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002406 }
2407 return 1;
2408}
2409
2410/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2411 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2412 * "src_http_err_cnt" only.
2413 */
2414static int
2415smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2416{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002417 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002418 struct stkctr *stkctr;
2419
Emeric Brun819fc6f2017-06-13 19:37:32 +02002420 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002421 if (!stkctr)
2422 return 0;
2423
2424 smp->flags = SMP_F_VOL_TEST;
2425 smp->data.type = SMP_T_SINT;
2426 smp->data.u.sint = 0;
2427 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002428 void *ptr;
2429
2430 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2431 if (!ptr) {
2432 if (stkctr == &tmpstkctr)
2433 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002434 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002435 }
2436
2437 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2438
Willy Tarreau7d562212016-11-25 16:10:05 +01002439 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002440
2441 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2442
2443 if (stkctr == &tmpstkctr)
2444 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002445 }
2446 return 1;
2447}
2448
2449/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2450 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2451 * "src_http_err_rate" only.
2452 */
2453static int
2454smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2455{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002456 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002457 struct stkctr *stkctr;
2458
Emeric Brun819fc6f2017-06-13 19:37:32 +02002459 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002460 if (!stkctr)
2461 return 0;
2462
2463 smp->flags = SMP_F_VOL_TEST;
2464 smp->data.type = SMP_T_SINT;
2465 smp->data.u.sint = 0;
2466 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002467 void *ptr;
2468
2469 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2470 if (!ptr) {
2471 if (stkctr == &tmpstkctr)
2472 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002473 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002474 }
2475
2476 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2477
Willy Tarreau7d562212016-11-25 16:10:05 +01002478 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2479 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002480
2481 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2482
2483 if (stkctr == &tmpstkctr)
2484 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002485 }
2486 return 1;
2487}
2488
2489/* set <smp> to the number of kbytes received from clients, as found in the
2490 * stream's tracked frontend counters. Supports being called as
2491 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2492 */
2493static int
2494smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2495{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002496 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002497 struct stkctr *stkctr;
2498
Emeric Brun819fc6f2017-06-13 19:37:32 +02002499 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002500 if (!stkctr)
2501 return 0;
2502
2503 smp->flags = SMP_F_VOL_TEST;
2504 smp->data.type = SMP_T_SINT;
2505 smp->data.u.sint = 0;
2506 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002507 void *ptr;
2508
2509 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2510 if (!ptr) {
2511 if (stkctr == &tmpstkctr)
2512 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002513 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002514 }
2515
2516 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2517
Willy Tarreau7d562212016-11-25 16:10:05 +01002518 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002519
2520 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2521
2522 if (stkctr == &tmpstkctr)
2523 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002524 }
2525 return 1;
2526}
2527
2528/* set <smp> to the data rate received from clients in bytes/s, as found
2529 * in the stream's tracked frontend counters. Supports being called as
2530 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2531 */
2532static int
2533smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2534{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002535 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002536 struct stkctr *stkctr;
2537
Emeric Brun819fc6f2017-06-13 19:37:32 +02002538 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002539 if (!stkctr)
2540 return 0;
2541
2542 smp->flags = SMP_F_VOL_TEST;
2543 smp->data.type = SMP_T_SINT;
2544 smp->data.u.sint = 0;
2545 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002546 void *ptr;
2547
2548 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2549 if (!ptr) {
2550 if (stkctr == &tmpstkctr)
2551 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002552 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002553 }
2554
2555 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2556
Willy Tarreau7d562212016-11-25 16:10:05 +01002557 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2558 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002559
2560 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2561
2562 if (stkctr == &tmpstkctr)
2563 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002564 }
2565 return 1;
2566}
2567
2568/* set <smp> to the number of kbytes sent to clients, as found in the
2569 * stream's tracked frontend counters. Supports being called as
2570 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2571 */
2572static int
2573smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2574{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002575 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002576 struct stkctr *stkctr;
2577
Emeric Brun819fc6f2017-06-13 19:37:32 +02002578 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002579 if (!stkctr)
2580 return 0;
2581
2582 smp->flags = SMP_F_VOL_TEST;
2583 smp->data.type = SMP_T_SINT;
2584 smp->data.u.sint = 0;
2585 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002586 void *ptr;
2587
2588 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2589 if (!ptr) {
2590 if (stkctr == &tmpstkctr)
2591 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002592 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002593 }
2594
2595 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2596
Willy Tarreau7d562212016-11-25 16:10:05 +01002597 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002598
2599 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2600
2601 if (stkctr == &tmpstkctr)
2602 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002603 }
2604 return 1;
2605}
2606
2607/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2608 * stream's tracked frontend counters. Supports being called as
2609 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2610 */
2611static int
2612smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2613{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002614 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002615 struct stkctr *stkctr;
2616
Emeric Brun819fc6f2017-06-13 19:37:32 +02002617 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002618 if (!stkctr)
2619 return 0;
2620
2621 smp->flags = SMP_F_VOL_TEST;
2622 smp->data.type = SMP_T_SINT;
2623 smp->data.u.sint = 0;
2624 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002625 void *ptr;
2626
2627 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2628 if (!ptr) {
2629 if (stkctr == &tmpstkctr)
2630 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002631 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002632 }
2633
2634 RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2635
Willy Tarreau7d562212016-11-25 16:10:05 +01002636 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2637 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002638
2639 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2640
2641 if (stkctr == &tmpstkctr)
2642 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002643 }
2644 return 1;
2645}
2646
2647/* set <smp> to the number of active trackers on the SC entry in the stream's
2648 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2649 */
2650static int
2651smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2652{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002653 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002654 struct stkctr *stkctr;
2655
Emeric Brun819fc6f2017-06-13 19:37:32 +02002656 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002657 if (!stkctr)
2658 return 0;
2659
2660 smp->flags = SMP_F_VOL_TEST;
2661 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662 if (stkctr == &tmpstkctr) {
2663 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
2664 stktable_release(stkctr->table, stkctr_entry(stkctr));
2665 }
2666 else {
2667 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
2668 }
2669
Willy Tarreau7d562212016-11-25 16:10:05 +01002670 return 1;
2671}
2672
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002673
2674/* The functions below are used to manipulate table contents from the CLI.
2675 * There are 3 main actions, "clear", "set" and "show". The code is shared
2676 * between all actions, and the action is encoded in the void *private in
2677 * the appctx as well as in the keyword registration, among one of the
2678 * following values.
2679 */
2680
2681enum {
2682 STK_CLI_ACT_CLR,
2683 STK_CLI_ACT_SET,
2684 STK_CLI_ACT_SHOW,
2685};
2686
2687/* Dump the status of a table to a stream interface's
2688 * read buffer. It returns 0 if the output buffer is full
2689 * and needs to be called again, otherwise non-zero.
2690 */
2691static int table_dump_head_to_buffer(struct chunk *msg, struct stream_interface *si,
2692 struct proxy *proxy, struct proxy *target)
2693{
2694 struct stream *s = si_strm(si);
2695
2696 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
2697 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
2698
2699 /* any other information should be dumped here */
2700
William Lallemand07a62f72017-05-24 00:57:40 +02002701 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002702 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
2703
Willy Tarreau06d80a92017-10-19 14:32:15 +02002704 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002705 si_applet_cant_put(si);
2706 return 0;
2707 }
2708
2709 return 1;
2710}
2711
2712/* Dump a table entry to a stream interface's
2713 * read buffer. It returns 0 if the output buffer is full
2714 * and needs to be called again, otherwise non-zero.
2715 */
2716static int table_dump_entry_to_buffer(struct chunk *msg, struct stream_interface *si,
2717 struct proxy *proxy, struct stksess *entry)
2718{
2719 int dt;
2720
2721 chunk_appendf(msg, "%p:", entry);
2722
2723 if (proxy->table.type == SMP_T_IPV4) {
2724 char addr[INET_ADDRSTRLEN];
2725 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
2726 chunk_appendf(msg, " key=%s", addr);
2727 }
2728 else if (proxy->table.type == SMP_T_IPV6) {
2729 char addr[INET6_ADDRSTRLEN];
2730 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
2731 chunk_appendf(msg, " key=%s", addr);
2732 }
2733 else if (proxy->table.type == SMP_T_SINT) {
2734 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
2735 }
2736 else if (proxy->table.type == SMP_T_STR) {
2737 chunk_appendf(msg, " key=");
2738 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
2739 }
2740 else {
2741 chunk_appendf(msg, " key=");
2742 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
2743 }
2744
2745 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
2746
2747 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
2748 void *ptr;
2749
2750 if (proxy->table.data_ofs[dt] == 0)
2751 continue;
2752 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
2753 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
2754 else
2755 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
2756
2757 ptr = stktable_data_ptr(&proxy->table, entry, dt);
2758 switch (stktable_data_types[dt].std_type) {
2759 case STD_T_SINT:
2760 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
2761 break;
2762 case STD_T_UINT:
2763 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
2764 break;
2765 case STD_T_ULL:
2766 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
2767 break;
2768 case STD_T_FRQP:
2769 chunk_appendf(msg, "%d",
2770 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
2771 proxy->table.data_arg[dt].u));
2772 break;
2773 }
2774 }
2775 chunk_appendf(msg, "\n");
2776
Willy Tarreau06d80a92017-10-19 14:32:15 +02002777 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002778 si_applet_cant_put(si);
2779 return 0;
2780 }
2781
2782 return 1;
2783}
2784
2785
2786/* Processes a single table entry matching a specific key passed in argument.
2787 * returns 0 if wants to be called again, 1 if has ended processing.
2788 */
2789static int table_process_entry_per_key(struct appctx *appctx, char **args)
2790{
2791 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002792 struct proxy *px = appctx->ctx.table.target;
2793 struct stksess *ts;
2794 uint32_t uint32_key;
2795 unsigned char ip6_key[sizeof(struct in6_addr)];
2796 long long value;
2797 int data_type;
2798 int cur_arg;
2799 void *ptr;
2800 struct freq_ctr_period *frqp;
2801
2802 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002803 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002804 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002805 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002806 return 1;
2807 }
2808
2809 switch (px->table.type) {
2810 case SMP_T_IPV4:
2811 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02002812 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002813 break;
2814 case SMP_T_IPV6:
2815 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02002816 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002817 break;
2818 case SMP_T_SINT:
2819 {
2820 char *endptr;
2821 unsigned long val;
2822 errno = 0;
2823 val = strtoul(args[4], &endptr, 10);
2824 if ((errno == ERANGE && val == ULONG_MAX) ||
2825 (errno != 0 && val == 0) || endptr == args[4] ||
2826 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002827 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002828 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002829 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002830 return 1;
2831 }
2832 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02002833 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002834 break;
2835 }
2836 break;
2837 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02002838 static_table_key.key = args[4];
2839 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002840 break;
2841 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01002842 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002843 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002844 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002845 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
2846 break;
2847 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002848 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002849 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
2850 break;
2851 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002852 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002853 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
2854 break;
2855 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002856 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002857 appctx->ctx.cli.msg = "Unknown action\n";
2858 break;
2859 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002860 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002861 return 1;
2862 }
2863
2864 /* check permissions */
2865 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
2866 return 1;
2867
Willy Tarreaua24bc782016-12-14 15:50:35 +01002868 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002869 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02002870 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002871 if (!ts)
2872 return 1;
2873 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002874 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
2875 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002876 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002877 }
2878 RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
2879 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
2880 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
2881 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002882 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002883 }
2884 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
2885 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002886 break;
2887
2888 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002890 if (!ts)
2891 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002892
2893 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002894 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002895 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002896 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002897 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002898 return 1;
2899 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02002900
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002901 break;
2902
2903 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02002904 ts = stktable_get_entry(&px->table, &static_table_key);
2905 if (!ts) {
2906 /* don't delete an entry which is currently referenced */
2907 appctx->ctx.cli.severity = LOG_ERR;
2908 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
2909 appctx->st0 = CLI_ST_PRINT;
2910 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002911 }
2912
Emeric Brun819fc6f2017-06-13 19:37:32 +02002913 RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002914 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
2915 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002916 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002917 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002918 appctx->st0 = CLI_ST_PRINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002919 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2920 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002921 return 1;
2922 }
2923
2924 data_type = stktable_get_data_type(args[cur_arg] + 5);
2925 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002926 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002927 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002928 appctx->st0 = CLI_ST_PRINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002929 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2930 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002931 return 1;
2932 }
2933
2934 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002935 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002936 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002937 appctx->st0 = CLI_ST_PRINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002938 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2939 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002940 return 1;
2941 }
2942
2943 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002944 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002945 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002946 appctx->st0 = CLI_ST_PRINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002947 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2948 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002949 return 1;
2950 }
2951
2952 ptr = stktable_data_ptr(&px->table, ts, data_type);
2953
2954 switch (stktable_data_types[data_type].std_type) {
2955 case STD_T_SINT:
2956 stktable_data_cast(ptr, std_t_sint) = value;
2957 break;
2958 case STD_T_UINT:
2959 stktable_data_cast(ptr, std_t_uint) = value;
2960 break;
2961 case STD_T_ULL:
2962 stktable_data_cast(ptr, std_t_ull) = value;
2963 break;
2964 case STD_T_FRQP:
2965 /* We set both the current and previous values. That way
2966 * the reported frequency is stable during all the period
2967 * then slowly fades out. This allows external tools to
2968 * push measures without having to update them too often.
2969 */
2970 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01002971 /* First bit is reserved for the freq_ctr_period lock
2972 Note: here we're still protected by the stksess lock
2973 so we don't need to update the update the freq_ctr_period
2974 using its internal lock */
2975 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002976 frqp->prev_ctr = 0;
2977 frqp->curr_ctr = value;
2978 break;
2979 }
2980 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981 RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2982 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002983 break;
2984
2985 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02002986 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002987 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002988 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01002989 break;
2990 }
2991 return 1;
2992}
2993
2994/* Prepares the appctx fields with the data-based filters from the command line.
2995 * Returns 0 if the dump can proceed, 1 if has ended processing.
2996 */
2997static int table_prepare_data_request(struct appctx *appctx, char **args)
2998{
Willy Tarreaua24bc782016-12-14 15:50:35 +01002999 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003000 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003001 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003002 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003003 return 1;
3004 }
3005
3006 /* condition on stored data value */
3007 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3008 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003009 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003010 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003011 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003012 return 1;
3013 }
3014
3015 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003016 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003017 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003018 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003019 return 1;
3020 }
3021
3022 appctx->ctx.table.data_op = get_std_op(args[4]);
3023 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003024 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003025 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003026 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003027 return 1;
3028 }
3029
3030 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003031 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003032 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003033 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003034 return 1;
3035 }
3036
3037 /* OK we're done, all the fields are set */
3038 return 0;
3039}
3040
3041/* returns 0 if wants to be called, 1 if has ended processing */
3042static int cli_parse_table_req(char **args, struct appctx *appctx, void *private)
3043{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003044 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003045 appctx->ctx.table.target = NULL;
3046 appctx->ctx.table.proxy = NULL;
3047 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003048 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003049
3050 if (*args[2]) {
3051 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3052 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003053 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003054 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003055 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003056 return 1;
3057 }
3058 }
3059 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003060 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003061 goto err_args;
3062 return 0;
3063 }
3064
3065 if (strcmp(args[3], "key") == 0)
3066 return table_process_entry_per_key(appctx, args);
3067 else if (strncmp(args[3], "data.", 5) == 0)
3068 return table_prepare_data_request(appctx, args);
3069 else if (*args[3])
3070 goto err_args;
3071
3072 return 0;
3073
3074err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003075 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003076 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003077 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003078 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3079 break;
3080 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003081 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003082 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3083 break;
3084 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003085 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003086 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3087 break;
3088 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003089 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003090 appctx->ctx.cli.msg = "Unknown action\n";
3091 break;
3092 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003093 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003094 return 1;
3095}
3096
3097/* This function is used to deal with table operations (dump or clear depending
3098 * on the action stored in appctx->private). It returns 0 if the output buffer is
3099 * full and it needs to be called again, otherwise non-zero.
3100 */
3101static int cli_io_handler_table(struct appctx *appctx)
3102{
3103 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003104 struct stream *s = si_strm(si);
3105 struct ebmb_node *eb;
3106 int dt;
3107 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003108 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003109
3110 /*
3111 * We have 3 possible states in appctx->st2 :
3112 * - STAT_ST_INIT : the first call
3113 * - STAT_ST_INFO : the proxy pointer points to the next table to
3114 * dump, the entry pointer is NULL ;
3115 * - STAT_ST_LIST : the proxy pointer points to the current table
3116 * and the entry pointer points to the next entry to be dumped,
3117 * and the refcount on the next entry is held ;
3118 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3119 * data though.
3120 */
3121
3122 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3123 /* in case of abort, remove any refcount we might have set on an entry */
3124 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003125 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003126 }
3127 return 1;
3128 }
3129
3130 chunk_reset(&trash);
3131
3132 while (appctx->st2 != STAT_ST_FIN) {
3133 switch (appctx->st2) {
3134 case STAT_ST_INIT:
3135 appctx->ctx.table.proxy = appctx->ctx.table.target;
3136 if (!appctx->ctx.table.proxy)
3137 appctx->ctx.table.proxy = proxy;
3138
3139 appctx->ctx.table.entry = NULL;
3140 appctx->st2 = STAT_ST_INFO;
3141 break;
3142
3143 case STAT_ST_INFO:
3144 if (!appctx->ctx.table.proxy ||
3145 (appctx->ctx.table.target &&
3146 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3147 appctx->st2 = STAT_ST_END;
3148 break;
3149 }
3150
3151 if (appctx->ctx.table.proxy->table.size) {
3152 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3153 return 0;
3154
3155 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003156 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003157 /* dump entries only if table explicitly requested */
Emeric Brun819fc6f2017-06-13 19:37:32 +02003158 SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003159 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3160 if (eb) {
3161 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3162 appctx->ctx.table.entry->ref_cnt++;
3163 appctx->st2 = STAT_ST_LIST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003164 SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003165 break;
3166 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003167 SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003168 }
3169 }
3170 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3171 break;
3172
3173 case STAT_ST_LIST:
3174 skip_entry = 0;
3175
Emeric Brun819fc6f2017-06-13 19:37:32 +02003176 RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
3177
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003178 if (appctx->ctx.table.data_type >= 0) {
3179 /* we're filtering on some data contents */
3180 void *ptr;
3181 long long data;
3182
Emeric Brun819fc6f2017-06-13 19:37:32 +02003183
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003184 dt = appctx->ctx.table.data_type;
3185 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3186 appctx->ctx.table.entry,
3187 dt);
3188
3189 data = 0;
3190 switch (stktable_data_types[dt].std_type) {
3191 case STD_T_SINT:
3192 data = stktable_data_cast(ptr, std_t_sint);
3193 break;
3194 case STD_T_UINT:
3195 data = stktable_data_cast(ptr, std_t_uint);
3196 break;
3197 case STD_T_ULL:
3198 data = stktable_data_cast(ptr, std_t_ull);
3199 break;
3200 case STD_T_FRQP:
3201 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3202 appctx->ctx.table.proxy->table.data_arg[dt].u);
3203 break;
3204 }
3205
3206 /* skip the entry if the data does not match the test and the value */
3207 if ((data < appctx->ctx.table.value &&
3208 (appctx->ctx.table.data_op == STD_OP_EQ ||
3209 appctx->ctx.table.data_op == STD_OP_GT ||
3210 appctx->ctx.table.data_op == STD_OP_GE)) ||
3211 (data == appctx->ctx.table.value &&
3212 (appctx->ctx.table.data_op == STD_OP_NE ||
3213 appctx->ctx.table.data_op == STD_OP_GT ||
3214 appctx->ctx.table.data_op == STD_OP_LT)) ||
3215 (data > appctx->ctx.table.value &&
3216 (appctx->ctx.table.data_op == STD_OP_EQ ||
3217 appctx->ctx.table.data_op == STD_OP_LT ||
3218 appctx->ctx.table.data_op == STD_OP_LE)))
3219 skip_entry = 1;
3220 }
3221
3222 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003223 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
3224 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
3225 return 0;
3226 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003227
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228 RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
3229
3230 SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003231 appctx->ctx.table.entry->ref_cnt--;
3232
3233 eb = ebmb_next(&appctx->ctx.table.entry->key);
3234 if (eb) {
3235 struct stksess *old = appctx->ctx.table.entry;
3236 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3237 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003238 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003239 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003240 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003241 appctx->ctx.table.entry->ref_cnt++;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003242 SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003243 break;
3244 }
3245
3246
3247 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003248 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003249 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003250 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3251
3252 SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003253
3254 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3255 appctx->st2 = STAT_ST_INFO;
3256 break;
3257
3258 case STAT_ST_END:
3259 appctx->st2 = STAT_ST_FIN;
3260 break;
3261 }
3262 }
3263 return 1;
3264}
3265
3266static void cli_release_show_table(struct appctx *appctx)
3267{
3268 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003269 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003270 }
3271}
3272
3273/* register cli keywords */
3274static struct cli_kw_list cli_kws = {{ },{
3275 { { "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 },
3276 { { "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 },
3277 { { "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 },
3278 {{},}
3279}};
3280
3281
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003282static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003283 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003284 { "sc-set-gpt0", parse_set_gpt0, 1 },
3285 { /* END */ }
3286}};
3287
Willy Tarreau620408f2016-10-21 16:37:51 +02003288static struct action_kw_list tcp_sess_kws = { { }, {
3289 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
3290 { "sc-set-gpt0", parse_set_gpt0, 1 },
3291 { /* END */ }
3292}};
3293
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003294static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003295 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003296 { "sc-set-gpt0", parse_set_gpt0, 1 },
3297 { /* END */ }
3298}};
3299
3300static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003301 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003302 { "sc-set-gpt0", parse_set_gpt0, 1 },
3303 { /* END */ }
3304}};
3305
3306static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003307 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003308 { "sc-set-gpt0", parse_set_gpt0, 1 },
3309 { /* END */ }
3310}};
3311
3312static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003313 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003314 { "sc-set-gpt0", parse_set_gpt0, 1 },
3315 { /* END */ }
3316}};
3317
Willy Tarreau7d562212016-11-25 16:10:05 +01003318///* Note: must not be declared <const> as its list will be overwritten.
3319// * Please take care of keeping this list alphabetically sorted.
3320// */
3321//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3322// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3323// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3324// { /* END */ },
3325//}};
3326/* Note: must not be declared <const> as its list will be overwritten.
3327 * Please take care of keeping this list alphabetically sorted.
3328 */
3329static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3330 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3331 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3332 { "sc_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3333 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3334 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3335 { "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 +01003336 { "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 +01003337 { "sc_get_gpc0", smp_fetch_sc_get_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3338 { "sc_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3339 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3340 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3341 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3342 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3343 { "sc_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3344 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3345 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3346 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3347 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3348 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3349 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3350 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3351 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3352 { "sc0_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3353 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3354 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3355 { "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 +01003356 { "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 +01003357 { "sc0_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3358 { "sc0_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3359 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3360 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3361 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3362 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3363 { "sc0_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3364 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3365 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3366 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3367 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3368 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3369 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3370 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3371 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3372 { "sc1_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3373 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3374 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3375 { "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 +01003376 { "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 +01003377 { "sc1_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3378 { "sc1_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3379 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3380 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3381 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3382 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3383 { "sc1_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3384 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3385 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3386 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3387 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3388 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3389 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3390 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3391 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3392 { "sc2_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3393 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3394 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3395 { "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 +01003396 { "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 +01003397 { "sc2_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3398 { "sc2_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3399 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3400 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3401 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3402 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3403 { "sc2_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3404 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3405 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3406 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3407 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3408 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3409 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3410 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3411 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3412 { "src_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3413 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3414 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3415 { "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 +01003416 { "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 +01003417 { "src_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3418 { "src_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3419 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3420 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3421 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3422 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3423 { "src_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3424 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3425 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3426 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3427 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3428 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3429 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3430 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3431 { /* END */ },
3432}};
3433
3434
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003435/* Note: must not be declared <const> as its list will be overwritten */
3436static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003437 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3438 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3439 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3440 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3441 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3442 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3443 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3444 { "table_gpc0", sample_conv_table_gpc0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3445 { "table_gpc0_rate", sample_conv_table_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3446 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3447 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3448 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3449 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3450 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3451 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3452 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3453 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3454 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3455 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003456 { /* END */ },
3457}};
3458
3459__attribute__((constructor))
3460static void __stick_table_init(void)
3461{
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003462 /* register som action keywords. */
3463 tcp_req_conn_keywords_register(&tcp_conn_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +02003464 tcp_req_sess_keywords_register(&tcp_sess_kws);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003465 tcp_req_cont_keywords_register(&tcp_req_kws);
3466 tcp_res_cont_keywords_register(&tcp_res_kws);
3467 http_req_keywords_register(&http_req_kws);
3468 http_res_keywords_register(&http_res_kws);
3469
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003470 /* register sample fetch and format conversion keywords */
Willy Tarreau7d562212016-11-25 16:10:05 +01003471 sample_register_fetches(&smp_fetch_keywords);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003472 sample_register_convs(&sample_conv_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003473 cli_register_kw(&cli_kws);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003474}