blob: 7f14163105d1148b6d434c4f2f376bdda6daceb9 [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>
Willy Tarreau61c112a2018-10-02 16:43:32 +020032#include <proto/http_rules.h>
Andjelko Iharosc3680ec2017-07-20 16:49:14 +020033#include <proto/log.h>
Thierry FOURNIER236657b2015-08-19 08:25:14 +020034#include <proto/proto_http.h>
Willy Tarreau7d562212016-11-25 16:10:05 +010035#include <proto/proto_tcp.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010036#include <proto/proxy.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020037#include <proto/sample.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020038#include <proto/stream.h>
Willy Tarreauf13ebdf2016-11-22 18:00:53 +010039#include <proto/stream_interface.h>
Willy Tarreau68129b92010-06-06 16:06:52 +020040#include <proto/stick_table.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010041#include <proto/task.h>
Emeric Brun32da3c42010-09-23 18:39:19 +020042#include <proto/peers.h>
Willy Tarreau39713102016-11-25 15:49:32 +010043#include <proto/tcp_rules.h>
Emeric Brun3bd697e2010-01-04 15:23:48 +010044
Willy Tarreau12785782012-04-27 21:37:17 +020045/* structure used to return a table key built from a sample */
Emeric Brun819fc6f2017-06-13 19:37:32 +020046static THREAD_LOCAL struct stktable_key static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +020047
Emeric Brun3bd697e2010-01-04 15:23:48 +010048/*
Willy Tarreauaea940e2010-06-06 11:56:36 +020049 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
50 * in table <t>.
Emeric Brun3bd697e2010-01-04 15:23:48 +010051 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020052void __stksess_free(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +010053{
54 t->current--;
Willy Tarreaubafbe012017-11-24 17:34:44 +010055 pool_free(t->pool, (void *)ts - t->data_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +010056}
57
58/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020059 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
60 * in table <t>.
61 * This function locks the table
62 */
63void stksess_free(struct stktable *t, struct stksess *ts)
64{
Christopher Faulet2a944ee2017-11-07 10:42:54 +010065 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020066 __stksess_free(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010067 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020068}
69
70/*
Willy Tarreauf6efda12010-08-03 20:34:06 +020071 * Kill an stksess (only if its ref_cnt is zero).
72 */
Emeric Brun819fc6f2017-06-13 19:37:32 +020073int __stksess_kill(struct stktable *t, struct stksess *ts)
Willy Tarreauf6efda12010-08-03 20:34:06 +020074{
75 if (ts->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +020076 return 0;
Willy Tarreauf6efda12010-08-03 20:34:06 +020077
78 eb32_delete(&ts->exp);
Emeric Brun85e77c72010-09-23 18:16:52 +020079 eb32_delete(&ts->upd);
Willy Tarreauf6efda12010-08-03 20:34:06 +020080 ebmb_delete(&ts->key);
Emeric Brun819fc6f2017-06-13 19:37:32 +020081 __stksess_free(t, ts);
82 return 1;
Willy Tarreauf6efda12010-08-03 20:34:06 +020083}
84
85/*
Emeric Brun819fc6f2017-06-13 19:37:32 +020086 * Decrease the refcount if decrefcnt is not 0.
87 * and try to kill the stksess
88 * This function locks the table
89 */
90int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
91{
92 int ret;
93
Christopher Faulet2a944ee2017-11-07 10:42:54 +010094 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020095 if (decrefcnt)
96 ts->ref_cnt--;
97 ret = __stksess_kill(t, ts);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010098 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +020099
100 return ret;
101}
102
103/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200104 * Initialize or update the key in the sticky session <ts> present in table <t>
105 * from the value present in <key>.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100106 */
Willy Tarreau393379c2010-06-06 12:11:37 +0200107void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100108{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200109 if (t->type != SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200110 memcpy(ts->key.key, key->key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100111 else {
Willy Tarreau86257dc2010-06-06 12:57:10 +0200112 memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
113 ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100114 }
115}
116
117
118/*
Willy Tarreau393379c2010-06-06 12:11:37 +0200119 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
120 * is returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100121 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200122static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100123{
Willy Tarreau393379c2010-06-06 12:11:37 +0200124 memset((void *)ts - t->data_size, 0, t->data_size);
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200125 ts->ref_cnt = 0;
Willy Tarreau86257dc2010-06-06 12:57:10 +0200126 ts->key.node.leaf_p = NULL;
127 ts->exp.node.leaf_p = NULL;
Emeric Brun85e77c72010-09-23 18:16:52 +0200128 ts->upd.node.leaf_p = NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200129 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100130 HA_RWLOCK_INIT(&ts->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100131 return ts;
132}
133
134/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200135 * Trash oldest <to_batch> sticky sessions from table <t>
136 * Returns number of trashed sticky sessions.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100137 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200138int __stktable_trash_oldest(struct stktable *t, int to_batch)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100139{
140 struct stksess *ts;
141 struct eb32_node *eb;
142 int batched = 0;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200143 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100144
145 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
146
147 while (batched < to_batch) {
148
149 if (unlikely(!eb)) {
150 /* we might have reached the end of the tree, typically because
151 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200152 * half. Let's loop back to the beginning of the tree now if we
153 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100154 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200155 if (looped)
156 break;
157 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100158 eb = eb32_first(&t->exps);
159 if (likely(!eb))
160 break;
161 }
162
163 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200164 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100165 eb = eb32_next(eb);
166
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200167 /* don't delete an entry which is currently referenced */
168 if (ts->ref_cnt)
169 continue;
170
Willy Tarreau86257dc2010-06-06 12:57:10 +0200171 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100172
Willy Tarreau86257dc2010-06-06 12:57:10 +0200173 if (ts->expire != ts->exp.key) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100174 if (!tick_isset(ts->expire))
175 continue;
176
Willy Tarreau86257dc2010-06-06 12:57:10 +0200177 ts->exp.key = ts->expire;
178 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100179
Willy Tarreau86257dc2010-06-06 12:57:10 +0200180 if (!eb || eb->key > ts->exp.key)
181 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100182
183 continue;
184 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100185
Willy Tarreauaea940e2010-06-06 11:56:36 +0200186 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200187 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200188 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200189 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100190 batched++;
191 }
192
193 return batched;
194}
195
196/*
Emeric Brun819fc6f2017-06-13 19:37:32 +0200197 * Trash oldest <to_batch> sticky sessions from table <t>
198 * Returns number of trashed sticky sessions.
199 * This function locks the table
200 */
201int stktable_trash_oldest(struct stktable *t, int to_batch)
202{
203 int ret;
204
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100205 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200206 ret = __stktable_trash_oldest(t, to_batch);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100207 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200208
209 return ret;
210}
211/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200212 * Allocate and initialise a new sticky session.
213 * The new sticky session is returned or NULL in case of lack of memory.
214 * Sticky sessions should only be allocated this way, and must be freed using
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200215 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
216 * is not NULL, it is assigned to the new session.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100217 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200218struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100219{
220 struct stksess *ts;
221
222 if (unlikely(t->current == t->size)) {
223 if ( t->nopurge )
224 return NULL;
225
Emeric Brun819fc6f2017-06-13 19:37:32 +0200226 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
Emeric Brun3bd697e2010-01-04 15:23:48 +0100227 return NULL;
228 }
229
Willy Tarreaubafbe012017-11-24 17:34:44 +0100230 ts = pool_alloc(t->pool);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100231 if (ts) {
232 t->current++;
Willy Tarreau51791462016-11-18 18:21:39 +0100233 ts = (void *)ts + t->data_size;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200234 __stksess_init(t, ts);
Willy Tarreaua7b46b52013-04-11 16:55:37 +0200235 if (key)
236 stksess_setkey(t, ts, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100237 }
238
239 return ts;
240}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200241/*
242 * Allocate and initialise a new sticky session.
243 * The new sticky session is returned or NULL in case of lack of memory.
244 * Sticky sessions should only be allocated this way, and must be freed using
245 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
246 * is not NULL, it is assigned to the new session.
247 * This function locks the table
248 */
249struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
250{
251 struct stksess *ts;
252
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100253 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200254 ts = __stksess_new(t, key);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100255 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200256
257 return ts;
258}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100259
260/*
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200261 * Looks in table <t> for a sticky session matching key <key>.
Willy Tarreauaea940e2010-06-06 11:56:36 +0200262 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100263 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200264struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100265{
266 struct ebmb_node *eb;
267
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200268 if (t->type == SMP_T_STR)
Emeric Brun485479d2010-09-23 18:02:19 +0200269 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 +0100270 else
271 eb = ebmb_lookup(&t->keys, key->key, t->key_size);
272
273 if (unlikely(!eb)) {
274 /* no session found */
275 return NULL;
276 }
277
Willy Tarreau86257dc2010-06-06 12:57:10 +0200278 return ebmb_entry(eb, struct stksess, key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100279}
280
Emeric Brun819fc6f2017-06-13 19:37:32 +0200281/*
282 * Looks in table <t> for a sticky session matching key <key>.
283 * Returns pointer on requested sticky session or NULL if none was found.
284 * The refcount of the found entry is increased and this function
285 * is protected using the table lock
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200286 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200287struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200288{
289 struct stksess *ts;
290
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100291 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200292 ts = __stktable_lookup_key(t, key);
293 if (ts)
294 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100295 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200296
Willy Tarreau1f7e9252010-06-20 12:27:21 +0200297 return ts;
298}
299
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200300/*
301 * Looks in table <t> for a sticky session with same key as <ts>.
302 * Returns pointer on requested sticky session or NULL if none was found.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100303 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200304struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100305{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100306 struct ebmb_node *eb;
307
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200308 if (t->type == SMP_T_STR)
Willy Tarreau86257dc2010-06-06 12:57:10 +0200309 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100310 else
Willy Tarreau86257dc2010-06-06 12:57:10 +0200311 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100312
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200313 if (unlikely(!eb))
314 return NULL;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100315
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200316 return ebmb_entry(eb, struct stksess, key);
317}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100318
Emeric Brun819fc6f2017-06-13 19:37:32 +0200319/*
320 * Looks in table <t> for a sticky session with same key as <ts>.
321 * Returns pointer on requested sticky session or NULL if none was found.
322 * The refcount of the found entry is increased and this function
323 * is protected using the table lock
324 */
325struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
326{
327 struct stksess *lts;
328
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100329 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200330 lts = __stktable_lookup(t, ts);
331 if (lts)
332 lts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100333 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200334
335 return lts;
336}
337
Willy Tarreaucb183642010-06-06 17:58:34 +0200338/* Update the expiration timer for <ts> but do not touch its expiration node.
339 * The table's expiration timer is updated if set.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200340 * The node will be also inserted into the update tree if needed, at a position
341 * depending if the update is a local or coming from a remote node
Willy Tarreaucb183642010-06-06 17:58:34 +0200342 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200343void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
Willy Tarreaucb183642010-06-06 17:58:34 +0200344{
Emeric Brun85e77c72010-09-23 18:16:52 +0200345 struct eb32_node * eb;
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200346 ts->expire = expire;
Willy Tarreaucb183642010-06-06 17:58:34 +0200347 if (t->expire) {
348 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
349 task_queue(t->exp_task);
350 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200351
Emeric Brun819fc6f2017-06-13 19:37:32 +0200352 /* If sync is enabled */
353 if (t->sync_task) {
354 if (local) {
355 /* If this entry is not in the tree
356 or not scheduled for at least one peer */
357 if (!ts->upd.node.leaf_p
358 || (int)(t->commitupdate - ts->upd.key) >= 0
359 || (int)(ts->upd.key - t->localupdate) >= 0) {
360 ts->upd.key = ++t->update;
361 t->localupdate = t->update;
362 eb32_delete(&ts->upd);
363 eb = eb32_insert(&t->updates, &ts->upd);
364 if (eb != &ts->upd) {
365 eb32_delete(eb);
366 eb32_insert(&t->updates, &ts->upd);
367 }
Emeric Brunaaf58602015-06-15 17:23:30 +0200368 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200369 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
Emeric Brun85e77c72010-09-23 18:16:52 +0200370 }
Emeric Brun819fc6f2017-06-13 19:37:32 +0200371 else {
372 /* If this entry is not in the tree */
373 if (!ts->upd.node.leaf_p) {
374 ts->upd.key= (++t->update)+(2147483648U);
375 eb = eb32_insert(&t->updates, &ts->upd);
376 if (eb != &ts->upd) {
377 eb32_delete(eb);
378 eb32_insert(&t->updates, &ts->upd);
379 }
380 }
381 }
Emeric Brun85e77c72010-09-23 18:16:52 +0200382 }
Willy Tarreaucb183642010-06-06 17:58:34 +0200383}
384
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200385/* Update the expiration timer for <ts> but do not touch its expiration node.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200386 * The table's expiration timer is updated using the date of expiration coming from
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200387 * <t> stick-table configuration.
Emeric Brun819fc6f2017-06-13 19:37:32 +0200388 * The node will be also inserted into the update tree if needed, at a position
389 * considering the update is coming from a remote node
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200390 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200391void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
392{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100393 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200394 __stktable_touch_with_exp(t, ts, 0, ts->expire);
395 if (decrefcnt)
396 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100397 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200398}
399
400/* Update the expiration timer for <ts> but do not touch its expiration node.
401 * The table's expiration timer is updated using the date of expiration coming from
402 * <t> stick-table configuration.
403 * The node will be also inserted into the update tree if needed, at a position
404 * considering the update was made locally
405 */
406void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200407{
408 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
409
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100410 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200411 __stktable_touch_with_exp(t, ts, 1, expire);
412 if (decrefcnt)
413 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100414 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200415}
Willy Tarreau43e90352018-06-27 06:25:57 +0200416/* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
417static void stktable_release(struct stktable *t, struct stksess *ts)
Emeric Brun819fc6f2017-06-13 19:37:32 +0200418{
Willy Tarreau43e90352018-06-27 06:25:57 +0200419 if (!ts)
420 return;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100421 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200422 ts->ref_cnt--;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100423 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200424}
425
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200426/* Insert new sticky session <ts> in the table. It is assumed that it does not
427 * yet exist (the caller must check this). The table's timeout is updated if it
428 * is set. <ts> is returned.
429 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200430void __stktable_store(struct stktable *t, struct stksess *ts)
Willy Tarreauf16d2b82010-06-06 15:38:59 +0200431{
Emeric Brun3bd697e2010-01-04 15:23:48 +0100432
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200433 ebmb_insert(&t->keys, &ts->key, t->key_size);
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200434 ts->exp.key = ts->expire;
435 eb32_insert(&t->exps, &ts->exp);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200436 if (t->expire) {
437 t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
438 task_queue(t->exp_task);
439 }
Frédéric Lécaille523cc9e2016-10-12 17:30:30 +0200440}
441
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200442/* Returns a valid or initialized stksess for the specified stktable_key in the
443 * specified table, or NULL if the key was NULL, or if no entry was found nor
444 * could be created. The entry's expiration is updated.
445 */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200446struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200447{
448 struct stksess *ts;
449
450 if (!key)
451 return NULL;
452
Emeric Brun819fc6f2017-06-13 19:37:32 +0200453 ts = __stktable_lookup_key(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200454 if (ts == NULL) {
455 /* entry does not exist, initialize a new one */
Emeric Brun819fc6f2017-06-13 19:37:32 +0200456 ts = __stksess_new(table, key);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200457 if (!ts)
458 return NULL;
Emeric Brun819fc6f2017-06-13 19:37:32 +0200459 __stktable_store(table, ts);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200460 }
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200461 return ts;
462}
Emeric Brun819fc6f2017-06-13 19:37:32 +0200463/* Returns a valid or initialized stksess for the specified stktable_key in the
464 * specified table, or NULL if the key was NULL, or if no entry was found nor
465 * could be created. The entry's expiration is updated.
466 * This function locks the table, and the refcount of the entry is increased.
467 */
468struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
469{
470 struct stksess *ts;
471
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100472 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200473 ts = __stktable_get_entry(table, key);
474 if (ts)
475 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100476 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200477
478 return ts;
479}
480
481/* Lookup for an entry with the same key and store the submitted
482 * stksess if not found.
483 */
484struct stksess *__stktable_set_entry(struct stktable *table, struct stksess *nts)
485{
486 struct stksess *ts;
487
488 ts = __stktable_lookup(table, nts);
489 if (ts == NULL) {
490 ts = nts;
491 __stktable_store(table, ts);
492 }
493 return ts;
494}
495
496/* Lookup for an entry with the same key and store the submitted
497 * stksess if not found.
498 * This function locks the table, and the refcount of the entry is increased.
499 */
500struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
501{
502 struct stksess *ts;
503
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100504 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200505 ts = __stktable_set_entry(table, nts);
506 ts->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100507 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
Willy Tarreau9ba2dcc2010-06-14 21:04:55 +0200508
Emeric Brun819fc6f2017-06-13 19:37:32 +0200509 return ts;
510}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100511/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200512 * Trash expired sticky sessions from table <t>. The next expiration date is
513 * returned.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100514 */
515static int stktable_trash_expired(struct stktable *t)
516{
517 struct stksess *ts;
518 struct eb32_node *eb;
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200519 int looped = 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100520
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100521 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100522 eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
523
524 while (1) {
525 if (unlikely(!eb)) {
526 /* we might have reached the end of the tree, typically because
527 * <now_ms> is in the first half and we're first scanning the last
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200528 * half. Let's loop back to the beginning of the tree now if we
529 * have not yet visited it.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100530 */
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200531 if (looped)
532 break;
533 looped = 1;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100534 eb = eb32_first(&t->exps);
535 if (likely(!eb))
536 break;
537 }
538
539 if (likely(tick_is_lt(now_ms, eb->key))) {
540 /* timer not expired yet, revisit it later */
541 t->exp_next = eb->key;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100542 goto out_unlock;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100543 }
544
545 /* timer looks expired, detach it from the queue */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200546 ts = eb32_entry(eb, struct stksess, exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100547 eb = eb32_next(eb);
548
Willy Tarreaue7f3d7a2010-06-14 14:53:07 +0200549 /* don't delete an entry which is currently referenced */
550 if (ts->ref_cnt)
551 continue;
552
Willy Tarreau86257dc2010-06-06 12:57:10 +0200553 eb32_delete(&ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100554
555 if (!tick_is_expired(ts->expire, now_ms)) {
556 if (!tick_isset(ts->expire))
557 continue;
558
Willy Tarreau86257dc2010-06-06 12:57:10 +0200559 ts->exp.key = ts->expire;
560 eb32_insert(&t->exps, &ts->exp);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100561
Willy Tarreau86257dc2010-06-06 12:57:10 +0200562 if (!eb || eb->key > ts->exp.key)
563 eb = &ts->exp;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100564 continue;
565 }
566
567 /* session expired, trash it */
Willy Tarreau86257dc2010-06-06 12:57:10 +0200568 ebmb_delete(&ts->key);
Emeric Brun85e77c72010-09-23 18:16:52 +0200569 eb32_delete(&ts->upd);
Emeric Brun819fc6f2017-06-13 19:37:32 +0200570 __stksess_free(t, ts);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100571 }
572
573 /* We have found no task to expire in any tree */
574 t->exp_next = TICK_ETERNITY;
Willy Tarreau4d5f13c2017-11-05 11:04:47 +0100575out_unlock:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100576 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100577 return t->exp_next;
578}
579
580/*
Willy Tarreauaea940e2010-06-06 11:56:36 +0200581 * Task processing function to trash expired sticky sessions. A pointer to the
582 * task itself is returned since it never dies.
Emeric Brun3bd697e2010-01-04 15:23:48 +0100583 */
Olivier Houchard9f6af332018-05-25 14:04:04 +0200584static struct task *process_table_expire(struct task *task, void *context, unsigned short state)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100585{
Olivier Houchard9f6af332018-05-25 14:04:04 +0200586 struct stktable *t = context;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100587
588 task->expire = stktable_trash_expired(t);
589 return task;
590}
591
Willy Tarreauaea940e2010-06-06 11:56:36 +0200592/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
Emeric Brun3bd697e2010-01-04 15:23:48 +0100593int stktable_init(struct stktable *t)
594{
595 if (t->size) {
Emeric Brun819fc6f2017-06-13 19:37:32 +0200596 t->keys = EB_ROOT_UNIQUE;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100597 memset(&t->exps, 0, sizeof(t->exps));
Emeric Brun1c6235d2015-12-16 15:28:12 +0100598 t->updates = EB_ROOT_UNIQUE;
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100599 HA_SPIN_INIT(&t->lock);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100600
Willy Tarreau393379c2010-06-06 12:11:37 +0200601 t->pool = create_pool("sticktables", sizeof(struct stksess) + t->data_size + t->key_size, MEM_F_SHARED);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100602
603 t->exp_next = TICK_ETERNITY;
604 if ( t->expire ) {
Emeric Brunc60def82017-09-27 14:59:38 +0200605 t->exp_task = task_new(MAX_THREADS_MASK);
Willy Tarreau848522f2018-10-15 11:12:15 +0200606 if (!t->exp_task)
607 return 0;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100608 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100609 t->exp_task->context = (void *)t;
610 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200611 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200612 peers_register_table(t->peers.p, t);
613 }
614
Emeric Brun3bd697e2010-01-04 15:23:48 +0100615 return t->pool != NULL;
616 }
617 return 1;
618}
619
620/*
621 * Configuration keywords of known table types
622 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200623struct stktable_type stktable_types[SMP_TYPES] = {
624 [SMP_T_SINT] = { "integer", 0, 4 },
625 [SMP_T_IPV4] = { "ip", 0, 4 },
626 [SMP_T_IPV6] = { "ipv6", 0, 16 },
627 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
628 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
629};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100630
631/*
632 * Parse table type configuration.
633 * Returns 0 on successful parsing, else 1.
634 * <myidx> is set at next configuration <args> index.
635 */
636int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
637{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200638 for (*type = 0; *type < SMP_TYPES; (*type)++) {
639 if (!stktable_types[*type].kw)
640 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100641 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
642 continue;
643
644 *key_size = stktable_types[*type].default_size;
645 (*myidx)++;
646
Willy Tarreauaea940e2010-06-06 11:56:36 +0200647 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100648 if (strcmp("len", args[*myidx]) == 0) {
649 (*myidx)++;
650 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200651 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100652 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200653 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200654 /* null terminated string needs +1 for '\0'. */
655 (*key_size)++;
656 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100657 (*myidx)++;
658 }
659 }
660 return 0;
661 }
662 return 1;
663}
664
Willy Tarreau8fed9032014-07-03 17:02:46 +0200665/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200666 * Note that the sample *is* modified and that the returned key may point
667 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200668 * Returns NULL if the sample could not be converted (eg: no matching type),
669 * otherwise a pointer to the static stktable_key filled with what is needed
670 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200671 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200672struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200673{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200674 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200675 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200676 return NULL;
677
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200678 /* Fill static_table_key. */
679 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200680
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200681 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200682 static_table_key.key = &smp->data.u.ipv4;
683 static_table_key.key_len = 4;
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_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200687 static_table_key.key = &smp->data.u.ipv6;
688 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200689 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200690
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200691 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200692 /* The stick table require a 32bit unsigned int, "sint" is a
693 * signed 64 it, so we can convert it inplace.
694 */
695 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200696 static_table_key.key = &smp->data.u.sint;
697 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200698 break;
699
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200700 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200701 if (!smp_make_safe(smp))
702 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200703 static_table_key.key = smp->data.u.str.area;
704 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200705 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200706
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200707 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200708 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200709 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200710 if (!smp_make_rw(smp))
711 return NULL;
712
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200713 if (smp->data.u.str.size < t->key_size)
714 if (!smp_dup(smp))
715 return NULL;
716 if (smp->data.u.str.size < t->key_size)
717 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200718 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
719 t->key_size - smp->data.u.str.data);
720 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200721 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200722 static_table_key.key = smp->data.u.str.area;
723 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200724 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200725
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200726 default: /* impossible case. */
727 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200728 }
729
Christopher Fauletca20d022017-08-29 15:30:31 +0200730 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200731}
732
733/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200734 * Process a fetch + format conversion as defined by the sample expression <expr>
735 * on request or response considering the <opt> parameter. Returns either NULL if
736 * no key could be extracted, or a pointer to the converted result stored in
737 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
738 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200739 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
740 * without SMP_OPT_FINAL). The output will be usable like this :
741 *
742 * return MAY_CHANGE FINAL Meaning for the sample
743 * NULL 0 * Not present and will never be (eg: header)
744 * NULL 1 0 Not present or unstable, could change (eg: req_len)
745 * NULL 1 1 Not present, will not change anymore
746 * smp 0 * Present and will not change (eg: header)
747 * smp 1 0 not possible
748 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200749 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200750struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200751 unsigned int opt, struct sample_expr *expr, struct sample *smp)
752{
753 if (smp)
754 memset(smp, 0, sizeof(*smp));
755
Willy Tarreau192252e2015-04-04 01:47:55 +0200756 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200757 if (!smp)
758 return NULL;
759
760 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
761 return NULL; /* we can only use stable samples */
762
763 return smp_to_stkey(smp, t);
764}
765
766/*
Willy Tarreau12785782012-04-27 21:37:17 +0200767 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200768 * type <table_type>, otherwise zero. Used in configuration check.
769 */
Willy Tarreau12785782012-04-27 21:37:17 +0200770int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200771{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100772 int out_type;
773
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200774 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200775 return 0;
776
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100777 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200778
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200779 /* Convert sample. */
780 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100781 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200782
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200783 return 1;
784}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100785
Willy Tarreauedee1d62014-07-15 16:44:27 +0200786/* Extra data types processing : after the last one, some room may remain
787 * before STKTABLE_DATA_TYPES that may be used to register extra data types
788 * at run time.
789 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200790struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200791 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200792 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200793 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200794 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200795 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
796 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
797 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
798 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
799 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
800 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
801 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
802 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
803 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
804 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
805 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
806 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
807 [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Frédéric Lécaille6778b272018-01-29 15:22:53 +0100808 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
809 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +0200810};
811
Willy Tarreauedee1d62014-07-15 16:44:27 +0200812/* Registers stick-table extra data type with index <idx>, name <name>, type
813 * <std_type> and arg type <arg_type>. If the index is negative, the next free
814 * index is automatically allocated. The allocated index is returned, or -1 if
815 * no free index was found or <name> was already registered. The <name> is used
816 * directly as a pointer, so if it's not stable, the caller must allocate it.
817 */
818int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
819{
820 if (idx < 0) {
821 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
822 if (!stktable_data_types[idx].name)
823 break;
824
825 if (strcmp(stktable_data_types[idx].name, name) == 0)
826 return -1;
827 }
828 }
829
830 if (idx >= STKTABLE_DATA_TYPES)
831 return -1;
832
833 if (stktable_data_types[idx].name != NULL)
834 return -1;
835
836 stktable_data_types[idx].name = name;
837 stktable_data_types[idx].std_type = std_type;
838 stktable_data_types[idx].arg_type = arg_type;
839 return idx;
840}
841
Willy Tarreau08d5f982010-06-06 13:34:54 +0200842/*
843 * Returns the data type number for the stktable_data_type whose name is <name>,
844 * or <0 if not found.
845 */
846int stktable_get_data_type(char *name)
847{
848 int type;
849
850 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +0200851 if (!stktable_data_types[type].name)
852 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +0200853 if (strcmp(name, stktable_data_types[type].name) == 0)
854 return type;
855 }
856 return -1;
857}
858
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200859/* Casts sample <smp> to the type of the table specified in arg(0), and looks
860 * it up into this table. Returns true if found, false otherwise. The input
861 * type is STR so that input samples are converted to string (since all types
862 * can be converted to strings), then the function casts the string again into
863 * the table's type. This is a double conversion, but in the future we might
864 * support automatic input types to perform the cast on the fly.
865 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200866static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200867{
868 struct stktable *t;
869 struct stktable_key *key;
870 struct stksess *ts;
871
872 t = &arg_p[0].data.prx->table;
873
874 key = smp_to_stkey(smp, t);
875 if (!key)
876 return 0;
877
878 ts = stktable_lookup_key(t, key);
879
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200880 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200881 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200882 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +0200883 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200884 return 1;
885}
886
887/* Casts sample <smp> to the type of the table specified in arg(0), and looks
888 * it up into this table. Returns the data rate received from clients in bytes/s
889 * if the key is present in the table, otherwise zero, so that comparisons can
890 * be easily performed. If the inspected parameter is not stored in the table,
891 * <not found> is returned.
892 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200893static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200894{
895 struct stktable *t;
896 struct stktable_key *key;
897 struct stksess *ts;
898 void *ptr;
899
900 t = &arg_p[0].data.prx->table;
901
902 key = smp_to_stkey(smp, t);
903 if (!key)
904 return 0;
905
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200906 ts = stktable_lookup_key(t, key);
907
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200908 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200909 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200910 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200911
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200912 if (!ts) /* key not present */
913 return 1;
914
915 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400916 if (ptr)
917 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
918 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200919
Daniel Corbett3e60b112018-05-27 09:47:12 -0400920 stktable_release(t, ts);
921 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200922}
923
924/* Casts sample <smp> to the type of the table specified in arg(0), and looks
925 * it up into this table. Returns the cumulated number of connections for the key
926 * if the key is present in the table, otherwise zero, so that comparisons can
927 * be easily performed. If the inspected parameter is not stored in the table,
928 * <not found> is returned.
929 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200930static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200931{
932 struct stktable *t;
933 struct stktable_key *key;
934 struct stksess *ts;
935 void *ptr;
936
937 t = &arg_p[0].data.prx->table;
938
939 key = smp_to_stkey(smp, t);
940 if (!key)
941 return 0;
942
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200943 ts = stktable_lookup_key(t, key);
944
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200945 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200946 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200947 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200948
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200949 if (!ts) /* key not present */
950 return 1;
951
952 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400953 if (ptr)
954 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200955
Daniel Corbett3e60b112018-05-27 09:47:12 -0400956 stktable_release(t, ts);
957 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200958}
959
960/* Casts sample <smp> to the type of the table specified in arg(0), and looks
961 * it up into this table. Returns the number of concurrent connections for the
962 * key if the key is present in the table, otherwise zero, so that comparisons
963 * can be easily performed. If the inspected parameter is not stored in the
964 * table, <not found> is returned.
965 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200966static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200967{
968 struct stktable *t;
969 struct stktable_key *key;
970 struct stksess *ts;
971 void *ptr;
972
973 t = &arg_p[0].data.prx->table;
974
975 key = smp_to_stkey(smp, t);
976 if (!key)
977 return 0;
978
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200979 ts = stktable_lookup_key(t, key);
980
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200981 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200982 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200983 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200984
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200985 if (!ts) /* key not present */
986 return 1;
987
988 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400989 if (ptr)
990 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200991
Daniel Corbett3e60b112018-05-27 09:47:12 -0400992 stktable_release(t, ts);
993 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200994}
995
996/* Casts sample <smp> to the type of the table specified in arg(0), and looks
997 * it up into this table. Returns the rate of incoming connections from the key
998 * if the key is present in the table, otherwise zero, so that comparisons can
999 * be easily performed. If the inspected parameter is not stored in the table,
1000 * <not found> is returned.
1001 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001002static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001003{
1004 struct stktable *t;
1005 struct stktable_key *key;
1006 struct stksess *ts;
1007 void *ptr;
1008
1009 t = &arg_p[0].data.prx->table;
1010
1011 key = smp_to_stkey(smp, t);
1012 if (!key)
1013 return 0;
1014
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001015 ts = stktable_lookup_key(t, key);
1016
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001017 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001018 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001019 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001020
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001021 if (!ts) /* key not present */
1022 return 1;
1023
1024 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001025 if (ptr)
1026 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1027 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001028
Daniel Corbett3e60b112018-05-27 09:47:12 -04001029 stktable_release(t, ts);
1030 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001031}
1032
1033/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1034 * it up into this table. Returns the data rate sent to clients in bytes/s
1035 * if the key is present in the table, otherwise zero, so that comparisons can
1036 * be easily performed. If the inspected parameter is not stored in the table,
1037 * <not found> is returned.
1038 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001039static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001040{
1041 struct stktable *t;
1042 struct stktable_key *key;
1043 struct stksess *ts;
1044 void *ptr;
1045
1046 t = &arg_p[0].data.prx->table;
1047
1048 key = smp_to_stkey(smp, t);
1049 if (!key)
1050 return 0;
1051
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001052 ts = stktable_lookup_key(t, key);
1053
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001054 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001055 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001056 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001057
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001058 if (!ts) /* key not present */
1059 return 1;
1060
1061 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001062 if (ptr)
1063 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1064 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001065
Daniel Corbett3e60b112018-05-27 09:47:12 -04001066 stktable_release(t, ts);
1067 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001068}
1069
1070/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001071 * it up into this table. Returns the value of the GPT0 tag for the key
1072 * if the key is present in the table, otherwise false, so that comparisons can
1073 * be easily performed. If the inspected parameter is not stored in the table,
1074 * <not found> is returned.
1075 */
1076static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1077{
1078 struct stktable *t;
1079 struct stktable_key *key;
1080 struct stksess *ts;
1081 void *ptr;
1082
1083 t = &arg_p[0].data.prx->table;
1084
1085 key = smp_to_stkey(smp, t);
1086 if (!key)
1087 return 0;
1088
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001089 ts = stktable_lookup_key(t, key);
1090
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001091 smp->flags = SMP_F_VOL_TEST;
1092 smp->data.type = SMP_T_SINT;
1093 smp->data.u.sint = 0;
1094
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001095 if (!ts) /* key not present */
1096 return 1;
1097
1098 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001099 if (ptr)
1100 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001101
Daniel Corbett3e60b112018-05-27 09:47:12 -04001102 stktable_release(t, ts);
1103 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001104}
1105
1106/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001107 * it up into this table. Returns the value of the GPC0 counter for the key
1108 * if the key is present in the table, otherwise zero, so that comparisons can
1109 * be easily performed. If the inspected parameter is not stored in the table,
1110 * <not found> is returned.
1111 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001112static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001113{
1114 struct stktable *t;
1115 struct stktable_key *key;
1116 struct stksess *ts;
1117 void *ptr;
1118
1119 t = &arg_p[0].data.prx->table;
1120
1121 key = smp_to_stkey(smp, t);
1122 if (!key)
1123 return 0;
1124
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001125 ts = stktable_lookup_key(t, key);
1126
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001127 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001128 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001129 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001130
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001131 if (!ts) /* key not present */
1132 return 1;
1133
1134 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001135 if (ptr)
1136 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001137
Daniel Corbett3e60b112018-05-27 09:47:12 -04001138 stktable_release(t, ts);
1139 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001140}
1141
1142/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1143 * it up into this table. Returns the event rate of the GPC0 counter for the key
1144 * if the key is present in the table, otherwise zero, so that comparisons can
1145 * be easily performed. If the inspected parameter is not stored in the table,
1146 * <not found> is returned.
1147 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001148static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001149{
1150 struct stktable *t;
1151 struct stktable_key *key;
1152 struct stksess *ts;
1153 void *ptr;
1154
1155 t = &arg_p[0].data.prx->table;
1156
1157 key = smp_to_stkey(smp, t);
1158 if (!key)
1159 return 0;
1160
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001161 ts = stktable_lookup_key(t, key);
1162
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001163 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001164 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001165 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001166
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001167 if (!ts) /* key not present */
1168 return 1;
1169
1170 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001171 if (ptr)
1172 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1173 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001174
Daniel Corbett3e60b112018-05-27 09:47:12 -04001175 stktable_release(t, ts);
1176 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001177}
1178
1179/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001180 * it up into this table. Returns the value of the GPC1 counter for the key
1181 * if the key is present in the table, otherwise zero, so that comparisons can
1182 * be easily performed. If the inspected parameter is not stored in the table,
1183 * <not found> is returned.
1184 */
1185static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1186{
1187 struct stktable *t;
1188 struct stktable_key *key;
1189 struct stksess *ts;
1190 void *ptr;
1191
1192 t = &arg_p[0].data.prx->table;
1193
1194 key = smp_to_stkey(smp, t);
1195 if (!key)
1196 return 0;
1197
1198 ts = stktable_lookup_key(t, key);
1199
1200 smp->flags = SMP_F_VOL_TEST;
1201 smp->data.type = SMP_T_SINT;
1202 smp->data.u.sint = 0;
1203
1204 if (!ts) /* key not present */
1205 return 1;
1206
1207 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001208 if (ptr)
1209 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001210
Daniel Corbett3e60b112018-05-27 09:47:12 -04001211 stktable_release(t, ts);
1212 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001213}
1214
1215/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1216 * it up into this table. Returns the event rate of the GPC1 counter for the key
1217 * if the key is present in the table, otherwise zero, so that comparisons can
1218 * be easily performed. If the inspected parameter is not stored in the table,
1219 * <not found> is returned.
1220 */
1221static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1222{
1223 struct stktable *t;
1224 struct stktable_key *key;
1225 struct stksess *ts;
1226 void *ptr;
1227
1228 t = &arg_p[0].data.prx->table;
1229
1230 key = smp_to_stkey(smp, t);
1231 if (!key)
1232 return 0;
1233
1234 ts = stktable_lookup_key(t, key);
1235
1236 smp->flags = SMP_F_VOL_TEST;
1237 smp->data.type = SMP_T_SINT;
1238 smp->data.u.sint = 0;
1239
1240 if (!ts) /* key not present */
1241 return 1;
1242
1243 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001244 if (ptr)
1245 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1246 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001247
Daniel Corbett3e60b112018-05-27 09:47:12 -04001248 stktable_release(t, ts);
1249 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001250}
1251
1252/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001253 * it up into this table. Returns the cumulated number of HTTP request errors
1254 * for the key if the key is present in the table, otherwise zero, so that
1255 * comparisons can be easily performed. If the inspected parameter is not stored
1256 * in the table, <not found> is returned.
1257 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001258static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001259{
1260 struct stktable *t;
1261 struct stktable_key *key;
1262 struct stksess *ts;
1263 void *ptr;
1264
1265 t = &arg_p[0].data.prx->table;
1266
1267 key = smp_to_stkey(smp, t);
1268 if (!key)
1269 return 0;
1270
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001271 ts = stktable_lookup_key(t, key);
1272
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001273 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001274 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001275 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001276
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001277 if (!ts) /* key not present */
1278 return 1;
1279
1280 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001281 if (ptr)
1282 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001283
Daniel Corbett3e60b112018-05-27 09:47:12 -04001284 stktable_release(t, ts);
1285 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001286}
1287
1288/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1289 * it up into this table. Returns the HTTP request error rate the key
1290 * if the key is present in the table, otherwise zero, so that comparisons can
1291 * be easily performed. If the inspected parameter is not stored in the table,
1292 * <not found> is returned.
1293 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001294static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001295{
1296 struct stktable *t;
1297 struct stktable_key *key;
1298 struct stksess *ts;
1299 void *ptr;
1300
1301 t = &arg_p[0].data.prx->table;
1302
1303 key = smp_to_stkey(smp, t);
1304 if (!key)
1305 return 0;
1306
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001307 ts = stktable_lookup_key(t, key);
1308
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001309 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001310 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001311 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001312
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001313 if (!ts) /* key not present */
1314 return 1;
1315
1316 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001317 if (ptr)
1318 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1319 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001320
Daniel Corbett3e60b112018-05-27 09:47:12 -04001321 stktable_release(t, ts);
1322 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001323}
1324
1325/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1326 * it up into this table. Returns the cumulated number of HTTP request for the
1327 * key if the key is present in the table, otherwise zero, so that comparisons
1328 * can be easily performed. If the inspected parameter is not stored in the
1329 * table, <not found> is returned.
1330 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001331static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001332{
1333 struct stktable *t;
1334 struct stktable_key *key;
1335 struct stksess *ts;
1336 void *ptr;
1337
1338 t = &arg_p[0].data.prx->table;
1339
1340 key = smp_to_stkey(smp, t);
1341 if (!key)
1342 return 0;
1343
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001344 ts = stktable_lookup_key(t, key);
1345
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001346 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001347 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001348 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001349
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001350 if (!ts) /* key not present */
1351 return 1;
1352
1353 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001354 if (ptr)
1355 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001356
Daniel Corbett3e60b112018-05-27 09:47:12 -04001357 stktable_release(t, ts);
1358 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001359}
1360
1361/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1362 * it up into this table. Returns the HTTP request rate the key if the key is
1363 * present in the table, otherwise zero, so that comparisons can be easily
1364 * performed. If the inspected parameter is not stored in the table, <not found>
1365 * is returned.
1366 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001367static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001368{
1369 struct stktable *t;
1370 struct stktable_key *key;
1371 struct stksess *ts;
1372 void *ptr;
1373
1374 t = &arg_p[0].data.prx->table;
1375
1376 key = smp_to_stkey(smp, t);
1377 if (!key)
1378 return 0;
1379
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001380 ts = stktable_lookup_key(t, key);
1381
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001382 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001383 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001384 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001385
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001386 if (!ts) /* key not present */
1387 return 1;
1388
1389 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001390 if (ptr)
1391 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1392 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001393
Daniel Corbett3e60b112018-05-27 09:47:12 -04001394 stktable_release(t, ts);
1395 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001396}
1397
1398/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1399 * it up into this table. Returns the volume of datareceived from clients in kbytes
1400 * if the key is present in the table, otherwise zero, so that comparisons can
1401 * be easily performed. If the inspected parameter is not stored in the table,
1402 * <not found> is returned.
1403 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001404static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001405{
1406 struct stktable *t;
1407 struct stktable_key *key;
1408 struct stksess *ts;
1409 void *ptr;
1410
1411 t = &arg_p[0].data.prx->table;
1412
1413 key = smp_to_stkey(smp, t);
1414 if (!key)
1415 return 0;
1416
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001417 ts = stktable_lookup_key(t, key);
1418
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001419 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001420 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001421 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001422
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001423 if (!ts) /* key not present */
1424 return 1;
1425
1426 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001427 if (ptr)
1428 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001429
Daniel Corbett3e60b112018-05-27 09:47:12 -04001430 stktable_release(t, ts);
1431 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001432}
1433
1434/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1435 * it up into this table. Returns the volume of data sent to clients in kbytes
1436 * if the key is present in the table, otherwise zero, so that comparisons can
1437 * be easily performed. If the inspected parameter is not stored in the table,
1438 * <not found> is returned.
1439 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001440static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001441{
1442 struct stktable *t;
1443 struct stktable_key *key;
1444 struct stksess *ts;
1445 void *ptr;
1446
1447 t = &arg_p[0].data.prx->table;
1448
1449 key = smp_to_stkey(smp, t);
1450 if (!key)
1451 return 0;
1452
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001453 ts = stktable_lookup_key(t, key);
1454
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001455 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001456 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001457 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001458
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001459 if (!ts) /* key not present */
1460 return 1;
1461
1462 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001463 if (ptr)
1464 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001465
Daniel Corbett3e60b112018-05-27 09:47:12 -04001466 stktable_release(t, ts);
1467 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001468}
1469
1470/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1471 * it up into this table. Returns the server ID associated with the key if the
1472 * key is present in the table, otherwise zero, so that comparisons can be
1473 * easily performed. If the inspected parameter is not stored in the table,
1474 * <not found> is returned.
1475 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001476static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001477{
1478 struct stktable *t;
1479 struct stktable_key *key;
1480 struct stksess *ts;
1481 void *ptr;
1482
1483 t = &arg_p[0].data.prx->table;
1484
1485 key = smp_to_stkey(smp, t);
1486 if (!key)
1487 return 0;
1488
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001489 ts = stktable_lookup_key(t, key);
1490
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001491 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001492 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001493 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001494
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001495 if (!ts) /* key not present */
1496 return 1;
1497
1498 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001499 if (ptr)
1500 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001501
Daniel Corbett3e60b112018-05-27 09:47:12 -04001502 stktable_release(t, ts);
1503 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001504}
1505
1506/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1507 * it up into this table. Returns the cumulated number of sessions for the
1508 * key if the key is present in the table, otherwise zero, so that comparisons
1509 * can be easily performed. If the inspected parameter is not stored in the
1510 * table, <not found> is returned.
1511 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001512static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001513{
1514 struct stktable *t;
1515 struct stktable_key *key;
1516 struct stksess *ts;
1517 void *ptr;
1518
1519 t = &arg_p[0].data.prx->table;
1520
1521 key = smp_to_stkey(smp, t);
1522 if (!key)
1523 return 0;
1524
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001525 ts = stktable_lookup_key(t, key);
1526
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001527 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001528 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001529 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001530
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001531 if (!ts) /* key not present */
1532 return 1;
1533
1534 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001535 if (ptr)
1536 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001537
Daniel Corbett3e60b112018-05-27 09:47:12 -04001538 stktable_release(t, ts);
1539 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001540}
1541
1542/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1543 * it up into this table. Returns the session rate the key if the key is
1544 * present in the table, otherwise zero, so that comparisons can be easily
1545 * performed. If the inspected parameter is not stored in the table, <not found>
1546 * is returned.
1547 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001548static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001549{
1550 struct stktable *t;
1551 struct stktable_key *key;
1552 struct stksess *ts;
1553 void *ptr;
1554
1555 t = &arg_p[0].data.prx->table;
1556
1557 key = smp_to_stkey(smp, t);
1558 if (!key)
1559 return 0;
1560
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001561 ts = stktable_lookup_key(t, key);
1562
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001563 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001564 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001565 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001566
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001567 if (!ts) /* key not present */
1568 return 1;
1569
1570 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001571 if (ptr)
1572 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1573 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001574
Daniel Corbett3e60b112018-05-27 09:47:12 -04001575 stktable_release(t, ts);
1576 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001577}
1578
1579/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1580 * it up into this table. Returns the amount of concurrent connections tracking
1581 * the same key if the key is present in the table, otherwise zero, so that
1582 * comparisons can be easily performed. If the inspected parameter is not
1583 * stored in the table, <not found> is returned.
1584 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001585static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001586{
1587 struct stktable *t;
1588 struct stktable_key *key;
1589 struct stksess *ts;
1590
1591 t = &arg_p[0].data.prx->table;
1592
1593 key = smp_to_stkey(smp, t);
1594 if (!key)
1595 return 0;
1596
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001597 ts = stktable_lookup_key(t, key);
1598
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001599 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001600 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001601 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001602
Tim Duesterhus65189c12018-06-26 15:57:29 +02001603 if (!ts)
1604 return 1;
1605
1606 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001607
Daniel Corbett3e60b112018-05-27 09:47:12 -04001608 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001609 return 1;
1610}
1611
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001612/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001613static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001614 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001615{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001616 struct stksess *ts;
1617 struct stkctr *stkctr;
1618
1619 /* Extract the stksess, return OK if no stksess available. */
1620 if (s)
1621 stkctr = &s->stkctr[rule->arg.gpc.sc];
1622 else
1623 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001624
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001625 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001626 if (ts) {
1627 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001628
Willy Tarreau79c1e912016-01-25 14:54:45 +01001629 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1630 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001631 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1632 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001633 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001634
1635 if (ptr1)
1636 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001637 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001638
Emeric Brun819fc6f2017-06-13 19:37:32 +02001639 if (ptr2)
1640 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001641
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001642 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001643
1644 /* If data was modified, we need to touch to re-schedule sync */
1645 stktable_touch_local(stkctr->table, ts, 0);
1646 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001647 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001648 return ACT_RET_CONT;
1649}
1650
1651/* This function is a common parser for using variables. It understands
1652 * the formats:
1653 *
1654 * sc-inc-gpc0(<stick-table ID>)
1655 *
1656 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1657 * it returns 1 and the variable <expr> is filled with the pointer to the
1658 * expression to execute.
1659 */
1660static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1661 struct act_rule *rule, char **err)
1662{
1663 const char *cmd_name = args[*arg-1];
1664 char *error;
1665
1666 cmd_name += strlen("sc-inc-gpc0");
1667 if (*cmd_name == '\0') {
1668 /* default stick table id. */
1669 rule->arg.gpc.sc = 0;
1670 } else {
1671 /* parse the stick table id. */
1672 if (*cmd_name != '(') {
1673 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1674 return ACT_RET_PRS_ERR;
1675 }
1676 cmd_name++; /* jump the '(' */
1677 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1678 if (*error != ')') {
1679 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1680 return ACT_RET_PRS_ERR;
1681 }
1682
1683 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1684 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1685 ACT_ACTION_TRK_SCMAX-1);
1686 return ACT_RET_PRS_ERR;
1687 }
1688 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001689 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001690 rule->action_ptr = action_inc_gpc0;
1691 return ACT_RET_PRS_OK;
1692}
1693
1694/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001695static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1696 struct session *sess, struct stream *s, int flags)
1697{
1698 struct stksess *ts;
1699 struct stkctr *stkctr;
1700
1701 /* Extract the stksess, return OK if no stksess available. */
1702 if (s)
1703 stkctr = &s->stkctr[rule->arg.gpc.sc];
1704 else
1705 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1706
1707 ts = stkctr_entry(stkctr);
1708 if (ts) {
1709 void *ptr1, *ptr2;
1710
1711 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1712 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1713 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1714 if (ptr1 || ptr2) {
1715 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1716
1717 if (ptr1)
1718 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1719 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1720
1721 if (ptr2)
1722 stktable_data_cast(ptr2, gpc1)++;
1723
1724 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1725
1726 /* If data was modified, we need to touch to re-schedule sync */
1727 stktable_touch_local(stkctr->table, ts, 0);
1728 }
1729 }
1730 return ACT_RET_CONT;
1731}
1732
1733/* This function is a common parser for using variables. It understands
1734 * the formats:
1735 *
1736 * sc-inc-gpc1(<stick-table ID>)
1737 *
1738 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1739 * it returns 1 and the variable <expr> is filled with the pointer to the
1740 * expression to execute.
1741 */
1742static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1743 struct act_rule *rule, char **err)
1744{
1745 const char *cmd_name = args[*arg-1];
1746 char *error;
1747
1748 cmd_name += strlen("sc-inc-gpc1");
1749 if (*cmd_name == '\0') {
1750 /* default stick table id. */
1751 rule->arg.gpc.sc = 0;
1752 } else {
1753 /* parse the stick table id. */
1754 if (*cmd_name != '(') {
1755 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1756 return ACT_RET_PRS_ERR;
1757 }
1758 cmd_name++; /* jump the '(' */
1759 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1760 if (*error != ')') {
1761 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1762 return ACT_RET_PRS_ERR;
1763 }
1764
1765 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1766 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1767 ACT_ACTION_TRK_SCMAX-1);
1768 return ACT_RET_PRS_ERR;
1769 }
1770 }
1771 rule->action = ACT_CUSTOM;
1772 rule->action_ptr = action_inc_gpc1;
1773 return ACT_RET_PRS_OK;
1774}
1775
1776/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001777static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001778 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001779{
1780 void *ptr;
1781 struct stksess *ts;
1782 struct stkctr *stkctr;
1783
1784 /* Extract the stksess, return OK if no stksess available. */
1785 if (s)
1786 stkctr = &s->stkctr[rule->arg.gpt.sc];
1787 else
1788 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001789
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001790 ts = stkctr_entry(stkctr);
1791 if (!ts)
1792 return ACT_RET_CONT;
1793
1794 /* Store the sample in the required sc, and ignore errors. */
1795 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001796 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001797 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001798
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001799 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001800
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001801 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001802
1803 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001804 }
1805
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001806 return ACT_RET_CONT;
1807}
1808
1809/* This function is a common parser for using variables. It understands
1810 * the format:
1811 *
1812 * set-gpt0(<stick-table ID>) <expression>
1813 *
1814 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1815 * it returns 1 and the variable <expr> is filled with the pointer to the
1816 * expression to execute.
1817 */
1818static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1819 struct act_rule *rule, char **err)
1820
1821
1822{
1823 const char *cmd_name = args[*arg-1];
1824 char *error;
1825
1826 cmd_name += strlen("sc-set-gpt0");
1827 if (*cmd_name == '\0') {
1828 /* default stick table id. */
1829 rule->arg.gpt.sc = 0;
1830 } else {
1831 /* parse the stick table id. */
1832 if (*cmd_name != '(') {
1833 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1834 return ACT_RET_PRS_ERR;
1835 }
1836 cmd_name++; /* jump the '(' */
1837 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1838 if (*error != ')') {
1839 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1840 return ACT_RET_PRS_ERR;
1841 }
1842
1843 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1844 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1845 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1846 return ACT_RET_PRS_ERR;
1847 }
1848 }
1849
1850 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1851 if (*error != '\0') {
1852 memprintf(err, "invalid integer value '%s'", args[*arg]);
1853 return ACT_RET_PRS_ERR;
1854 }
1855 (*arg)++;
1856
Thierry FOURNIER42148732015-09-02 17:17:33 +02001857 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001858 rule->action_ptr = action_set_gpt0;
1859
1860 return ACT_RET_PRS_OK;
1861}
1862
Willy Tarreau7d562212016-11-25 16:10:05 +01001863/* set temp integer to the number of used entries in the table pointed to by expr.
1864 * Accepts exactly 1 argument of type table.
1865 */
1866static int
1867smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1868{
1869 smp->flags = SMP_F_VOL_TEST;
1870 smp->data.type = SMP_T_SINT;
1871 smp->data.u.sint = args->data.prx->table.current;
1872 return 1;
1873}
1874
1875/* set temp integer to the number of free entries in the table pointed to by expr.
1876 * Accepts exactly 1 argument of type table.
1877 */
1878static int
1879smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1880{
1881 struct proxy *px;
1882
1883 px = args->data.prx;
1884 smp->flags = SMP_F_VOL_TEST;
1885 smp->data.type = SMP_T_SINT;
1886 smp->data.u.sint = px->table.size - px->table.current;
1887 return 1;
1888}
1889
1890/* Returns a pointer to a stkctr depending on the fetch keyword name.
1891 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1892 * sc[0-9]_* will return a pointer to the respective field in the
1893 * stream <l4>. sc_* requires an UINT argument specifying the stick
1894 * counter number. src_* will fill a locally allocated structure with
1895 * the table and entry corresponding to what is specified with src_*.
1896 * NULL may be returned if the designated stkctr is not tracked. For
1897 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1898 * passed. When present, the currently tracked key is then looked up
1899 * in the specified table instead of the current table. The purpose is
1900 * to be able to convery multiple values per key (eg: have gpc0 from
1901 * multiple tables). <strm> is allowed to be NULL, in which case only
1902 * the session will be consulted.
1903 */
1904struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001905smp_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 +01001906{
Willy Tarreau7d562212016-11-25 16:10:05 +01001907 struct stkctr *stkptr;
1908 struct stksess *stksess;
1909 unsigned int num = kw[2] - '0';
1910 int arg = 0;
1911
1912 if (num == '_' - '0') {
1913 /* sc_* variant, args[0] = ctr# (mandatory) */
1914 num = args[arg++].data.sint;
1915 if (num >= MAX_SESS_STKCTR)
1916 return NULL;
1917 }
1918 else if (num > 9) { /* src_* variant, args[0] = table */
1919 struct stktable_key *key;
1920 struct connection *conn = objt_conn(sess->origin);
1921 struct sample smp;
1922
1923 if (!conn)
1924 return NULL;
1925
1926 /* Fetch source adress in a sample. */
1927 smp.px = NULL;
1928 smp.sess = sess;
1929 smp.strm = strm;
1930 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1931 return NULL;
1932
1933 /* Converts into key. */
1934 key = smp_to_stkey(&smp, &args->data.prx->table);
1935 if (!key)
1936 return NULL;
1937
Emeric Brun819fc6f2017-06-13 19:37:32 +02001938 stkctr->table = &args->data.prx->table;
1939 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1940 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001941 }
1942
1943 /* Here, <num> contains the counter number from 0 to 9 for
1944 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1945 * args[arg] is the first optional argument. We first lookup the
1946 * ctr form the stream, then from the session if it was not there.
1947 */
1948
1949 if (strm)
1950 stkptr = &strm->stkctr[num];
1951 if (!strm || !stkctr_entry(stkptr)) {
1952 stkptr = &sess->stkctr[num];
1953 if (!stkctr_entry(stkptr))
1954 return NULL;
1955 }
1956
1957 stksess = stkctr_entry(stkptr);
1958 if (!stksess)
1959 return NULL;
1960
1961 if (unlikely(args[arg].type == ARGT_TAB)) {
1962 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001963 stkctr->table = &args[arg].data.prx->table;
1964 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1965 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001966 }
1967 return stkptr;
1968}
1969
1970/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1971 * the entry if it doesn't exist yet. This is needed for a few fetch
1972 * functions which need to create an entry, such as src_inc_gpc* and
1973 * src_clr_gpc*.
1974 */
1975struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001976smp_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 +01001977{
Willy Tarreau7d562212016-11-25 16:10:05 +01001978 struct stktable_key *key;
1979 struct connection *conn = objt_conn(sess->origin);
1980 struct sample smp;
1981
1982 if (strncmp(kw, "src_", 4) != 0)
1983 return NULL;
1984
1985 if (!conn)
1986 return NULL;
1987
1988 /* Fetch source adress in a sample. */
1989 smp.px = NULL;
1990 smp.sess = sess;
1991 smp.strm = strm;
1992 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1993 return NULL;
1994
1995 /* Converts into key. */
1996 key = smp_to_stkey(&smp, &args->data.prx->table);
1997 if (!key)
1998 return NULL;
1999
Emeric Brun819fc6f2017-06-13 19:37:32 +02002000 stkctr->table = &args->data.prx->table;
2001 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2002 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002003}
2004
2005/* set return a boolean indicating if the requested stream counter is
2006 * currently being tracked or not.
2007 * Supports being called as "sc[0-9]_tracked" only.
2008 */
2009static int
2010smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2011{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002012 struct stkctr tmpstkctr;
2013 struct stkctr *stkctr;
2014
Willy Tarreau7d562212016-11-25 16:10:05 +01002015 smp->flags = SMP_F_VOL_TEST;
2016 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002017 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2018 smp->data.u.sint = !!stkctr;
2019
2020 /* release the ref count */
Dirkjan Bussinkff57f1b2018-09-14 14:31:22 +02002021 if (stkctr == &tmpstkctr)
Emeric Brun819fc6f2017-06-13 19:37:32 +02002022 stktable_release(stkctr->table, stkctr_entry(stkctr));
2023
Willy Tarreau7d562212016-11-25 16:10:05 +01002024 return 1;
2025}
2026
2027/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2028 * frontend counters or from the src.
2029 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2030 * zero is returned if the key is new.
2031 */
2032static int
2033smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2034{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002035 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002036 struct stkctr *stkctr;
2037
Emeric Brun819fc6f2017-06-13 19:37:32 +02002038 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002039 if (!stkctr)
2040 return 0;
2041
2042 smp->flags = SMP_F_VOL_TEST;
2043 smp->data.type = SMP_T_SINT;
2044 smp->data.u.sint = 0;
2045
Emeric Brun819fc6f2017-06-13 19:37:32 +02002046 if (stkctr_entry(stkctr)) {
2047 void *ptr;
2048
2049 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2050 if (!ptr) {
2051 if (stkctr == &tmpstkctr)
2052 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002053 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002054 }
2055
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002056 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002057
Willy Tarreau7d562212016-11-25 16:10:05 +01002058 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002059
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002060 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002061
2062 if (stkctr == &tmpstkctr)
2063 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002064 }
2065 return 1;
2066}
2067
2068/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2069 * frontend counters or from the src.
2070 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2071 * zero is returned if the key is new.
2072 */
2073static int
2074smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2075{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002076 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002077 struct stkctr *stkctr;
2078
Emeric Brun819fc6f2017-06-13 19:37:32 +02002079 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002080 if (!stkctr)
2081 return 0;
2082
2083 smp->flags = SMP_F_VOL_TEST;
2084 smp->data.type = SMP_T_SINT;
2085 smp->data.u.sint = 0;
2086
2087 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002088 void *ptr;
2089
2090 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2091 if (!ptr) {
2092 if (stkctr == &tmpstkctr)
2093 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002094 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002095 }
2096
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002097 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002098
Willy Tarreau7d562212016-11-25 16:10:05 +01002099 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002100
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002101 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002102
2103 if (stkctr == &tmpstkctr)
2104 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002105 }
2106 return 1;
2107}
2108
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002109/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2110 * frontend counters or from the src.
2111 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2112 * zero is returned if the key is new.
2113 */
2114static int
2115smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2116{
2117 struct stkctr tmpstkctr;
2118 struct stkctr *stkctr;
2119
2120 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2121 if (!stkctr)
2122 return 0;
2123
2124 smp->flags = SMP_F_VOL_TEST;
2125 smp->data.type = SMP_T_SINT;
2126 smp->data.u.sint = 0;
2127
2128 if (stkctr_entry(stkctr) != NULL) {
2129 void *ptr;
2130
2131 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2132 if (!ptr) {
2133 if (stkctr == &tmpstkctr)
2134 stktable_release(stkctr->table, stkctr_entry(stkctr));
2135 return 0; /* parameter not stored */
2136 }
2137
2138 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2139
2140 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2141
2142 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2143
2144 if (stkctr == &tmpstkctr)
2145 stktable_release(stkctr->table, stkctr_entry(stkctr));
2146 }
2147 return 1;
2148}
2149
Willy Tarreau7d562212016-11-25 16:10:05 +01002150/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2151 * tracked frontend counters or from the src.
2152 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2153 * Value zero is returned if the key is new.
2154 */
2155static int
2156smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2157{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002158 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002159 struct stkctr *stkctr;
2160
Emeric Brun819fc6f2017-06-13 19:37:32 +02002161 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002162 if (!stkctr)
2163 return 0;
2164
2165 smp->flags = SMP_F_VOL_TEST;
2166 smp->data.type = SMP_T_SINT;
2167 smp->data.u.sint = 0;
2168 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002169 void *ptr;
2170
2171 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2172 if (!ptr) {
2173 if (stkctr == &tmpstkctr)
2174 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002175 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002176 }
2177
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002178 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002179
Willy Tarreau7d562212016-11-25 16:10:05 +01002180 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2181 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002182
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002183 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002184
2185 if (stkctr == &tmpstkctr)
2186 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002187 }
2188 return 1;
2189}
2190
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002191/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2192 * tracked frontend counters or from the src.
2193 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2194 * Value zero is returned if the key is new.
2195 */
2196static int
2197smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2198{
2199 struct stkctr tmpstkctr;
2200 struct stkctr *stkctr;
2201
2202 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2203 if (!stkctr)
2204 return 0;
2205
2206 smp->flags = SMP_F_VOL_TEST;
2207 smp->data.type = SMP_T_SINT;
2208 smp->data.u.sint = 0;
2209 if (stkctr_entry(stkctr) != NULL) {
2210 void *ptr;
2211
2212 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2213 if (!ptr) {
2214 if (stkctr == &tmpstkctr)
2215 stktable_release(stkctr->table, stkctr_entry(stkctr));
2216 return 0; /* parameter not stored */
2217 }
2218
2219 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2220
2221 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2222 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2223
2224 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2225
2226 if (stkctr == &tmpstkctr)
2227 stktable_release(stkctr->table, stkctr_entry(stkctr));
2228 }
2229 return 1;
2230}
2231
Willy Tarreau7d562212016-11-25 16:10:05 +01002232/* Increment the General Purpose Counter 0 value from the stream's tracked
2233 * frontend counters and return it into temp integer.
2234 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2235 */
2236static int
2237smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2238{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002239 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002240 struct stkctr *stkctr;
2241
Emeric Brun819fc6f2017-06-13 19:37:32 +02002242 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002243 if (!stkctr)
2244 return 0;
2245
2246 smp->flags = SMP_F_VOL_TEST;
2247 smp->data.type = SMP_T_SINT;
2248 smp->data.u.sint = 0;
2249
Emeric Brun819fc6f2017-06-13 19:37:32 +02002250 if (!stkctr_entry(stkctr))
2251 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002252
2253 if (stkctr && stkctr_entry(stkctr)) {
2254 void *ptr1,*ptr2;
2255
Emeric Brun819fc6f2017-06-13 19:37:32 +02002256
Willy Tarreau7d562212016-11-25 16:10:05 +01002257 /* First, update gpc0_rate if it's tracked. Second, update its
2258 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2259 */
2260 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002261 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002262 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002263 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002264
Emeric Brun819fc6f2017-06-13 19:37:32 +02002265 if (ptr1) {
2266 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2267 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2268 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2269 }
2270
2271 if (ptr2)
2272 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2273
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002274 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002275
2276 /* If data was modified, we need to touch to re-schedule sync */
2277 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2278 }
2279 else if (stkctr == &tmpstkctr)
2280 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002281 }
2282 return 1;
2283}
2284
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002285/* Increment the General Purpose Counter 1 value from the stream's tracked
2286 * frontend counters and return it into temp integer.
2287 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2288 */
2289static int
2290smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2291{
2292 struct stkctr tmpstkctr;
2293 struct stkctr *stkctr;
2294
2295 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2296 if (!stkctr)
2297 return 0;
2298
2299 smp->flags = SMP_F_VOL_TEST;
2300 smp->data.type = SMP_T_SINT;
2301 smp->data.u.sint = 0;
2302
2303 if (!stkctr_entry(stkctr))
2304 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2305
2306 if (stkctr && stkctr_entry(stkctr)) {
2307 void *ptr1,*ptr2;
2308
2309
2310 /* First, update gpc1_rate if it's tracked. Second, update its
2311 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2312 */
2313 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2314 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2315 if (ptr1 || ptr2) {
2316 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2317
2318 if (ptr1) {
2319 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2320 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2321 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2322 }
2323
2324 if (ptr2)
2325 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2326
2327 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2328
2329 /* If data was modified, we need to touch to re-schedule sync */
2330 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2331 }
2332 else if (stkctr == &tmpstkctr)
2333 stktable_release(stkctr->table, stkctr_entry(stkctr));
2334 }
2335 return 1;
2336}
2337
Willy Tarreau7d562212016-11-25 16:10:05 +01002338/* Clear the General Purpose Counter 0 value from the stream's tracked
2339 * frontend counters and return its previous value into temp integer.
2340 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2341 */
2342static int
2343smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2344{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002345 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002346 struct stkctr *stkctr;
2347
Emeric Brun819fc6f2017-06-13 19:37:32 +02002348 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002349 if (!stkctr)
2350 return 0;
2351
2352 smp->flags = SMP_F_VOL_TEST;
2353 smp->data.type = SMP_T_SINT;
2354 smp->data.u.sint = 0;
2355
Emeric Brun819fc6f2017-06-13 19:37:32 +02002356 if (!stkctr_entry(stkctr))
2357 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002358
Emeric Brun819fc6f2017-06-13 19:37:32 +02002359 if (stkctr && stkctr_entry(stkctr)) {
2360 void *ptr;
2361
2362 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2363 if (!ptr) {
2364 if (stkctr == &tmpstkctr)
2365 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002366 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002367 }
2368
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002369 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002370
Willy Tarreau7d562212016-11-25 16:10:05 +01002371 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2372 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002373
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002374 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002375
Willy Tarreau7d562212016-11-25 16:10:05 +01002376 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002377 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002378 }
2379 return 1;
2380}
2381
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002382/* Clear the General Purpose Counter 1 value from the stream's tracked
2383 * frontend counters and return its previous value into temp integer.
2384 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2385 */
2386static int
2387smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2388{
2389 struct stkctr tmpstkctr;
2390 struct stkctr *stkctr;
2391
2392 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2393 if (!stkctr)
2394 return 0;
2395
2396 smp->flags = SMP_F_VOL_TEST;
2397 smp->data.type = SMP_T_SINT;
2398 smp->data.u.sint = 0;
2399
2400 if (!stkctr_entry(stkctr))
2401 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2402
2403 if (stkctr && stkctr_entry(stkctr)) {
2404 void *ptr;
2405
2406 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2407 if (!ptr) {
2408 if (stkctr == &tmpstkctr)
2409 stktable_release(stkctr->table, stkctr_entry(stkctr));
2410 return 0; /* parameter not stored */
2411 }
2412
2413 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2414
2415 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2416 stktable_data_cast(ptr, gpc1) = 0;
2417
2418 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2419
2420 /* If data was modified, we need to touch to re-schedule sync */
2421 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2422 }
2423 return 1;
2424}
2425
Willy Tarreau7d562212016-11-25 16:10:05 +01002426/* set <smp> to the cumulated number of connections from the stream's tracked
2427 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2428 * "src_conn_cnt" only.
2429 */
2430static int
2431smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2432{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002433 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002434 struct stkctr *stkctr;
2435
Emeric Brun819fc6f2017-06-13 19:37:32 +02002436 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002437 if (!stkctr)
2438 return 0;
2439
2440 smp->flags = SMP_F_VOL_TEST;
2441 smp->data.type = SMP_T_SINT;
2442 smp->data.u.sint = 0;
2443 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002444 void *ptr;
2445
2446 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2447 if (!ptr) {
2448 if (stkctr == &tmpstkctr)
2449 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002450 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002451 }
2452
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002453 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002454
Willy Tarreau7d562212016-11-25 16:10:05 +01002455 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002456
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002457 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002458
2459 if (stkctr == &tmpstkctr)
2460 stktable_release(stkctr->table, stkctr_entry(stkctr));
2461
2462
Willy Tarreau7d562212016-11-25 16:10:05 +01002463 }
2464 return 1;
2465}
2466
2467/* set <smp> to the connection rate from the stream's tracked frontend
2468 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2469 * only.
2470 */
2471static int
2472smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2473{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002474 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002475 struct stkctr *stkctr;
2476
Emeric Brun819fc6f2017-06-13 19:37:32 +02002477 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002478 if (!stkctr)
2479 return 0;
2480
2481 smp->flags = SMP_F_VOL_TEST;
2482 smp->data.type = SMP_T_SINT;
2483 smp->data.u.sint = 0;
2484 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002485 void *ptr;
2486
2487 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2488 if (!ptr) {
2489 if (stkctr == &tmpstkctr)
2490 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002491 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002492 }
2493
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002494 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002495
Willy Tarreau7d562212016-11-25 16:10:05 +01002496 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2497 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002498
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002499 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002500
2501 if (stkctr == &tmpstkctr)
2502 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002503 }
2504 return 1;
2505}
2506
2507/* set temp integer to the number of connections from the stream's source address
2508 * in the table pointed to by expr, after updating it.
2509 * Accepts exactly 1 argument of type table.
2510 */
2511static int
2512smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2513{
2514 struct connection *conn = objt_conn(smp->sess->origin);
2515 struct stksess *ts;
2516 struct stktable_key *key;
2517 void *ptr;
2518 struct proxy *px;
2519
2520 if (!conn)
2521 return 0;
2522
2523 /* Fetch source adress in a sample. */
2524 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2525 return 0;
2526
2527 /* Converts into key. */
2528 key = smp_to_stkey(smp, &args->data.prx->table);
2529 if (!key)
2530 return 0;
2531
2532 px = args->data.prx;
2533
Emeric Brun819fc6f2017-06-13 19:37:32 +02002534 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002535 /* entry does not exist and could not be created */
2536 return 0;
2537
2538 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002539 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002540 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002541 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002542
2543 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002544
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002545 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002546
Willy Tarreau7d562212016-11-25 16:10:05 +01002547 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002548
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002549 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550
Willy Tarreau7d562212016-11-25 16:10:05 +01002551 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002552
2553 stktable_touch_local(&px->table, ts, 1);
2554
2555 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002556 return 1;
2557}
2558
2559/* set <smp> to the number of concurrent connections from the stream's tracked
2560 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2561 * "src_conn_cur" only.
2562 */
2563static int
2564smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2565{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002566 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002567 struct stkctr *stkctr;
2568
Emeric Brun819fc6f2017-06-13 19:37:32 +02002569 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002570 if (!stkctr)
2571 return 0;
2572
2573 smp->flags = SMP_F_VOL_TEST;
2574 smp->data.type = SMP_T_SINT;
2575 smp->data.u.sint = 0;
2576 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002577 void *ptr;
2578
2579 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2580 if (!ptr) {
2581 if (stkctr == &tmpstkctr)
2582 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002583 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002584 }
2585
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002586 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002587
Willy Tarreau7d562212016-11-25 16:10:05 +01002588 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002589
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002590 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002591
2592 if (stkctr == &tmpstkctr)
2593 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002594 }
2595 return 1;
2596}
2597
2598/* set <smp> to the cumulated number of streams from the stream's tracked
2599 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2600 * "src_sess_cnt" only.
2601 */
2602static int
2603smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2604{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002605 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002606 struct stkctr *stkctr;
2607
Emeric Brun819fc6f2017-06-13 19:37:32 +02002608 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002609 if (!stkctr)
2610 return 0;
2611
2612 smp->flags = SMP_F_VOL_TEST;
2613 smp->data.type = SMP_T_SINT;
2614 smp->data.u.sint = 0;
2615 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002616 void *ptr;
2617
2618 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2619 if (!ptr) {
2620 if (stkctr == &tmpstkctr)
2621 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002622 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002623 }
2624
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002625 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002626
Willy Tarreau7d562212016-11-25 16:10:05 +01002627 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002628
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002629 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002630
2631 if (stkctr == &tmpstkctr)
2632 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002633 }
2634 return 1;
2635}
2636
2637/* set <smp> to the stream rate from the stream's tracked frontend counters.
2638 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2639 */
2640static int
2641smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2642{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002643 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002644 struct stkctr *stkctr;
2645
Emeric Brun819fc6f2017-06-13 19:37:32 +02002646 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002647 if (!stkctr)
2648 return 0;
2649
2650 smp->flags = SMP_F_VOL_TEST;
2651 smp->data.type = SMP_T_SINT;
2652 smp->data.u.sint = 0;
2653 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002654 void *ptr;
2655
2656 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2657 if (!ptr) {
2658 if (stkctr == &tmpstkctr)
2659 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002660 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002661 }
2662
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002663 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002664
Willy Tarreau7d562212016-11-25 16:10:05 +01002665 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2666 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002667
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002668 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002669
2670 if (stkctr == &tmpstkctr)
2671 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002672 }
2673 return 1;
2674}
2675
2676/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2677 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2678 * "src_http_req_cnt" only.
2679 */
2680static int
2681smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2682{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002683 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002684 struct stkctr *stkctr;
2685
Emeric Brun819fc6f2017-06-13 19:37:32 +02002686 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002687 if (!stkctr)
2688 return 0;
2689
2690 smp->flags = SMP_F_VOL_TEST;
2691 smp->data.type = SMP_T_SINT;
2692 smp->data.u.sint = 0;
2693 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002694 void *ptr;
2695
2696 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2697 if (!ptr) {
2698 if (stkctr == &tmpstkctr)
2699 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002700 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002701 }
2702
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002703 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002704
Willy Tarreau7d562212016-11-25 16:10:05 +01002705 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002706
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002707 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002708
2709 if (stkctr == &tmpstkctr)
2710 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002711 }
2712 return 1;
2713}
2714
2715/* set <smp> to the HTTP request rate from the stream's tracked frontend
2716 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2717 * "src_http_req_rate" only.
2718 */
2719static int
2720smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2721{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002722 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002723 struct stkctr *stkctr;
2724
Emeric Brun819fc6f2017-06-13 19:37:32 +02002725 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002726 if (!stkctr)
2727 return 0;
2728
2729 smp->flags = SMP_F_VOL_TEST;
2730 smp->data.type = SMP_T_SINT;
2731 smp->data.u.sint = 0;
2732 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002733 void *ptr;
2734
2735 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2736 if (!ptr) {
2737 if (stkctr == &tmpstkctr)
2738 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002739 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002740 }
2741
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002742 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002743
Willy Tarreau7d562212016-11-25 16:10:05 +01002744 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2745 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002747 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002748
2749 if (stkctr == &tmpstkctr)
2750 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002751 }
2752 return 1;
2753}
2754
2755/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2756 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2757 * "src_http_err_cnt" only.
2758 */
2759static int
2760smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2761{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002762 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002763 struct stkctr *stkctr;
2764
Emeric Brun819fc6f2017-06-13 19:37:32 +02002765 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002766 if (!stkctr)
2767 return 0;
2768
2769 smp->flags = SMP_F_VOL_TEST;
2770 smp->data.type = SMP_T_SINT;
2771 smp->data.u.sint = 0;
2772 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002773 void *ptr;
2774
2775 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2776 if (!ptr) {
2777 if (stkctr == &tmpstkctr)
2778 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002779 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002780 }
2781
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002782 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002783
Willy Tarreau7d562212016-11-25 16:10:05 +01002784 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002785
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002786 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002787
2788 if (stkctr == &tmpstkctr)
2789 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002790 }
2791 return 1;
2792}
2793
2794/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2795 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2796 * "src_http_err_rate" only.
2797 */
2798static int
2799smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2800{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002801 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002802 struct stkctr *stkctr;
2803
Emeric Brun819fc6f2017-06-13 19:37:32 +02002804 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002805 if (!stkctr)
2806 return 0;
2807
2808 smp->flags = SMP_F_VOL_TEST;
2809 smp->data.type = SMP_T_SINT;
2810 smp->data.u.sint = 0;
2811 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002812 void *ptr;
2813
2814 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2815 if (!ptr) {
2816 if (stkctr == &tmpstkctr)
2817 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002818 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002819 }
2820
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002821 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002822
Willy Tarreau7d562212016-11-25 16:10:05 +01002823 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2824 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002825
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002826 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002827
2828 if (stkctr == &tmpstkctr)
2829 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002830 }
2831 return 1;
2832}
2833
2834/* set <smp> to the number of kbytes received from clients, as found in the
2835 * stream's tracked frontend counters. Supports being called as
2836 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2837 */
2838static int
2839smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2840{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002841 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002842 struct stkctr *stkctr;
2843
Emeric Brun819fc6f2017-06-13 19:37:32 +02002844 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002845 if (!stkctr)
2846 return 0;
2847
2848 smp->flags = SMP_F_VOL_TEST;
2849 smp->data.type = SMP_T_SINT;
2850 smp->data.u.sint = 0;
2851 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002852 void *ptr;
2853
2854 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2855 if (!ptr) {
2856 if (stkctr == &tmpstkctr)
2857 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002858 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002859 }
2860
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002861 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002862
Willy Tarreau7d562212016-11-25 16:10:05 +01002863 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002864
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002865 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002866
2867 if (stkctr == &tmpstkctr)
2868 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002869 }
2870 return 1;
2871}
2872
2873/* set <smp> to the data rate received from clients in bytes/s, as found
2874 * in the stream's tracked frontend counters. Supports being called as
2875 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2876 */
2877static int
2878smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2879{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002880 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002881 struct stkctr *stkctr;
2882
Emeric Brun819fc6f2017-06-13 19:37:32 +02002883 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002884 if (!stkctr)
2885 return 0;
2886
2887 smp->flags = SMP_F_VOL_TEST;
2888 smp->data.type = SMP_T_SINT;
2889 smp->data.u.sint = 0;
2890 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002891 void *ptr;
2892
2893 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2894 if (!ptr) {
2895 if (stkctr == &tmpstkctr)
2896 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002897 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002898 }
2899
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002900 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002901
Willy Tarreau7d562212016-11-25 16:10:05 +01002902 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2903 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002904
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002905 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002906
2907 if (stkctr == &tmpstkctr)
2908 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002909 }
2910 return 1;
2911}
2912
2913/* set <smp> to the number of kbytes sent to clients, as found in the
2914 * stream's tracked frontend counters. Supports being called as
2915 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2916 */
2917static int
2918smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2919{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002920 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002921 struct stkctr *stkctr;
2922
Emeric Brun819fc6f2017-06-13 19:37:32 +02002923 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002924 if (!stkctr)
2925 return 0;
2926
2927 smp->flags = SMP_F_VOL_TEST;
2928 smp->data.type = SMP_T_SINT;
2929 smp->data.u.sint = 0;
2930 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002931 void *ptr;
2932
2933 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2934 if (!ptr) {
2935 if (stkctr == &tmpstkctr)
2936 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002937 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002938 }
2939
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002940 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002941
Willy Tarreau7d562212016-11-25 16:10:05 +01002942 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002943
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002944 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002945
2946 if (stkctr == &tmpstkctr)
2947 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002948 }
2949 return 1;
2950}
2951
2952/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2953 * stream's tracked frontend counters. Supports being called as
2954 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2955 */
2956static int
2957smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2958{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002959 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002960 struct stkctr *stkctr;
2961
Emeric Brun819fc6f2017-06-13 19:37:32 +02002962 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002963 if (!stkctr)
2964 return 0;
2965
2966 smp->flags = SMP_F_VOL_TEST;
2967 smp->data.type = SMP_T_SINT;
2968 smp->data.u.sint = 0;
2969 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002970 void *ptr;
2971
2972 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2973 if (!ptr) {
2974 if (stkctr == &tmpstkctr)
2975 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002976 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002977 }
2978
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002979 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002980
Willy Tarreau7d562212016-11-25 16:10:05 +01002981 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2982 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002983
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002984 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002985
2986 if (stkctr == &tmpstkctr)
2987 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002988 }
2989 return 1;
2990}
2991
2992/* set <smp> to the number of active trackers on the SC entry in the stream's
2993 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2994 */
2995static int
2996smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2997{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002998 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002999 struct stkctr *stkctr;
3000
Emeric Brun819fc6f2017-06-13 19:37:32 +02003001 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003002 if (!stkctr)
3003 return 0;
3004
3005 smp->flags = SMP_F_VOL_TEST;
3006 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003007 if (stkctr == &tmpstkctr) {
3008 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3009 stktable_release(stkctr->table, stkctr_entry(stkctr));
3010 }
3011 else {
3012 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3013 }
3014
Willy Tarreau7d562212016-11-25 16:10:05 +01003015 return 1;
3016}
3017
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003018
3019/* The functions below are used to manipulate table contents from the CLI.
3020 * There are 3 main actions, "clear", "set" and "show". The code is shared
3021 * between all actions, and the action is encoded in the void *private in
3022 * the appctx as well as in the keyword registration, among one of the
3023 * following values.
3024 */
3025
3026enum {
3027 STK_CLI_ACT_CLR,
3028 STK_CLI_ACT_SET,
3029 STK_CLI_ACT_SHOW,
3030};
3031
3032/* Dump the status of a table to a stream interface's
3033 * read buffer. It returns 0 if the output buffer is full
3034 * and needs to be called again, otherwise non-zero.
3035 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003036static int table_dump_head_to_buffer(struct buffer *msg,
3037 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003038 struct proxy *proxy, struct proxy *target)
3039{
3040 struct stream *s = si_strm(si);
3041
3042 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3043 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3044
3045 /* any other information should be dumped here */
3046
William Lallemand07a62f72017-05-24 00:57:40 +02003047 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003048 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3049
Willy Tarreau06d80a92017-10-19 14:32:15 +02003050 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003051 si_cant_put(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003052 return 0;
3053 }
3054
3055 return 1;
3056}
3057
3058/* Dump a table entry to a stream interface's
3059 * read buffer. It returns 0 if the output buffer is full
3060 * and needs to be called again, otherwise non-zero.
3061 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003062static int table_dump_entry_to_buffer(struct buffer *msg,
3063 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003064 struct proxy *proxy, struct stksess *entry)
3065{
3066 int dt;
3067
3068 chunk_appendf(msg, "%p:", entry);
3069
3070 if (proxy->table.type == SMP_T_IPV4) {
3071 char addr[INET_ADDRSTRLEN];
3072 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3073 chunk_appendf(msg, " key=%s", addr);
3074 }
3075 else if (proxy->table.type == SMP_T_IPV6) {
3076 char addr[INET6_ADDRSTRLEN];
3077 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3078 chunk_appendf(msg, " key=%s", addr);
3079 }
3080 else if (proxy->table.type == SMP_T_SINT) {
3081 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3082 }
3083 else if (proxy->table.type == SMP_T_STR) {
3084 chunk_appendf(msg, " key=");
3085 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3086 }
3087 else {
3088 chunk_appendf(msg, " key=");
3089 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3090 }
3091
3092 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3093
3094 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3095 void *ptr;
3096
3097 if (proxy->table.data_ofs[dt] == 0)
3098 continue;
3099 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3100 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3101 else
3102 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3103
3104 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3105 switch (stktable_data_types[dt].std_type) {
3106 case STD_T_SINT:
3107 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3108 break;
3109 case STD_T_UINT:
3110 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3111 break;
3112 case STD_T_ULL:
3113 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3114 break;
3115 case STD_T_FRQP:
3116 chunk_appendf(msg, "%d",
3117 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3118 proxy->table.data_arg[dt].u));
3119 break;
3120 }
3121 }
3122 chunk_appendf(msg, "\n");
3123
Willy Tarreau06d80a92017-10-19 14:32:15 +02003124 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003125 si_cant_put(si);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003126 return 0;
3127 }
3128
3129 return 1;
3130}
3131
3132
3133/* Processes a single table entry matching a specific key passed in argument.
3134 * returns 0 if wants to be called again, 1 if has ended processing.
3135 */
3136static int table_process_entry_per_key(struct appctx *appctx, char **args)
3137{
3138 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003139 struct proxy *px = appctx->ctx.table.target;
3140 struct stksess *ts;
3141 uint32_t uint32_key;
3142 unsigned char ip6_key[sizeof(struct in6_addr)];
3143 long long value;
3144 int data_type;
3145 int cur_arg;
3146 void *ptr;
3147 struct freq_ctr_period *frqp;
3148
3149 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003150 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003151 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003152 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003153 return 1;
3154 }
3155
3156 switch (px->table.type) {
3157 case SMP_T_IPV4:
3158 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003159 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003160 break;
3161 case SMP_T_IPV6:
3162 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003163 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003164 break;
3165 case SMP_T_SINT:
3166 {
3167 char *endptr;
3168 unsigned long val;
3169 errno = 0;
3170 val = strtoul(args[4], &endptr, 10);
3171 if ((errno == ERANGE && val == ULONG_MAX) ||
3172 (errno != 0 && val == 0) || endptr == args[4] ||
3173 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003174 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003175 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003176 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003177 return 1;
3178 }
3179 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003180 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003181 break;
3182 }
3183 break;
3184 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003185 static_table_key.key = args[4];
3186 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003187 break;
3188 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003189 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003190 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003191 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003192 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3193 break;
3194 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003195 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003196 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3197 break;
3198 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003199 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003200 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3201 break;
3202 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003203 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003204 appctx->ctx.cli.msg = "Unknown action\n";
3205 break;
3206 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003207 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003208 return 1;
3209 }
3210
3211 /* check permissions */
3212 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3213 return 1;
3214
Willy Tarreaua24bc782016-12-14 15:50:35 +01003215 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003216 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003217 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003218 if (!ts)
3219 return 1;
3220 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003221 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3222 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003223 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003224 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003225 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003226 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003227 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003229 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003231 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003232 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003233 break;
3234
3235 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003236 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003237 if (!ts)
3238 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003239
3240 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003241 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003242 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003243 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003244 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003245 return 1;
3246 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003247
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003248 break;
3249
3250 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003251 ts = stktable_get_entry(&px->table, &static_table_key);
3252 if (!ts) {
3253 /* don't delete an entry which is currently referenced */
3254 appctx->ctx.cli.severity = LOG_ERR;
3255 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3256 appctx->st0 = CLI_ST_PRINT;
3257 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003258 }
3259
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003260 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003261 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3262 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003263 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003264 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003265 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003266 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003267 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003268 return 1;
3269 }
3270
3271 data_type = stktable_get_data_type(args[cur_arg] + 5);
3272 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003273 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003274 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003275 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003276 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003277 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003278 return 1;
3279 }
3280
3281 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003282 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003283 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003284 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003285 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003286 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003287 return 1;
3288 }
3289
3290 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003291 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003292 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003293 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003294 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003295 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003296 return 1;
3297 }
3298
3299 ptr = stktable_data_ptr(&px->table, ts, data_type);
3300
3301 switch (stktable_data_types[data_type].std_type) {
3302 case STD_T_SINT:
3303 stktable_data_cast(ptr, std_t_sint) = value;
3304 break;
3305 case STD_T_UINT:
3306 stktable_data_cast(ptr, std_t_uint) = value;
3307 break;
3308 case STD_T_ULL:
3309 stktable_data_cast(ptr, std_t_ull) = value;
3310 break;
3311 case STD_T_FRQP:
3312 /* We set both the current and previous values. That way
3313 * the reported frequency is stable during all the period
3314 * then slowly fades out. This allows external tools to
3315 * push measures without having to update them too often.
3316 */
3317 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003318 /* First bit is reserved for the freq_ctr_period lock
3319 Note: here we're still protected by the stksess lock
3320 so we don't need to update the update the freq_ctr_period
3321 using its internal lock */
3322 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003323 frqp->prev_ctr = 0;
3324 frqp->curr_ctr = value;
3325 break;
3326 }
3327 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003328 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003329 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003330 break;
3331
3332 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003333 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003334 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003335 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003336 break;
3337 }
3338 return 1;
3339}
3340
3341/* Prepares the appctx fields with the data-based filters from the command line.
3342 * Returns 0 if the dump can proceed, 1 if has ended processing.
3343 */
3344static int table_prepare_data_request(struct appctx *appctx, char **args)
3345{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003346 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003347 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003348 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003349 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003350 return 1;
3351 }
3352
3353 /* condition on stored data value */
3354 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3355 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003356 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003357 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003358 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003359 return 1;
3360 }
3361
3362 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003363 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003364 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003365 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003366 return 1;
3367 }
3368
3369 appctx->ctx.table.data_op = get_std_op(args[4]);
3370 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003371 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003372 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003373 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003374 return 1;
3375 }
3376
3377 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003378 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003379 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003380 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003381 return 1;
3382 }
3383
3384 /* OK we're done, all the fields are set */
3385 return 0;
3386}
3387
3388/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003389static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003390{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003391 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003392 appctx->ctx.table.target = NULL;
3393 appctx->ctx.table.proxy = NULL;
3394 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003395 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003396
3397 if (*args[2]) {
3398 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3399 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003400 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003401 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003402 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003403 return 1;
3404 }
3405 }
3406 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003407 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003408 goto err_args;
3409 return 0;
3410 }
3411
3412 if (strcmp(args[3], "key") == 0)
3413 return table_process_entry_per_key(appctx, args);
3414 else if (strncmp(args[3], "data.", 5) == 0)
3415 return table_prepare_data_request(appctx, args);
3416 else if (*args[3])
3417 goto err_args;
3418
3419 return 0;
3420
3421err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003422 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003423 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003424 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003425 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3426 break;
3427 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003428 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003429 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3430 break;
3431 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003432 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003433 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3434 break;
3435 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003436 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003437 appctx->ctx.cli.msg = "Unknown action\n";
3438 break;
3439 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003440 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003441 return 1;
3442}
3443
3444/* This function is used to deal with table operations (dump or clear depending
3445 * on the action stored in appctx->private). It returns 0 if the output buffer is
3446 * full and it needs to be called again, otherwise non-zero.
3447 */
3448static int cli_io_handler_table(struct appctx *appctx)
3449{
3450 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003451 struct stream *s = si_strm(si);
3452 struct ebmb_node *eb;
3453 int dt;
3454 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003455 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003456
3457 /*
3458 * We have 3 possible states in appctx->st2 :
3459 * - STAT_ST_INIT : the first call
3460 * - STAT_ST_INFO : the proxy pointer points to the next table to
3461 * dump, the entry pointer is NULL ;
3462 * - STAT_ST_LIST : the proxy pointer points to the current table
3463 * and the entry pointer points to the next entry to be dumped,
3464 * and the refcount on the next entry is held ;
3465 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3466 * data though.
3467 */
3468
3469 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3470 /* in case of abort, remove any refcount we might have set on an entry */
3471 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003472 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003473 }
3474 return 1;
3475 }
3476
3477 chunk_reset(&trash);
3478
3479 while (appctx->st2 != STAT_ST_FIN) {
3480 switch (appctx->st2) {
3481 case STAT_ST_INIT:
3482 appctx->ctx.table.proxy = appctx->ctx.table.target;
3483 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003484 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003485
3486 appctx->ctx.table.entry = NULL;
3487 appctx->st2 = STAT_ST_INFO;
3488 break;
3489
3490 case STAT_ST_INFO:
3491 if (!appctx->ctx.table.proxy ||
3492 (appctx->ctx.table.target &&
3493 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3494 appctx->st2 = STAT_ST_END;
3495 break;
3496 }
3497
3498 if (appctx->ctx.table.proxy->table.size) {
3499 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3500 return 0;
3501
3502 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003503 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003504 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003505 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003506 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3507 if (eb) {
3508 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3509 appctx->ctx.table.entry->ref_cnt++;
3510 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003511 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003512 break;
3513 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003514 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003515 }
3516 }
3517 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3518 break;
3519
3520 case STAT_ST_LIST:
3521 skip_entry = 0;
3522
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003523 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003524
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003525 if (appctx->ctx.table.data_type >= 0) {
3526 /* we're filtering on some data contents */
3527 void *ptr;
3528 long long data;
3529
Emeric Brun819fc6f2017-06-13 19:37:32 +02003530
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003531 dt = appctx->ctx.table.data_type;
3532 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3533 appctx->ctx.table.entry,
3534 dt);
3535
3536 data = 0;
3537 switch (stktable_data_types[dt].std_type) {
3538 case STD_T_SINT:
3539 data = stktable_data_cast(ptr, std_t_sint);
3540 break;
3541 case STD_T_UINT:
3542 data = stktable_data_cast(ptr, std_t_uint);
3543 break;
3544 case STD_T_ULL:
3545 data = stktable_data_cast(ptr, std_t_ull);
3546 break;
3547 case STD_T_FRQP:
3548 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3549 appctx->ctx.table.proxy->table.data_arg[dt].u);
3550 break;
3551 }
3552
3553 /* skip the entry if the data does not match the test and the value */
3554 if ((data < appctx->ctx.table.value &&
3555 (appctx->ctx.table.data_op == STD_OP_EQ ||
3556 appctx->ctx.table.data_op == STD_OP_GT ||
3557 appctx->ctx.table.data_op == STD_OP_GE)) ||
3558 (data == appctx->ctx.table.value &&
3559 (appctx->ctx.table.data_op == STD_OP_NE ||
3560 appctx->ctx.table.data_op == STD_OP_GT ||
3561 appctx->ctx.table.data_op == STD_OP_LT)) ||
3562 (data > appctx->ctx.table.value &&
3563 (appctx->ctx.table.data_op == STD_OP_EQ ||
3564 appctx->ctx.table.data_op == STD_OP_LT ||
3565 appctx->ctx.table.data_op == STD_OP_LE)))
3566 skip_entry = 1;
3567 }
3568
3569 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003570 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003571 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003572 return 0;
3573 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003574
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003575 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003576
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003577 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003578 appctx->ctx.table.entry->ref_cnt--;
3579
3580 eb = ebmb_next(&appctx->ctx.table.entry->key);
3581 if (eb) {
3582 struct stksess *old = appctx->ctx.table.entry;
3583 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3584 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003585 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003586 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003587 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003588 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003589 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003590 break;
3591 }
3592
3593
3594 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003595 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003596 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003597 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3598
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003599 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003600
3601 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3602 appctx->st2 = STAT_ST_INFO;
3603 break;
3604
3605 case STAT_ST_END:
3606 appctx->st2 = STAT_ST_FIN;
3607 break;
3608 }
3609 }
3610 return 1;
3611}
3612
3613static void cli_release_show_table(struct appctx *appctx)
3614{
3615 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003616 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003617 }
3618}
3619
3620/* register cli keywords */
3621static struct cli_kw_list cli_kws = {{ },{
3622 { { "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 },
3623 { { "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 },
3624 { { "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 },
3625 {{},}
3626}};
3627
3628
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003629static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003630 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003631 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003632 { "sc-set-gpt0", parse_set_gpt0, 1 },
3633 { /* END */ }
3634}};
3635
Willy Tarreau620408f2016-10-21 16:37:51 +02003636static struct action_kw_list tcp_sess_kws = { { }, {
3637 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003638 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003639 { "sc-set-gpt0", parse_set_gpt0, 1 },
3640 { /* END */ }
3641}};
3642
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003643static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003644 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003645 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003646 { "sc-set-gpt0", parse_set_gpt0, 1 },
3647 { /* END */ }
3648}};
3649
3650static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003651 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003652 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003653 { "sc-set-gpt0", parse_set_gpt0, 1 },
3654 { /* END */ }
3655}};
3656
3657static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003658 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003659 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003660 { "sc-set-gpt0", parse_set_gpt0, 1 },
3661 { /* END */ }
3662}};
3663
3664static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003665 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003666 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003667 { "sc-set-gpt0", parse_set_gpt0, 1 },
3668 { /* END */ }
3669}};
3670
Willy Tarreau7d562212016-11-25 16:10:05 +01003671///* Note: must not be declared <const> as its list will be overwritten.
3672// * Please take care of keeping this list alphabetically sorted.
3673// */
3674//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3675// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3676// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3677// { /* END */ },
3678//}};
3679/* Note: must not be declared <const> as its list will be overwritten.
3680 * Please take care of keeping this list alphabetically sorted.
3681 */
3682static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3683 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3684 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3685 { "sc_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003686 { "sc_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
Willy Tarreau7d562212016-11-25 16:10:05 +01003687 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3688 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3689 { "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 +01003690 { "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 +01003691 { "sc_get_gpc0", smp_fetch_sc_get_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003692 { "sc_get_gpc1", smp_fetch_sc_get_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
Willy Tarreau7d562212016-11-25 16:10:05 +01003693 { "sc_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003694 { "sc_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003695 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3696 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3697 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3698 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3699 { "sc_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003700 { "sc_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003701 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3702 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3703 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3704 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3705 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3706 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3707 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3708 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3709 { "sc0_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003710 { "sc0_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003711 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3712 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3713 { "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 +01003714 { "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 +01003715 { "sc0_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003716 { "sc0_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003717 { "sc0_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003718 { "sc0_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003719 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3720 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3721 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3722 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3723 { "sc0_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003724 { "sc0_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003725 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3726 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3727 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3728 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3729 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3730 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3731 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3732 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3733 { "sc1_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003734 { "sc1_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003735 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3736 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3737 { "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 +01003738 { "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 +01003739 { "sc1_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003740 { "sc1_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003741 { "sc1_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003742 { "sc1_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003743 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3744 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3745 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3746 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3747 { "sc1_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003748 { "sc1_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003749 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3750 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3751 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3752 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3753 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3754 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3755 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3756 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3757 { "sc2_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003758 { "sc2_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003759 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3760 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3761 { "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 +01003762 { "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 +01003763 { "sc2_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003764 { "sc2_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003765 { "sc2_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003766 { "sc2_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003767 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3768 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3769 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3770 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3771 { "sc2_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003772 { "sc2_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003773 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3774 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3775 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3776 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3777 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3778 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3779 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3780 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3781 { "src_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003782 { "src_clr_gpc1", smp_fetch_sc_clr_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003783 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3784 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3785 { "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 +01003786 { "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 +01003787 { "src_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003788 { "src_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003789 { "src_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003790 { "src_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003791 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3792 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3793 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3794 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3795 { "src_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003796 { "src_inc_gpc1", smp_fetch_sc_inc_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
Willy Tarreau7d562212016-11-25 16:10:05 +01003797 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3798 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3799 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3800 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3801 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3802 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3803 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3804 { /* END */ },
3805}};
3806
3807
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003808/* Note: must not be declared <const> as its list will be overwritten */
3809static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003810 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3811 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3812 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3813 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3814 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3815 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3816 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3817 { "table_gpc0", sample_conv_table_gpc0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003818 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003819 { "table_gpc0_rate", sample_conv_table_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003820 { "table_gpc1_rate", sample_conv_table_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003821 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3822 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3823 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3824 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3825 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3826 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3827 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3828 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3829 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3830 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003831 { /* END */ },
3832}};
3833
3834__attribute__((constructor))
3835static void __stick_table_init(void)
3836{
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003837 /* register som action keywords. */
3838 tcp_req_conn_keywords_register(&tcp_conn_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +02003839 tcp_req_sess_keywords_register(&tcp_sess_kws);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003840 tcp_req_cont_keywords_register(&tcp_req_kws);
3841 tcp_res_cont_keywords_register(&tcp_res_kws);
3842 http_req_keywords_register(&http_req_kws);
3843 http_res_keywords_register(&http_res_kws);
3844
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003845 /* register sample fetch and format conversion keywords */
Willy Tarreau7d562212016-11-25 16:10:05 +01003846 sample_register_fetches(&smp_fetch_keywords);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003847 sample_register_convs(&sample_conv_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003848 cli_register_kw(&cli_kws);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003849}