blob: d2aea6d9755b9caafa7bb650396c64f7f54f9b57 [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);
Emeric Brun3bd697e2010-01-04 15:23:48 +0100606 t->exp_task->process = process_table_expire;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100607 t->exp_task->context = (void *)t;
608 }
Willy Tarreauc8b67912015-05-01 18:29:57 +0200609 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
Emeric Brun32da3c42010-09-23 18:39:19 +0200610 peers_register_table(t->peers.p, t);
611 }
612
Emeric Brun3bd697e2010-01-04 15:23:48 +0100613 return t->pool != NULL;
614 }
615 return 1;
616}
617
618/*
619 * Configuration keywords of known table types
620 */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200621struct stktable_type stktable_types[SMP_TYPES] = {
622 [SMP_T_SINT] = { "integer", 0, 4 },
623 [SMP_T_IPV4] = { "ip", 0, 4 },
624 [SMP_T_IPV6] = { "ipv6", 0, 16 },
625 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
626 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
627};
Emeric Brun3bd697e2010-01-04 15:23:48 +0100628
629/*
630 * Parse table type configuration.
631 * Returns 0 on successful parsing, else 1.
632 * <myidx> is set at next configuration <args> index.
633 */
634int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
635{
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200636 for (*type = 0; *type < SMP_TYPES; (*type)++) {
637 if (!stktable_types[*type].kw)
638 continue;
Emeric Brun3bd697e2010-01-04 15:23:48 +0100639 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
640 continue;
641
642 *key_size = stktable_types[*type].default_size;
643 (*myidx)++;
644
Willy Tarreauaea940e2010-06-06 11:56:36 +0200645 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
Emeric Brun3bd697e2010-01-04 15:23:48 +0100646 if (strcmp("len", args[*myidx]) == 0) {
647 (*myidx)++;
648 *key_size = atol(args[*myidx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200649 if (!*key_size)
Emeric Brun3bd697e2010-01-04 15:23:48 +0100650 break;
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200651 if (*type == SMP_T_STR) {
Emeric Brun485479d2010-09-23 18:02:19 +0200652 /* null terminated string needs +1 for '\0'. */
653 (*key_size)++;
654 }
Emeric Brun3bd697e2010-01-04 15:23:48 +0100655 (*myidx)++;
656 }
657 }
658 return 0;
659 }
660 return 1;
661}
662
Willy Tarreau8fed9032014-07-03 17:02:46 +0200663/* Prepares a stktable_key from a sample <smp> to search into table <t>.
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200664 * Note that the sample *is* modified and that the returned key may point
665 * to it, so the sample must not be modified afterwards before the lookup.
Willy Tarreau8fed9032014-07-03 17:02:46 +0200666 * Returns NULL if the sample could not be converted (eg: no matching type),
667 * otherwise a pointer to the static stktable_key filled with what is needed
668 * for the lookup.
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200669 */
Willy Tarreau8fed9032014-07-03 17:02:46 +0200670struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200671{
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200672 /* Convert sample. */
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200673 if (!sample_convert(smp, t->type))
Willy Tarreau7fc1c6e2012-04-26 11:03:17 +0200674 return NULL;
675
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200676 /* Fill static_table_key. */
677 switch (t->type) {
Emeric Brun485479d2010-09-23 18:02:19 +0200678
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200679 case SMP_T_IPV4:
Christopher Fauletca20d022017-08-29 15:30:31 +0200680 static_table_key.key = &smp->data.u.ipv4;
681 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200682 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200683
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200684 case SMP_T_IPV6:
Christopher Fauletca20d022017-08-29 15:30:31 +0200685 static_table_key.key = &smp->data.u.ipv6;
686 static_table_key.key_len = 16;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200687 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200688
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200689 case SMP_T_SINT:
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200690 /* The stick table require a 32bit unsigned int, "sint" is a
691 * signed 64 it, so we can convert it inplace.
692 */
693 *(unsigned int *)&smp->data.u.sint = (unsigned int)smp->data.u.sint;
Christopher Fauletca20d022017-08-29 15:30:31 +0200694 static_table_key.key = &smp->data.u.sint;
695 static_table_key.key_len = 4;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200696 break;
697
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200698 case SMP_T_STR:
Willy Tarreauce6955e2016-08-09 11:59:12 +0200699 if (!smp_make_safe(smp))
700 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200701 static_table_key.key = smp->data.u.str.area;
702 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200703 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200704
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200705 case SMP_T_BIN:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200706 if (smp->data.u.str.data < t->key_size) {
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200707 /* This type needs padding with 0. */
Willy Tarreauf65c6c02016-08-09 12:08:41 +0200708 if (!smp_make_rw(smp))
709 return NULL;
710
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200711 if (smp->data.u.str.size < t->key_size)
712 if (!smp_dup(smp))
713 return NULL;
714 if (smp->data.u.str.size < t->key_size)
715 return NULL;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200716 memset(smp->data.u.str.area + smp->data.u.str.data, 0,
717 t->key_size - smp->data.u.str.data);
718 smp->data.u.str.data = t->key_size;
Emeric Brun485479d2010-09-23 18:02:19 +0200719 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200720 static_table_key.key = smp->data.u.str.area;
721 static_table_key.key_len = smp->data.u.str.data;
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200722 break;
Emeric Brun485479d2010-09-23 18:02:19 +0200723
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200724 default: /* impossible case. */
725 return NULL;
Emeric Brun485479d2010-09-23 18:02:19 +0200726 }
727
Christopher Fauletca20d022017-08-29 15:30:31 +0200728 return &static_table_key;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200729}
730
731/*
Willy Tarreau8fed9032014-07-03 17:02:46 +0200732 * Process a fetch + format conversion as defined by the sample expression <expr>
733 * on request or response considering the <opt> parameter. Returns either NULL if
734 * no key could be extracted, or a pointer to the converted result stored in
735 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
736 * and its flags will be initialized so that the caller gets a copy of the input
Willy Tarreau6bcb0a82014-07-30 08:56:35 +0200737 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
738 * without SMP_OPT_FINAL). The output will be usable like this :
739 *
740 * return MAY_CHANGE FINAL Meaning for the sample
741 * NULL 0 * Not present and will never be (eg: header)
742 * NULL 1 0 Not present or unstable, could change (eg: req_len)
743 * NULL 1 1 Not present, will not change anymore
744 * smp 0 * Present and will not change (eg: header)
745 * smp 1 0 not possible
746 * smp 1 1 Present, last known value (eg: request length)
Willy Tarreau8fed9032014-07-03 17:02:46 +0200747 */
Willy Tarreau192252e2015-04-04 01:47:55 +0200748struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
Willy Tarreau8fed9032014-07-03 17:02:46 +0200749 unsigned int opt, struct sample_expr *expr, struct sample *smp)
750{
751 if (smp)
752 memset(smp, 0, sizeof(*smp));
753
Willy Tarreau192252e2015-04-04 01:47:55 +0200754 smp = sample_process(px, sess, strm, opt, expr, smp);
Willy Tarreau8fed9032014-07-03 17:02:46 +0200755 if (!smp)
756 return NULL;
757
758 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
759 return NULL; /* we can only use stable samples */
760
761 return smp_to_stkey(smp, t);
762}
763
764/*
Willy Tarreau12785782012-04-27 21:37:17 +0200765 * Returns 1 if sample expression <expr> result can be converted to table key of
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200766 * type <table_type>, otherwise zero. Used in configuration check.
767 */
Willy Tarreau12785782012-04-27 21:37:17 +0200768int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200769{
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100770 int out_type;
771
Thierry FOURNIER5d24ebc2015-07-24 08:46:42 +0200772 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200773 return 0;
774
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100775 out_type = smp_expr_output_type(expr);
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200776
Thierry FOURNIERbc8c4042015-08-10 17:53:45 +0200777 /* Convert sample. */
778 if (!sample_casts[out_type][table_type])
Thierry FOURNIERf73eb8f2013-11-27 15:30:55 +0100779 return 0;
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200780
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200781 return 1;
782}
Emeric Brun3bd697e2010-01-04 15:23:48 +0100783
Willy Tarreauedee1d62014-07-15 16:44:27 +0200784/* Extra data types processing : after the last one, some room may remain
785 * before STKTABLE_DATA_TYPES that may be used to register extra data types
786 * at run time.
787 */
Willy Tarreau08d5f982010-06-06 13:34:54 +0200788struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200789 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
Thierry FOURNIER3cf11112015-07-28 08:57:05 +0200790 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200791 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
Willy Tarreauba2ffd12013-05-29 15:54:14 +0200792 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau3b9c6e02010-07-18 08:04:30 +0200793 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
794 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
795 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
796 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
797 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
798 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
799 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
800 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
801 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
802 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
803 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
804 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
805 [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 +0100806 [STKTABLE_DT_GPC1] = { .name = "gpc1", .std_type = STD_T_UINT },
807 [STKTABLE_DT_GPC1_RATE] = { .name = "gpc1_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
Willy Tarreau08d5f982010-06-06 13:34:54 +0200808};
809
Willy Tarreauedee1d62014-07-15 16:44:27 +0200810/* Registers stick-table extra data type with index <idx>, name <name>, type
811 * <std_type> and arg type <arg_type>. If the index is negative, the next free
812 * index is automatically allocated. The allocated index is returned, or -1 if
813 * no free index was found or <name> was already registered. The <name> is used
814 * directly as a pointer, so if it's not stable, the caller must allocate it.
815 */
816int stktable_register_data_store(int idx, const char *name, int std_type, int arg_type)
817{
818 if (idx < 0) {
819 for (idx = 0; idx < STKTABLE_DATA_TYPES; idx++) {
820 if (!stktable_data_types[idx].name)
821 break;
822
823 if (strcmp(stktable_data_types[idx].name, name) == 0)
824 return -1;
825 }
826 }
827
828 if (idx >= STKTABLE_DATA_TYPES)
829 return -1;
830
831 if (stktable_data_types[idx].name != NULL)
832 return -1;
833
834 stktable_data_types[idx].name = name;
835 stktable_data_types[idx].std_type = std_type;
836 stktable_data_types[idx].arg_type = arg_type;
837 return idx;
838}
839
Willy Tarreau08d5f982010-06-06 13:34:54 +0200840/*
841 * Returns the data type number for the stktable_data_type whose name is <name>,
842 * or <0 if not found.
843 */
844int stktable_get_data_type(char *name)
845{
846 int type;
847
848 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
Willy Tarreauedee1d62014-07-15 16:44:27 +0200849 if (!stktable_data_types[type].name)
850 continue;
Willy Tarreau08d5f982010-06-06 13:34:54 +0200851 if (strcmp(name, stktable_data_types[type].name) == 0)
852 return type;
853 }
854 return -1;
855}
856
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200857/* Casts sample <smp> to the type of the table specified in arg(0), and looks
858 * it up into this table. Returns true if found, false otherwise. The input
859 * type is STR so that input samples are converted to string (since all types
860 * can be converted to strings), then the function casts the string again into
861 * the table's type. This is a double conversion, but in the future we might
862 * support automatic input types to perform the cast on the fly.
863 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200864static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200865{
866 struct stktable *t;
867 struct stktable_key *key;
868 struct stksess *ts;
869
870 t = &arg_p[0].data.prx->table;
871
872 key = smp_to_stkey(smp, t);
873 if (!key)
874 return 0;
875
876 ts = stktable_lookup_key(t, key);
877
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200878 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200879 smp->data.u.sint = !!ts;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200880 smp->flags = SMP_F_VOL_TEST;
Willy Tarreau43e90352018-06-27 06:25:57 +0200881 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200882 return 1;
883}
884
885/* Casts sample <smp> to the type of the table specified in arg(0), and looks
886 * it up into this table. Returns the data rate received from clients in bytes/s
887 * if the key is present in the table, otherwise zero, so that comparisons can
888 * be easily performed. If the inspected parameter is not stored in the table,
889 * <not found> is returned.
890 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200891static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200892{
893 struct stktable *t;
894 struct stktable_key *key;
895 struct stksess *ts;
896 void *ptr;
897
898 t = &arg_p[0].data.prx->table;
899
900 key = smp_to_stkey(smp, t);
901 if (!key)
902 return 0;
903
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200904 ts = stktable_lookup_key(t, key);
905
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200906 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200907 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200908 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200909
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200910 if (!ts) /* key not present */
911 return 1;
912
913 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400914 if (ptr)
915 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
916 t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200917
Daniel Corbett3e60b112018-05-27 09:47:12 -0400918 stktable_release(t, ts);
919 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200920}
921
922/* Casts sample <smp> to the type of the table specified in arg(0), and looks
923 * it up into this table. Returns the cumulated number of connections for the key
924 * if the key is present in the table, otherwise zero, so that comparisons can
925 * be easily performed. If the inspected parameter is not stored in the table,
926 * <not found> is returned.
927 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200928static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200929{
930 struct stktable *t;
931 struct stktable_key *key;
932 struct stksess *ts;
933 void *ptr;
934
935 t = &arg_p[0].data.prx->table;
936
937 key = smp_to_stkey(smp, t);
938 if (!key)
939 return 0;
940
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200941 ts = stktable_lookup_key(t, key);
942
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200943 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200944 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200945 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200946
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200947 if (!ts) /* key not present */
948 return 1;
949
950 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400951 if (ptr)
952 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200953
Daniel Corbett3e60b112018-05-27 09:47:12 -0400954 stktable_release(t, ts);
955 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200956}
957
958/* Casts sample <smp> to the type of the table specified in arg(0), and looks
959 * it up into this table. Returns the number of concurrent connections for the
960 * key if the key is present in the table, otherwise zero, so that comparisons
961 * can be easily performed. If the inspected parameter is not stored in the
962 * table, <not found> is returned.
963 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200964static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200965{
966 struct stktable *t;
967 struct stktable_key *key;
968 struct stksess *ts;
969 void *ptr;
970
971 t = &arg_p[0].data.prx->table;
972
973 key = smp_to_stkey(smp, t);
974 if (!key)
975 return 0;
976
Willy Tarreauf0c730a2016-05-25 17:07:56 +0200977 ts = stktable_lookup_key(t, key);
978
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200979 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200980 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200981 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200982
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200983 if (!ts) /* key not present */
984 return 1;
985
986 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
Daniel Corbett3e60b112018-05-27 09:47:12 -0400987 if (ptr)
988 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200989
Daniel Corbett3e60b112018-05-27 09:47:12 -0400990 stktable_release(t, ts);
991 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +0200992}
993
994/* Casts sample <smp> to the type of the table specified in arg(0), and looks
995 * it up into this table. Returns the rate of incoming connections from the key
996 * if the key is present in the table, otherwise zero, so that comparisons can
997 * be easily performed. If the inspected parameter is not stored in the table,
998 * <not found> is returned.
999 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001000static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001001{
1002 struct stktable *t;
1003 struct stktable_key *key;
1004 struct stksess *ts;
1005 void *ptr;
1006
1007 t = &arg_p[0].data.prx->table;
1008
1009 key = smp_to_stkey(smp, t);
1010 if (!key)
1011 return 0;
1012
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001013 ts = stktable_lookup_key(t, key);
1014
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001015 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001016 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001017 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001018
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001019 if (!ts) /* key not present */
1020 return 1;
1021
1022 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001023 if (ptr)
1024 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
1025 t->data_arg[STKTABLE_DT_CONN_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001026
Daniel Corbett3e60b112018-05-27 09:47:12 -04001027 stktable_release(t, ts);
1028 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001029}
1030
1031/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1032 * it up into this table. Returns the data rate sent to clients in bytes/s
1033 * if the key is present in the table, otherwise zero, so that comparisons can
1034 * be easily performed. If the inspected parameter is not stored in the table,
1035 * <not found> is returned.
1036 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001037static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001038{
1039 struct stktable *t;
1040 struct stktable_key *key;
1041 struct stksess *ts;
1042 void *ptr;
1043
1044 t = &arg_p[0].data.prx->table;
1045
1046 key = smp_to_stkey(smp, t);
1047 if (!key)
1048 return 0;
1049
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001050 ts = stktable_lookup_key(t, key);
1051
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001052 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001053 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001054 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001055
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001056 if (!ts) /* key not present */
1057 return 1;
1058
1059 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001060 if (ptr)
1061 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
1062 t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001063
Daniel Corbett3e60b112018-05-27 09:47:12 -04001064 stktable_release(t, ts);
1065 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001066}
1067
1068/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001069 * it up into this table. Returns the value of the GPT0 tag for the key
1070 * if the key is present in the table, otherwise false, so that comparisons can
1071 * be easily performed. If the inspected parameter is not stored in the table,
1072 * <not found> is returned.
1073 */
1074static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, void *private)
1075{
1076 struct stktable *t;
1077 struct stktable_key *key;
1078 struct stksess *ts;
1079 void *ptr;
1080
1081 t = &arg_p[0].data.prx->table;
1082
1083 key = smp_to_stkey(smp, t);
1084 if (!key)
1085 return 0;
1086
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001087 ts = stktable_lookup_key(t, key);
1088
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001089 smp->flags = SMP_F_VOL_TEST;
1090 smp->data.type = SMP_T_SINT;
1091 smp->data.u.sint = 0;
1092
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001093 if (!ts) /* key not present */
1094 return 1;
1095
1096 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001097 if (ptr)
1098 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001099
Daniel Corbett3e60b112018-05-27 09:47:12 -04001100 stktable_release(t, ts);
1101 return !!ptr;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001102}
1103
1104/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001105 * it up into this table. Returns the value of the GPC0 counter for the key
1106 * if the key is present in the table, otherwise zero, so that comparisons can
1107 * be easily performed. If the inspected parameter is not stored in the table,
1108 * <not found> is returned.
1109 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001110static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001111{
1112 struct stktable *t;
1113 struct stktable_key *key;
1114 struct stksess *ts;
1115 void *ptr;
1116
1117 t = &arg_p[0].data.prx->table;
1118
1119 key = smp_to_stkey(smp, t);
1120 if (!key)
1121 return 0;
1122
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001123 ts = stktable_lookup_key(t, key);
1124
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001125 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001126 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001127 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001128
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001129 if (!ts) /* key not present */
1130 return 1;
1131
1132 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001133 if (ptr)
1134 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001135
Daniel Corbett3e60b112018-05-27 09:47:12 -04001136 stktable_release(t, ts);
1137 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001138}
1139
1140/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1141 * it up into this table. Returns the event rate of the GPC0 counter for the key
1142 * if the key is present in the table, otherwise zero, so that comparisons can
1143 * be easily performed. If the inspected parameter is not stored in the table,
1144 * <not found> is returned.
1145 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001146static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001147{
1148 struct stktable *t;
1149 struct stktable_key *key;
1150 struct stksess *ts;
1151 void *ptr;
1152
1153 t = &arg_p[0].data.prx->table;
1154
1155 key = smp_to_stkey(smp, t);
1156 if (!key)
1157 return 0;
1158
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001159 ts = stktable_lookup_key(t, key);
1160
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001161 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001162 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001163 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001164
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001165 if (!ts) /* key not present */
1166 return 1;
1167
1168 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001169 if (ptr)
1170 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1171 t->data_arg[STKTABLE_DT_GPC0_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001172
Daniel Corbett3e60b112018-05-27 09:47:12 -04001173 stktable_release(t, ts);
1174 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001175}
1176
1177/* 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 +01001178 * it up into this table. Returns the value of the GPC1 counter for the key
1179 * if the key is present in the table, otherwise zero, so that comparisons can
1180 * be easily performed. If the inspected parameter is not stored in the table,
1181 * <not found> is returned.
1182 */
1183static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, void *private)
1184{
1185 struct stktable *t;
1186 struct stktable_key *key;
1187 struct stksess *ts;
1188 void *ptr;
1189
1190 t = &arg_p[0].data.prx->table;
1191
1192 key = smp_to_stkey(smp, t);
1193 if (!key)
1194 return 0;
1195
1196 ts = stktable_lookup_key(t, key);
1197
1198 smp->flags = SMP_F_VOL_TEST;
1199 smp->data.type = SMP_T_SINT;
1200 smp->data.u.sint = 0;
1201
1202 if (!ts) /* key not present */
1203 return 1;
1204
1205 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001206 if (ptr)
1207 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001208
Daniel Corbett3e60b112018-05-27 09:47:12 -04001209 stktable_release(t, ts);
1210 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001211}
1212
1213/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1214 * it up into this table. Returns the event rate of the GPC1 counter for the key
1215 * if the key is present in the table, otherwise zero, so that comparisons can
1216 * be easily performed. If the inspected parameter is not stored in the table,
1217 * <not found> is returned.
1218 */
1219static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *smp, void *private)
1220{
1221 struct stktable *t;
1222 struct stktable_key *key;
1223 struct stksess *ts;
1224 void *ptr;
1225
1226 t = &arg_p[0].data.prx->table;
1227
1228 key = smp_to_stkey(smp, t);
1229 if (!key)
1230 return 0;
1231
1232 ts = stktable_lookup_key(t, key);
1233
1234 smp->flags = SMP_F_VOL_TEST;
1235 smp->data.type = SMP_T_SINT;
1236 smp->data.u.sint = 0;
1237
1238 if (!ts) /* key not present */
1239 return 1;
1240
1241 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC1_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001242 if (ptr)
1243 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
1244 t->data_arg[STKTABLE_DT_GPC1_RATE].u);
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001245
Daniel Corbett3e60b112018-05-27 09:47:12 -04001246 stktable_release(t, ts);
1247 return !!ptr;
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001248}
1249
1250/* Casts sample <smp> to the type of the table specified in arg(0), and looks
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001251 * it up into this table. Returns the cumulated number of HTTP request errors
1252 * for the key if the key is present in the table, otherwise zero, so that
1253 * comparisons can be easily performed. If the inspected parameter is not stored
1254 * in the table, <not found> is returned.
1255 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001256static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001257{
1258 struct stktable *t;
1259 struct stktable_key *key;
1260 struct stksess *ts;
1261 void *ptr;
1262
1263 t = &arg_p[0].data.prx->table;
1264
1265 key = smp_to_stkey(smp, t);
1266 if (!key)
1267 return 0;
1268
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001269 ts = stktable_lookup_key(t, key);
1270
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001271 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001272 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001273 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001274
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001275 if (!ts) /* key not present */
1276 return 1;
1277
1278 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001279 if (ptr)
1280 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001281
Daniel Corbett3e60b112018-05-27 09:47:12 -04001282 stktable_release(t, ts);
1283 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001284}
1285
1286/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1287 * it up into this table. Returns the HTTP request error rate the key
1288 * if the key is present in the table, otherwise zero, so that comparisons can
1289 * be easily performed. If the inspected parameter is not stored in the table,
1290 * <not found> is returned.
1291 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001292static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001293{
1294 struct stktable *t;
1295 struct stktable_key *key;
1296 struct stksess *ts;
1297 void *ptr;
1298
1299 t = &arg_p[0].data.prx->table;
1300
1301 key = smp_to_stkey(smp, t);
1302 if (!key)
1303 return 0;
1304
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001305 ts = stktable_lookup_key(t, key);
1306
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001307 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001308 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001309 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001310
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001311 if (!ts) /* key not present */
1312 return 1;
1313
1314 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001315 if (ptr)
1316 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1317 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001318
Daniel Corbett3e60b112018-05-27 09:47:12 -04001319 stktable_release(t, ts);
1320 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001321}
1322
1323/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1324 * it up into this table. Returns the cumulated number of HTTP request for the
1325 * key if the key is present in the table, otherwise zero, so that comparisons
1326 * can be easily performed. If the inspected parameter is not stored in the
1327 * table, <not found> is returned.
1328 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001329static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001330{
1331 struct stktable *t;
1332 struct stktable_key *key;
1333 struct stksess *ts;
1334 void *ptr;
1335
1336 t = &arg_p[0].data.prx->table;
1337
1338 key = smp_to_stkey(smp, t);
1339 if (!key)
1340 return 0;
1341
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001342 ts = stktable_lookup_key(t, key);
1343
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001344 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001345 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001346 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001347
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001348 if (!ts) /* key not present */
1349 return 1;
1350
1351 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001352 if (ptr)
1353 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001354
Daniel Corbett3e60b112018-05-27 09:47:12 -04001355 stktable_release(t, ts);
1356 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001357}
1358
1359/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1360 * it up into this table. Returns the HTTP request rate the key if the key is
1361 * present in the table, otherwise zero, so that comparisons can be easily
1362 * performed. If the inspected parameter is not stored in the table, <not found>
1363 * is returned.
1364 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001365static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001366{
1367 struct stktable *t;
1368 struct stktable_key *key;
1369 struct stksess *ts;
1370 void *ptr;
1371
1372 t = &arg_p[0].data.prx->table;
1373
1374 key = smp_to_stkey(smp, t);
1375 if (!key)
1376 return 0;
1377
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001378 ts = stktable_lookup_key(t, key);
1379
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001380 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001381 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001382 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001383
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001384 if (!ts) /* key not present */
1385 return 1;
1386
1387 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001388 if (ptr)
1389 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1390 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001391
Daniel Corbett3e60b112018-05-27 09:47:12 -04001392 stktable_release(t, ts);
1393 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001394}
1395
1396/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1397 * it up into this table. Returns the volume of datareceived from clients in kbytes
1398 * if the key is present in the table, otherwise zero, so that comparisons can
1399 * be easily performed. If the inspected parameter is not stored in the table,
1400 * <not found> is returned.
1401 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001402static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001403{
1404 struct stktable *t;
1405 struct stktable_key *key;
1406 struct stksess *ts;
1407 void *ptr;
1408
1409 t = &arg_p[0].data.prx->table;
1410
1411 key = smp_to_stkey(smp, t);
1412 if (!key)
1413 return 0;
1414
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001415 ts = stktable_lookup_key(t, key);
1416
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001417 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001418 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001419 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001420
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001421 if (!ts) /* key not present */
1422 return 1;
1423
1424 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001425 if (ptr)
1426 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001427
Daniel Corbett3e60b112018-05-27 09:47:12 -04001428 stktable_release(t, ts);
1429 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001430}
1431
1432/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1433 * it up into this table. Returns the volume of data sent to clients in kbytes
1434 * if the key is present in the table, otherwise zero, so that comparisons can
1435 * be easily performed. If the inspected parameter is not stored in the table,
1436 * <not found> is returned.
1437 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001438static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001439{
1440 struct stktable *t;
1441 struct stktable_key *key;
1442 struct stksess *ts;
1443 void *ptr;
1444
1445 t = &arg_p[0].data.prx->table;
1446
1447 key = smp_to_stkey(smp, t);
1448 if (!key)
1449 return 0;
1450
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001451 ts = stktable_lookup_key(t, key);
1452
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001453 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001454 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001455 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001456
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001457 if (!ts) /* key not present */
1458 return 1;
1459
1460 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001461 if (ptr)
1462 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001463
Daniel Corbett3e60b112018-05-27 09:47:12 -04001464 stktable_release(t, ts);
1465 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001466}
1467
1468/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1469 * it up into this table. Returns the server ID associated with the key if the
1470 * key is present in the table, otherwise zero, so that comparisons can be
1471 * easily performed. If the inspected parameter is not stored in the table,
1472 * <not found> is returned.
1473 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001474static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001475{
1476 struct stktable *t;
1477 struct stktable_key *key;
1478 struct stksess *ts;
1479 void *ptr;
1480
1481 t = &arg_p[0].data.prx->table;
1482
1483 key = smp_to_stkey(smp, t);
1484 if (!key)
1485 return 0;
1486
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001487 ts = stktable_lookup_key(t, key);
1488
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001489 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001490 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001491 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001492
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001493 if (!ts) /* key not present */
1494 return 1;
1495
1496 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001497 if (ptr)
1498 smp->data.u.sint = stktable_data_cast(ptr, server_id);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001499
Daniel Corbett3e60b112018-05-27 09:47:12 -04001500 stktable_release(t, ts);
1501 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001502}
1503
1504/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1505 * it up into this table. Returns the cumulated number of sessions for the
1506 * key if the key is present in the table, otherwise zero, so that comparisons
1507 * can be easily performed. If the inspected parameter is not stored in the
1508 * table, <not found> is returned.
1509 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001510static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001511{
1512 struct stktable *t;
1513 struct stktable_key *key;
1514 struct stksess *ts;
1515 void *ptr;
1516
1517 t = &arg_p[0].data.prx->table;
1518
1519 key = smp_to_stkey(smp, t);
1520 if (!key)
1521 return 0;
1522
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001523 ts = stktable_lookup_key(t, key);
1524
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001525 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001526 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001527 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001528
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001529 if (!ts) /* key not present */
1530 return 1;
1531
1532 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001533 if (ptr)
1534 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001535
Daniel Corbett3e60b112018-05-27 09:47:12 -04001536 stktable_release(t, ts);
1537 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001538}
1539
1540/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1541 * it up into this table. Returns the session rate the key if the key is
1542 * present in the table, otherwise zero, so that comparisons can be easily
1543 * performed. If the inspected parameter is not stored in the table, <not found>
1544 * is returned.
1545 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001546static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001547{
1548 struct stktable *t;
1549 struct stktable_key *key;
1550 struct stksess *ts;
1551 void *ptr;
1552
1553 t = &arg_p[0].data.prx->table;
1554
1555 key = smp_to_stkey(smp, t);
1556 if (!key)
1557 return 0;
1558
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001559 ts = stktable_lookup_key(t, key);
1560
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001561 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001562 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001563 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001564
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001565 if (!ts) /* key not present */
1566 return 1;
1567
1568 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
Daniel Corbett3e60b112018-05-27 09:47:12 -04001569 if (ptr)
1570 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1571 t->data_arg[STKTABLE_DT_SESS_RATE].u);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001572
Daniel Corbett3e60b112018-05-27 09:47:12 -04001573 stktable_release(t, ts);
1574 return !!ptr;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001575}
1576
1577/* Casts sample <smp> to the type of the table specified in arg(0), and looks
1578 * it up into this table. Returns the amount of concurrent connections tracking
1579 * the same key if the key is present in the table, otherwise zero, so that
1580 * comparisons can be easily performed. If the inspected parameter is not
1581 * stored in the table, <not found> is returned.
1582 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02001583static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001584{
1585 struct stktable *t;
1586 struct stktable_key *key;
1587 struct stksess *ts;
1588
1589 t = &arg_p[0].data.prx->table;
1590
1591 key = smp_to_stkey(smp, t);
1592 if (!key)
1593 return 0;
1594
Willy Tarreauf0c730a2016-05-25 17:07:56 +02001595 ts = stktable_lookup_key(t, key);
1596
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001597 smp->flags = SMP_F_VOL_TEST;
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001598 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001599 smp->data.u.sint = 0;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001600
Tim Duesterhus65189c12018-06-26 15:57:29 +02001601 if (!ts)
1602 return 1;
1603
1604 smp->data.u.sint = ts->ref_cnt;
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001605
Daniel Corbett3e60b112018-05-27 09:47:12 -04001606 stktable_release(t, ts);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02001607 return 1;
1608}
1609
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001610/* Always returns 1. */
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001611static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001612 struct session *sess, struct stream *s, int flags)
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001613{
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001614 struct stksess *ts;
1615 struct stkctr *stkctr;
1616
1617 /* Extract the stksess, return OK if no stksess available. */
1618 if (s)
1619 stkctr = &s->stkctr[rule->arg.gpc.sc];
1620 else
1621 stkctr = &sess->stkctr[rule->arg.gpc.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001622
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001623 ts = stkctr_entry(stkctr);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001624 if (ts) {
1625 void *ptr1, *ptr2;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001626
Willy Tarreau79c1e912016-01-25 14:54:45 +01001627 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1628 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001629 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1630 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001631 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001632
1633 if (ptr1)
1634 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
Willy Tarreau79c1e912016-01-25 14:54:45 +01001635 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001636
Emeric Brun819fc6f2017-06-13 19:37:32 +02001637 if (ptr2)
1638 stktable_data_cast(ptr2, gpc0)++;
Willy Tarreau79c1e912016-01-25 14:54:45 +01001639
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001640 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001641
1642 /* If data was modified, we need to touch to re-schedule sync */
1643 stktable_touch_local(stkctr->table, ts, 0);
1644 }
Willy Tarreau79c1e912016-01-25 14:54:45 +01001645 }
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001646 return ACT_RET_CONT;
1647}
1648
1649/* This function is a common parser for using variables. It understands
1650 * the formats:
1651 *
1652 * sc-inc-gpc0(<stick-table ID>)
1653 *
1654 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1655 * it returns 1 and the variable <expr> is filled with the pointer to the
1656 * expression to execute.
1657 */
1658static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1659 struct act_rule *rule, char **err)
1660{
1661 const char *cmd_name = args[*arg-1];
1662 char *error;
1663
1664 cmd_name += strlen("sc-inc-gpc0");
1665 if (*cmd_name == '\0') {
1666 /* default stick table id. */
1667 rule->arg.gpc.sc = 0;
1668 } else {
1669 /* parse the stick table id. */
1670 if (*cmd_name != '(') {
1671 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1672 return ACT_RET_PRS_ERR;
1673 }
1674 cmd_name++; /* jump the '(' */
1675 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1676 if (*error != ')') {
1677 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1678 return ACT_RET_PRS_ERR;
1679 }
1680
1681 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1682 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1683 ACT_ACTION_TRK_SCMAX-1);
1684 return ACT_RET_PRS_ERR;
1685 }
1686 }
Thierry FOURNIER42148732015-09-02 17:17:33 +02001687 rule->action = ACT_CUSTOM;
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02001688 rule->action_ptr = action_inc_gpc0;
1689 return ACT_RET_PRS_OK;
1690}
1691
1692/* Always returns 1. */
Frédéric Lécaille6778b272018-01-29 15:22:53 +01001693static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
1694 struct session *sess, struct stream *s, int flags)
1695{
1696 struct stksess *ts;
1697 struct stkctr *stkctr;
1698
1699 /* Extract the stksess, return OK if no stksess available. */
1700 if (s)
1701 stkctr = &s->stkctr[rule->arg.gpc.sc];
1702 else
1703 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1704
1705 ts = stkctr_entry(stkctr);
1706 if (ts) {
1707 void *ptr1, *ptr2;
1708
1709 /* First, update gpc1_rate if it's tracked. Second, update its gpc1 if tracked. */
1710 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1_RATE);
1711 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC1);
1712 if (ptr1 || ptr2) {
1713 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1714
1715 if (ptr1)
1716 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
1717 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
1718
1719 if (ptr2)
1720 stktable_data_cast(ptr2, gpc1)++;
1721
1722 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1723
1724 /* If data was modified, we need to touch to re-schedule sync */
1725 stktable_touch_local(stkctr->table, ts, 0);
1726 }
1727 }
1728 return ACT_RET_CONT;
1729}
1730
1731/* This function is a common parser for using variables. It understands
1732 * the formats:
1733 *
1734 * sc-inc-gpc1(<stick-table ID>)
1735 *
1736 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1737 * it returns 1 and the variable <expr> is filled with the pointer to the
1738 * expression to execute.
1739 */
1740static enum act_parse_ret parse_inc_gpc1(const char **args, int *arg, struct proxy *px,
1741 struct act_rule *rule, char **err)
1742{
1743 const char *cmd_name = args[*arg-1];
1744 char *error;
1745
1746 cmd_name += strlen("sc-inc-gpc1");
1747 if (*cmd_name == '\0') {
1748 /* default stick table id. */
1749 rule->arg.gpc.sc = 0;
1750 } else {
1751 /* parse the stick table id. */
1752 if (*cmd_name != '(') {
1753 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1754 return ACT_RET_PRS_ERR;
1755 }
1756 cmd_name++; /* jump the '(' */
1757 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1758 if (*error != ')') {
1759 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1760 return ACT_RET_PRS_ERR;
1761 }
1762
1763 if (rule->arg.gpc.sc >= ACT_ACTION_TRK_SCMAX) {
1764 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1765 ACT_ACTION_TRK_SCMAX-1);
1766 return ACT_RET_PRS_ERR;
1767 }
1768 }
1769 rule->action = ACT_CUSTOM;
1770 rule->action_ptr = action_inc_gpc1;
1771 return ACT_RET_PRS_OK;
1772}
1773
1774/* Always returns 1. */
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001775static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02001776 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001777{
1778 void *ptr;
1779 struct stksess *ts;
1780 struct stkctr *stkctr;
1781
1782 /* Extract the stksess, return OK if no stksess available. */
1783 if (s)
1784 stkctr = &s->stkctr[rule->arg.gpt.sc];
1785 else
1786 stkctr = &sess->stkctr[rule->arg.gpt.sc];
Willy Tarreau79c1e912016-01-25 14:54:45 +01001787
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001788 ts = stkctr_entry(stkctr);
1789 if (!ts)
1790 return ACT_RET_CONT;
1791
1792 /* Store the sample in the required sc, and ignore errors. */
1793 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001794 if (ptr) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001795 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001796
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001797 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
Emeric Brun819fc6f2017-06-13 19:37:32 +02001798
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001799 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02001800
1801 stktable_touch_local(stkctr->table, ts, 0);
Willy Tarreau79c1e912016-01-25 14:54:45 +01001802 }
1803
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001804 return ACT_RET_CONT;
1805}
1806
1807/* This function is a common parser for using variables. It understands
1808 * the format:
1809 *
1810 * set-gpt0(<stick-table ID>) <expression>
1811 *
1812 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1813 * it returns 1 and the variable <expr> is filled with the pointer to the
1814 * expression to execute.
1815 */
1816static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1817 struct act_rule *rule, char **err)
1818
1819
1820{
1821 const char *cmd_name = args[*arg-1];
1822 char *error;
1823
1824 cmd_name += strlen("sc-set-gpt0");
1825 if (*cmd_name == '\0') {
1826 /* default stick table id. */
1827 rule->arg.gpt.sc = 0;
1828 } else {
1829 /* parse the stick table id. */
1830 if (*cmd_name != '(') {
1831 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1832 return ACT_RET_PRS_ERR;
1833 }
1834 cmd_name++; /* jump the '(' */
1835 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1836 if (*error != ')') {
1837 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1838 return ACT_RET_PRS_ERR;
1839 }
1840
1841 if (rule->arg.gpt.sc >= ACT_ACTION_TRK_SCMAX) {
1842 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1843 args[*arg-1], ACT_ACTION_TRK_SCMAX-1);
1844 return ACT_RET_PRS_ERR;
1845 }
1846 }
1847
1848 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1849 if (*error != '\0') {
1850 memprintf(err, "invalid integer value '%s'", args[*arg]);
1851 return ACT_RET_PRS_ERR;
1852 }
1853 (*arg)++;
1854
Thierry FOURNIER42148732015-09-02 17:17:33 +02001855 rule->action = ACT_CUSTOM;
Thierry FOURNIER236657b2015-08-19 08:25:14 +02001856 rule->action_ptr = action_set_gpt0;
1857
1858 return ACT_RET_PRS_OK;
1859}
1860
Willy Tarreau7d562212016-11-25 16:10:05 +01001861/* set temp integer to the number of used entries in the table pointed to by expr.
1862 * Accepts exactly 1 argument of type table.
1863 */
1864static int
1865smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1866{
1867 smp->flags = SMP_F_VOL_TEST;
1868 smp->data.type = SMP_T_SINT;
1869 smp->data.u.sint = args->data.prx->table.current;
1870 return 1;
1871}
1872
1873/* set temp integer to the number of free entries in the table pointed to by expr.
1874 * Accepts exactly 1 argument of type table.
1875 */
1876static int
1877smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1878{
1879 struct proxy *px;
1880
1881 px = args->data.prx;
1882 smp->flags = SMP_F_VOL_TEST;
1883 smp->data.type = SMP_T_SINT;
1884 smp->data.u.sint = px->table.size - px->table.current;
1885 return 1;
1886}
1887
1888/* Returns a pointer to a stkctr depending on the fetch keyword name.
1889 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1890 * sc[0-9]_* will return a pointer to the respective field in the
1891 * stream <l4>. sc_* requires an UINT argument specifying the stick
1892 * counter number. src_* will fill a locally allocated structure with
1893 * the table and entry corresponding to what is specified with src_*.
1894 * NULL may be returned if the designated stkctr is not tracked. For
1895 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1896 * passed. When present, the currently tracked key is then looked up
1897 * in the specified table instead of the current table. The purpose is
1898 * to be able to convery multiple values per key (eg: have gpc0 from
1899 * multiple tables). <strm> is allowed to be NULL, in which case only
1900 * the session will be consulted.
1901 */
1902struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001903smp_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 +01001904{
Willy Tarreau7d562212016-11-25 16:10:05 +01001905 struct stkctr *stkptr;
1906 struct stksess *stksess;
1907 unsigned int num = kw[2] - '0';
1908 int arg = 0;
1909
1910 if (num == '_' - '0') {
1911 /* sc_* variant, args[0] = ctr# (mandatory) */
1912 num = args[arg++].data.sint;
1913 if (num >= MAX_SESS_STKCTR)
1914 return NULL;
1915 }
1916 else if (num > 9) { /* src_* variant, args[0] = table */
1917 struct stktable_key *key;
1918 struct connection *conn = objt_conn(sess->origin);
1919 struct sample smp;
1920
1921 if (!conn)
1922 return NULL;
1923
1924 /* Fetch source adress in a sample. */
1925 smp.px = NULL;
1926 smp.sess = sess;
1927 smp.strm = strm;
1928 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1929 return NULL;
1930
1931 /* Converts into key. */
1932 key = smp_to_stkey(&smp, &args->data.prx->table);
1933 if (!key)
1934 return NULL;
1935
Emeric Brun819fc6f2017-06-13 19:37:32 +02001936 stkctr->table = &args->data.prx->table;
1937 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1938 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001939 }
1940
1941 /* Here, <num> contains the counter number from 0 to 9 for
1942 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1943 * args[arg] is the first optional argument. We first lookup the
1944 * ctr form the stream, then from the session if it was not there.
1945 */
1946
1947 if (strm)
1948 stkptr = &strm->stkctr[num];
1949 if (!strm || !stkctr_entry(stkptr)) {
1950 stkptr = &sess->stkctr[num];
1951 if (!stkctr_entry(stkptr))
1952 return NULL;
1953 }
1954
1955 stksess = stkctr_entry(stkptr);
1956 if (!stksess)
1957 return NULL;
1958
1959 if (unlikely(args[arg].type == ARGT_TAB)) {
1960 /* an alternate table was specified, let's look up the same key there */
Emeric Brun819fc6f2017-06-13 19:37:32 +02001961 stkctr->table = &args[arg].data.prx->table;
1962 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1963 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01001964 }
1965 return stkptr;
1966}
1967
1968/* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1969 * the entry if it doesn't exist yet. This is needed for a few fetch
1970 * functions which need to create an entry, such as src_inc_gpc* and
1971 * src_clr_gpc*.
1972 */
1973struct stkctr *
Emeric Brun819fc6f2017-06-13 19:37:32 +02001974smp_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 +01001975{
Willy Tarreau7d562212016-11-25 16:10:05 +01001976 struct stktable_key *key;
1977 struct connection *conn = objt_conn(sess->origin);
1978 struct sample smp;
1979
1980 if (strncmp(kw, "src_", 4) != 0)
1981 return NULL;
1982
1983 if (!conn)
1984 return NULL;
1985
1986 /* Fetch source adress in a sample. */
1987 smp.px = NULL;
1988 smp.sess = sess;
1989 smp.strm = strm;
1990 if (!smp_fetch_src(NULL, &smp, NULL, NULL))
1991 return NULL;
1992
1993 /* Converts into key. */
1994 key = smp_to_stkey(&smp, &args->data.prx->table);
1995 if (!key)
1996 return NULL;
1997
Emeric Brun819fc6f2017-06-13 19:37:32 +02001998 stkctr->table = &args->data.prx->table;
1999 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
2000 return stkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002001}
2002
2003/* set return a boolean indicating if the requested stream counter is
2004 * currently being tracked or not.
2005 * Supports being called as "sc[0-9]_tracked" only.
2006 */
2007static int
2008smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
2009{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002010 struct stkctr tmpstkctr;
2011 struct stkctr *stkctr;
2012
Willy Tarreau7d562212016-11-25 16:10:05 +01002013 smp->flags = SMP_F_VOL_TEST;
2014 smp->data.type = SMP_T_BOOL;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002015 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2016 smp->data.u.sint = !!stkctr;
2017
2018 /* release the ref count */
Willy Tarreau43e90352018-06-27 06:25:57 +02002019 if ((stkctr == &tmpstkctr))
Emeric Brun819fc6f2017-06-13 19:37:32 +02002020 stktable_release(stkctr->table, stkctr_entry(stkctr));
2021
Willy Tarreau7d562212016-11-25 16:10:05 +01002022 return 1;
2023}
2024
2025/* set <smp> to the General Purpose Flag 0 value from the stream's tracked
2026 * frontend counters or from the src.
2027 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
2028 * zero is returned if the key is new.
2029 */
2030static int
2031smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2032{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002033 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002034 struct stkctr *stkctr;
2035
Emeric Brun819fc6f2017-06-13 19:37:32 +02002036 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002037 if (!stkctr)
2038 return 0;
2039
2040 smp->flags = SMP_F_VOL_TEST;
2041 smp->data.type = SMP_T_SINT;
2042 smp->data.u.sint = 0;
2043
Emeric Brun819fc6f2017-06-13 19:37:32 +02002044 if (stkctr_entry(stkctr)) {
2045 void *ptr;
2046
2047 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
2048 if (!ptr) {
2049 if (stkctr == &tmpstkctr)
2050 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002051 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002052 }
2053
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002054 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002055
Willy Tarreau7d562212016-11-25 16:10:05 +01002056 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002057
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002058 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002059
2060 if (stkctr == &tmpstkctr)
2061 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002062 }
2063 return 1;
2064}
2065
2066/* set <smp> to the General Purpose Counter 0 value from the stream's tracked
2067 * frontend counters or from the src.
2068 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
2069 * zero is returned if the key is new.
2070 */
2071static int
2072smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2073{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002074 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002075 struct stkctr *stkctr;
2076
Emeric Brun819fc6f2017-06-13 19:37:32 +02002077 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002078 if (!stkctr)
2079 return 0;
2080
2081 smp->flags = SMP_F_VOL_TEST;
2082 smp->data.type = SMP_T_SINT;
2083 smp->data.u.sint = 0;
2084
2085 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002086 void *ptr;
2087
2088 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2089 if (!ptr) {
2090 if (stkctr == &tmpstkctr)
2091 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002092 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002093 }
2094
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002095 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002096
Willy Tarreau7d562212016-11-25 16:10:05 +01002097 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002098
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002099 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002100
2101 if (stkctr == &tmpstkctr)
2102 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002103 }
2104 return 1;
2105}
2106
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002107/* set <smp> to the General Purpose Counter 1 value from the stream's tracked
2108 * frontend counters or from the src.
2109 * Supports being called as "sc[0-9]_get_gpc1" or "src_get_gpc1" only. Value
2110 * zero is returned if the key is new.
2111 */
2112static int
2113smp_fetch_sc_get_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2114{
2115 struct stkctr tmpstkctr;
2116 struct stkctr *stkctr;
2117
2118 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2119 if (!stkctr)
2120 return 0;
2121
2122 smp->flags = SMP_F_VOL_TEST;
2123 smp->data.type = SMP_T_SINT;
2124 smp->data.u.sint = 0;
2125
2126 if (stkctr_entry(stkctr) != NULL) {
2127 void *ptr;
2128
2129 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2130 if (!ptr) {
2131 if (stkctr == &tmpstkctr)
2132 stktable_release(stkctr->table, stkctr_entry(stkctr));
2133 return 0; /* parameter not stored */
2134 }
2135
2136 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2137
2138 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2139
2140 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2141
2142 if (stkctr == &tmpstkctr)
2143 stktable_release(stkctr->table, stkctr_entry(stkctr));
2144 }
2145 return 1;
2146}
2147
Willy Tarreau7d562212016-11-25 16:10:05 +01002148/* set <smp> to the General Purpose Counter 0's event rate from the stream's
2149 * tracked frontend counters or from the src.
2150 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
2151 * Value zero is returned if the key is new.
2152 */
2153static int
2154smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2155{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002156 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002157 struct stkctr *stkctr;
2158
Emeric Brun819fc6f2017-06-13 19:37:32 +02002159 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002160 if (!stkctr)
2161 return 0;
2162
2163 smp->flags = SMP_F_VOL_TEST;
2164 smp->data.type = SMP_T_SINT;
2165 smp->data.u.sint = 0;
2166 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002167 void *ptr;
2168
2169 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2170 if (!ptr) {
2171 if (stkctr == &tmpstkctr)
2172 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002173 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002174 }
2175
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002176 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002177
Willy Tarreau7d562212016-11-25 16:10:05 +01002178 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
2179 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002180
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002181 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002182
2183 if (stkctr == &tmpstkctr)
2184 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002185 }
2186 return 1;
2187}
2188
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002189/* set <smp> to the General Purpose Counter 1's event rate from the stream's
2190 * tracked frontend counters or from the src.
2191 * Supports being called as "sc[0-9]_gpc1_rate" or "src_gpc1_rate" only.
2192 * Value zero is returned if the key is new.
2193 */
2194static int
2195smp_fetch_sc_gpc1_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2196{
2197 struct stkctr tmpstkctr;
2198 struct stkctr *stkctr;
2199
2200 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2201 if (!stkctr)
2202 return 0;
2203
2204 smp->flags = SMP_F_VOL_TEST;
2205 smp->data.type = SMP_T_SINT;
2206 smp->data.u.sint = 0;
2207 if (stkctr_entry(stkctr) != NULL) {
2208 void *ptr;
2209
2210 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2211 if (!ptr) {
2212 if (stkctr == &tmpstkctr)
2213 stktable_release(stkctr->table, stkctr_entry(stkctr));
2214 return 0; /* parameter not stored */
2215 }
2216
2217 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2218
2219 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc1_rate),
2220 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u);
2221
2222 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2223
2224 if (stkctr == &tmpstkctr)
2225 stktable_release(stkctr->table, stkctr_entry(stkctr));
2226 }
2227 return 1;
2228}
2229
Willy Tarreau7d562212016-11-25 16:10:05 +01002230/* Increment the General Purpose Counter 0 value from the stream's tracked
2231 * frontend counters and return it into temp integer.
2232 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
2233 */
2234static int
2235smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2236{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002237 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002238 struct stkctr *stkctr;
2239
Emeric Brun819fc6f2017-06-13 19:37:32 +02002240 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002241 if (!stkctr)
2242 return 0;
2243
2244 smp->flags = SMP_F_VOL_TEST;
2245 smp->data.type = SMP_T_SINT;
2246 smp->data.u.sint = 0;
2247
Emeric Brun819fc6f2017-06-13 19:37:32 +02002248 if (!stkctr_entry(stkctr))
2249 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002250
2251 if (stkctr && stkctr_entry(stkctr)) {
2252 void *ptr1,*ptr2;
2253
Emeric Brun819fc6f2017-06-13 19:37:32 +02002254
Willy Tarreau7d562212016-11-25 16:10:05 +01002255 /* First, update gpc0_rate if it's tracked. Second, update its
2256 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2257 */
2258 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
Willy Tarreau7d562212016-11-25 16:10:05 +01002259 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002260 if (ptr1 || ptr2) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002261 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Willy Tarreau7d562212016-11-25 16:10:05 +01002262
Emeric Brun819fc6f2017-06-13 19:37:32 +02002263 if (ptr1) {
2264 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2265 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2266 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2267 }
2268
2269 if (ptr2)
2270 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2271
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002272 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002273
2274 /* If data was modified, we need to touch to re-schedule sync */
2275 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2276 }
2277 else if (stkctr == &tmpstkctr)
2278 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002279 }
2280 return 1;
2281}
2282
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002283/* Increment the General Purpose Counter 1 value from the stream's tracked
2284 * frontend counters and return it into temp integer.
2285 * Supports being called as "sc[0-9]_inc_gpc1" or "src_inc_gpc1" only.
2286 */
2287static int
2288smp_fetch_sc_inc_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2289{
2290 struct stkctr tmpstkctr;
2291 struct stkctr *stkctr;
2292
2293 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2294 if (!stkctr)
2295 return 0;
2296
2297 smp->flags = SMP_F_VOL_TEST;
2298 smp->data.type = SMP_T_SINT;
2299 smp->data.u.sint = 0;
2300
2301 if (!stkctr_entry(stkctr))
2302 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2303
2304 if (stkctr && stkctr_entry(stkctr)) {
2305 void *ptr1,*ptr2;
2306
2307
2308 /* First, update gpc1_rate if it's tracked. Second, update its
2309 * gpc1 if tracked. Returns gpc1's value otherwise the curr_ctr.
2310 */
2311 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1_RATE);
2312 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2313 if (ptr1 || ptr2) {
2314 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2315
2316 if (ptr1) {
2317 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc1_rate),
2318 stkctr->table->data_arg[STKTABLE_DT_GPC1_RATE].u, 1);
2319 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc1_rate))->curr_ctr;
2320 }
2321
2322 if (ptr2)
2323 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc1);
2324
2325 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2326
2327 /* If data was modified, we need to touch to re-schedule sync */
2328 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2329 }
2330 else if (stkctr == &tmpstkctr)
2331 stktable_release(stkctr->table, stkctr_entry(stkctr));
2332 }
2333 return 1;
2334}
2335
Willy Tarreau7d562212016-11-25 16:10:05 +01002336/* Clear the General Purpose Counter 0 value from the stream's tracked
2337 * frontend counters and return its previous value into temp integer.
2338 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2339 */
2340static int
2341smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2342{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002343 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002344 struct stkctr *stkctr;
2345
Emeric Brun819fc6f2017-06-13 19:37:32 +02002346 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002347 if (!stkctr)
2348 return 0;
2349
2350 smp->flags = SMP_F_VOL_TEST;
2351 smp->data.type = SMP_T_SINT;
2352 smp->data.u.sint = 0;
2353
Emeric Brun819fc6f2017-06-13 19:37:32 +02002354 if (!stkctr_entry(stkctr))
2355 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002356
Emeric Brun819fc6f2017-06-13 19:37:32 +02002357 if (stkctr && stkctr_entry(stkctr)) {
2358 void *ptr;
2359
2360 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2361 if (!ptr) {
2362 if (stkctr == &tmpstkctr)
2363 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002364 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002365 }
2366
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002367 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002368
Willy Tarreau7d562212016-11-25 16:10:05 +01002369 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2370 stktable_data_cast(ptr, gpc0) = 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002371
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002372 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002373
Willy Tarreau7d562212016-11-25 16:10:05 +01002374 /* If data was modified, we need to touch to re-schedule sync */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002375 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
Willy Tarreau7d562212016-11-25 16:10:05 +01002376 }
2377 return 1;
2378}
2379
Frédéric Lécaille6778b272018-01-29 15:22:53 +01002380/* Clear the General Purpose Counter 1 value from the stream's tracked
2381 * frontend counters and return its previous value into temp integer.
2382 * Supports being called as "sc[0-9]_clr_gpc1" or "src_clr_gpc1" only.
2383 */
2384static int
2385smp_fetch_sc_clr_gpc1(const struct arg *args, struct sample *smp, const char *kw, void *private)
2386{
2387 struct stkctr tmpstkctr;
2388 struct stkctr *stkctr;
2389
2390 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2391 if (!stkctr)
2392 return 0;
2393
2394 smp->flags = SMP_F_VOL_TEST;
2395 smp->data.type = SMP_T_SINT;
2396 smp->data.u.sint = 0;
2397
2398 if (!stkctr_entry(stkctr))
2399 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2400
2401 if (stkctr && stkctr_entry(stkctr)) {
2402 void *ptr;
2403
2404 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC1);
2405 if (!ptr) {
2406 if (stkctr == &tmpstkctr)
2407 stktable_release(stkctr->table, stkctr_entry(stkctr));
2408 return 0; /* parameter not stored */
2409 }
2410
2411 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2412
2413 smp->data.u.sint = stktable_data_cast(ptr, gpc1);
2414 stktable_data_cast(ptr, gpc1) = 0;
2415
2416 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2417
2418 /* If data was modified, we need to touch to re-schedule sync */
2419 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2420 }
2421 return 1;
2422}
2423
Willy Tarreau7d562212016-11-25 16:10:05 +01002424/* set <smp> to the cumulated number of connections from the stream's tracked
2425 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2426 * "src_conn_cnt" only.
2427 */
2428static int
2429smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2430{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002431 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002432 struct stkctr *stkctr;
2433
Emeric Brun819fc6f2017-06-13 19:37:32 +02002434 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002435 if (!stkctr)
2436 return 0;
2437
2438 smp->flags = SMP_F_VOL_TEST;
2439 smp->data.type = SMP_T_SINT;
2440 smp->data.u.sint = 0;
2441 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002442 void *ptr;
2443
2444 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2445 if (!ptr) {
2446 if (stkctr == &tmpstkctr)
2447 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002448 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002449 }
2450
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002451 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002452
Willy Tarreau7d562212016-11-25 16:10:05 +01002453 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002454
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002455 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002456
2457 if (stkctr == &tmpstkctr)
2458 stktable_release(stkctr->table, stkctr_entry(stkctr));
2459
2460
Willy Tarreau7d562212016-11-25 16:10:05 +01002461 }
2462 return 1;
2463}
2464
2465/* set <smp> to the connection rate from the stream's tracked frontend
2466 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2467 * only.
2468 */
2469static int
2470smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2471{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002472 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002473 struct stkctr *stkctr;
2474
Emeric Brun819fc6f2017-06-13 19:37:32 +02002475 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002476 if (!stkctr)
2477 return 0;
2478
2479 smp->flags = SMP_F_VOL_TEST;
2480 smp->data.type = SMP_T_SINT;
2481 smp->data.u.sint = 0;
2482 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002483 void *ptr;
2484
2485 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2486 if (!ptr) {
2487 if (stkctr == &tmpstkctr)
2488 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002489 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002490 }
2491
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002492 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002493
Willy Tarreau7d562212016-11-25 16:10:05 +01002494 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2495 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002496
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002497 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002498
2499 if (stkctr == &tmpstkctr)
2500 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002501 }
2502 return 1;
2503}
2504
2505/* set temp integer to the number of connections from the stream's source address
2506 * in the table pointed to by expr, after updating it.
2507 * Accepts exactly 1 argument of type table.
2508 */
2509static int
2510smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2511{
2512 struct connection *conn = objt_conn(smp->sess->origin);
2513 struct stksess *ts;
2514 struct stktable_key *key;
2515 void *ptr;
2516 struct proxy *px;
2517
2518 if (!conn)
2519 return 0;
2520
2521 /* Fetch source adress in a sample. */
2522 if (!smp_fetch_src(NULL, smp, NULL, NULL))
2523 return 0;
2524
2525 /* Converts into key. */
2526 key = smp_to_stkey(smp, &args->data.prx->table);
2527 if (!key)
2528 return 0;
2529
2530 px = args->data.prx;
2531
Emeric Brun819fc6f2017-06-13 19:37:32 +02002532 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
Willy Tarreau7d562212016-11-25 16:10:05 +01002533 /* entry does not exist and could not be created */
2534 return 0;
2535
2536 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002537 if (!ptr) {
Willy Tarreau7d562212016-11-25 16:10:05 +01002538 return 0; /* parameter not stored in this table */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002539 }
Willy Tarreau7d562212016-11-25 16:10:05 +01002540
2541 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002542
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002543 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002544
Willy Tarreau7d562212016-11-25 16:10:05 +01002545 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002546
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002547 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002548
Willy Tarreau7d562212016-11-25 16:10:05 +01002549 smp->flags = SMP_F_VOL_TEST;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002550
2551 stktable_touch_local(&px->table, ts, 1);
2552
2553 /* Touch was previously performed by stktable_update_key */
Willy Tarreau7d562212016-11-25 16:10:05 +01002554 return 1;
2555}
2556
2557/* set <smp> to the number of concurrent connections from the stream's tracked
2558 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2559 * "src_conn_cur" only.
2560 */
2561static int
2562smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2563{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002564 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002565 struct stkctr *stkctr;
2566
Emeric Brun819fc6f2017-06-13 19:37:32 +02002567 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002568 if (!stkctr)
2569 return 0;
2570
2571 smp->flags = SMP_F_VOL_TEST;
2572 smp->data.type = SMP_T_SINT;
2573 smp->data.u.sint = 0;
2574 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002575 void *ptr;
2576
2577 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2578 if (!ptr) {
2579 if (stkctr == &tmpstkctr)
2580 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002581 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002582 }
2583
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002584 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002585
Willy Tarreau7d562212016-11-25 16:10:05 +01002586 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002587
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002588 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002589
2590 if (stkctr == &tmpstkctr)
2591 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002592 }
2593 return 1;
2594}
2595
2596/* set <smp> to the cumulated number of streams from the stream's tracked
2597 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2598 * "src_sess_cnt" only.
2599 */
2600static int
2601smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2602{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002603 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002604 struct stkctr *stkctr;
2605
Emeric Brun819fc6f2017-06-13 19:37:32 +02002606 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002607 if (!stkctr)
2608 return 0;
2609
2610 smp->flags = SMP_F_VOL_TEST;
2611 smp->data.type = SMP_T_SINT;
2612 smp->data.u.sint = 0;
2613 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002614 void *ptr;
2615
2616 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2617 if (!ptr) {
2618 if (stkctr == &tmpstkctr)
2619 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002620 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002621 }
2622
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002623 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002624
Willy Tarreau7d562212016-11-25 16:10:05 +01002625 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002626
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002627 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002628
2629 if (stkctr == &tmpstkctr)
2630 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002631 }
2632 return 1;
2633}
2634
2635/* set <smp> to the stream rate from the stream's tracked frontend counters.
2636 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2637 */
2638static int
2639smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2640{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002641 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002642 struct stkctr *stkctr;
2643
Emeric Brun819fc6f2017-06-13 19:37:32 +02002644 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002645 if (!stkctr)
2646 return 0;
2647
2648 smp->flags = SMP_F_VOL_TEST;
2649 smp->data.type = SMP_T_SINT;
2650 smp->data.u.sint = 0;
2651 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002652 void *ptr;
2653
2654 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2655 if (!ptr) {
2656 if (stkctr == &tmpstkctr)
2657 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002658 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002659 }
2660
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002661 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002662
Willy Tarreau7d562212016-11-25 16:10:05 +01002663 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2664 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002665
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002666 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002667
2668 if (stkctr == &tmpstkctr)
2669 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002670 }
2671 return 1;
2672}
2673
2674/* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2675 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2676 * "src_http_req_cnt" only.
2677 */
2678static int
2679smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2680{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002681 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002682 struct stkctr *stkctr;
2683
Emeric Brun819fc6f2017-06-13 19:37:32 +02002684 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002685 if (!stkctr)
2686 return 0;
2687
2688 smp->flags = SMP_F_VOL_TEST;
2689 smp->data.type = SMP_T_SINT;
2690 smp->data.u.sint = 0;
2691 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002692 void *ptr;
2693
2694 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2695 if (!ptr) {
2696 if (stkctr == &tmpstkctr)
2697 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002698 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002699 }
2700
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002701 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002702
Willy Tarreau7d562212016-11-25 16:10:05 +01002703 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002704
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002705 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002706
2707 if (stkctr == &tmpstkctr)
2708 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002709 }
2710 return 1;
2711}
2712
2713/* set <smp> to the HTTP request rate from the stream's tracked frontend
2714 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2715 * "src_http_req_rate" only.
2716 */
2717static int
2718smp_fetch_sc_http_req_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2719{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002720 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002721 struct stkctr *stkctr;
2722
Emeric Brun819fc6f2017-06-13 19:37:32 +02002723 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002724 if (!stkctr)
2725 return 0;
2726
2727 smp->flags = SMP_F_VOL_TEST;
2728 smp->data.type = SMP_T_SINT;
2729 smp->data.u.sint = 0;
2730 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002731 void *ptr;
2732
2733 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2734 if (!ptr) {
2735 if (stkctr == &tmpstkctr)
2736 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002737 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002738 }
2739
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002740 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002741
Willy Tarreau7d562212016-11-25 16:10:05 +01002742 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2743 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002744
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002745 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002746
2747 if (stkctr == &tmpstkctr)
2748 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002749 }
2750 return 1;
2751}
2752
2753/* set <smp> to the cumulated number of HTTP requests errors from the stream's
2754 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2755 * "src_http_err_cnt" only.
2756 */
2757static int
2758smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2759{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002760 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002761 struct stkctr *stkctr;
2762
Emeric Brun819fc6f2017-06-13 19:37:32 +02002763 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002764 if (!stkctr)
2765 return 0;
2766
2767 smp->flags = SMP_F_VOL_TEST;
2768 smp->data.type = SMP_T_SINT;
2769 smp->data.u.sint = 0;
2770 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002771 void *ptr;
2772
2773 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2774 if (!ptr) {
2775 if (stkctr == &tmpstkctr)
2776 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002777 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002778 }
2779
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002780 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002781
Willy Tarreau7d562212016-11-25 16:10:05 +01002782 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002783
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002784 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002785
2786 if (stkctr == &tmpstkctr)
2787 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002788 }
2789 return 1;
2790}
2791
2792/* set <smp> to the HTTP request error rate from the stream's tracked frontend
2793 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2794 * "src_http_err_rate" only.
2795 */
2796static int
2797smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2798{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002799 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002800 struct stkctr *stkctr;
2801
Emeric Brun819fc6f2017-06-13 19:37:32 +02002802 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002803 if (!stkctr)
2804 return 0;
2805
2806 smp->flags = SMP_F_VOL_TEST;
2807 smp->data.type = SMP_T_SINT;
2808 smp->data.u.sint = 0;
2809 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002810 void *ptr;
2811
2812 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2813 if (!ptr) {
2814 if (stkctr == &tmpstkctr)
2815 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002816 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002817 }
2818
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002819 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002820
Willy Tarreau7d562212016-11-25 16:10:05 +01002821 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2822 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002823
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002824 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002825
2826 if (stkctr == &tmpstkctr)
2827 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002828 }
2829 return 1;
2830}
2831
2832/* set <smp> to the number of kbytes received from clients, as found in the
2833 * stream's tracked frontend counters. Supports being called as
2834 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2835 */
2836static int
2837smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2838{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002839 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002840 struct stkctr *stkctr;
2841
Emeric Brun819fc6f2017-06-13 19:37:32 +02002842 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002843 if (!stkctr)
2844 return 0;
2845
2846 smp->flags = SMP_F_VOL_TEST;
2847 smp->data.type = SMP_T_SINT;
2848 smp->data.u.sint = 0;
2849 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002850 void *ptr;
2851
2852 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2853 if (!ptr) {
2854 if (stkctr == &tmpstkctr)
2855 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002856 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002857 }
2858
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002859 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002860
Willy Tarreau7d562212016-11-25 16:10:05 +01002861 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002862
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002863 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002864
2865 if (stkctr == &tmpstkctr)
2866 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002867 }
2868 return 1;
2869}
2870
2871/* set <smp> to the data rate received from clients in bytes/s, as found
2872 * in the stream's tracked frontend counters. Supports being called as
2873 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2874 */
2875static int
2876smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2877{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002878 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002879 struct stkctr *stkctr;
2880
Emeric Brun819fc6f2017-06-13 19:37:32 +02002881 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002882 if (!stkctr)
2883 return 0;
2884
2885 smp->flags = SMP_F_VOL_TEST;
2886 smp->data.type = SMP_T_SINT;
2887 smp->data.u.sint = 0;
2888 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002889 void *ptr;
2890
2891 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2892 if (!ptr) {
2893 if (stkctr == &tmpstkctr)
2894 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002895 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002896 }
2897
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002898 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002899
Willy Tarreau7d562212016-11-25 16:10:05 +01002900 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2901 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002902
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002903 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002904
2905 if (stkctr == &tmpstkctr)
2906 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002907 }
2908 return 1;
2909}
2910
2911/* set <smp> to the number of kbytes sent to clients, as found in the
2912 * stream's tracked frontend counters. Supports being called as
2913 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2914 */
2915static int
2916smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2917{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002918 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002919 struct stkctr *stkctr;
2920
Emeric Brun819fc6f2017-06-13 19:37:32 +02002921 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002922 if (!stkctr)
2923 return 0;
2924
2925 smp->flags = SMP_F_VOL_TEST;
2926 smp->data.type = SMP_T_SINT;
2927 smp->data.u.sint = 0;
2928 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002929 void *ptr;
2930
2931 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2932 if (!ptr) {
2933 if (stkctr == &tmpstkctr)
2934 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002935 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002936 }
2937
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002938 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002939
Willy Tarreau7d562212016-11-25 16:10:05 +01002940 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
Emeric Brun819fc6f2017-06-13 19:37:32 +02002941
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002942 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002943
2944 if (stkctr == &tmpstkctr)
2945 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002946 }
2947 return 1;
2948}
2949
2950/* set <smp> to the data rate sent to clients in bytes/s, as found in the
2951 * stream's tracked frontend counters. Supports being called as
2952 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2953 */
2954static int
2955smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2956{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002957 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002958 struct stkctr *stkctr;
2959
Emeric Brun819fc6f2017-06-13 19:37:32 +02002960 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01002961 if (!stkctr)
2962 return 0;
2963
2964 smp->flags = SMP_F_VOL_TEST;
2965 smp->data.type = SMP_T_SINT;
2966 smp->data.u.sint = 0;
2967 if (stkctr_entry(stkctr) != NULL) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02002968 void *ptr;
2969
2970 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2971 if (!ptr) {
2972 if (stkctr == &tmpstkctr)
2973 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002974 return 0; /* parameter not stored */
Emeric Brun819fc6f2017-06-13 19:37:32 +02002975 }
2976
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002977 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002978
Willy Tarreau7d562212016-11-25 16:10:05 +01002979 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2980 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002981
Christopher Faulet2a944ee2017-11-07 10:42:54 +01002982 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02002983
2984 if (stkctr == &tmpstkctr)
2985 stktable_release(stkctr->table, stkctr_entry(stkctr));
Willy Tarreau7d562212016-11-25 16:10:05 +01002986 }
2987 return 1;
2988}
2989
2990/* set <smp> to the number of active trackers on the SC entry in the stream's
2991 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2992 */
2993static int
2994smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2995{
Emeric Brun819fc6f2017-06-13 19:37:32 +02002996 struct stkctr tmpstkctr;
Willy Tarreau7d562212016-11-25 16:10:05 +01002997 struct stkctr *stkctr;
2998
Emeric Brun819fc6f2017-06-13 19:37:32 +02002999 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
Willy Tarreau7d562212016-11-25 16:10:05 +01003000 if (!stkctr)
3001 return 0;
3002
3003 smp->flags = SMP_F_VOL_TEST;
3004 smp->data.type = SMP_T_SINT;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003005 if (stkctr == &tmpstkctr) {
3006 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
3007 stktable_release(stkctr->table, stkctr_entry(stkctr));
3008 }
3009 else {
3010 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
3011 }
3012
Willy Tarreau7d562212016-11-25 16:10:05 +01003013 return 1;
3014}
3015
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003016
3017/* The functions below are used to manipulate table contents from the CLI.
3018 * There are 3 main actions, "clear", "set" and "show". The code is shared
3019 * between all actions, and the action is encoded in the void *private in
3020 * the appctx as well as in the keyword registration, among one of the
3021 * following values.
3022 */
3023
3024enum {
3025 STK_CLI_ACT_CLR,
3026 STK_CLI_ACT_SET,
3027 STK_CLI_ACT_SHOW,
3028};
3029
3030/* Dump the status of a table to a stream interface's
3031 * read buffer. It returns 0 if the output buffer is full
3032 * and needs to be called again, otherwise non-zero.
3033 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003034static int table_dump_head_to_buffer(struct buffer *msg,
3035 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003036 struct proxy *proxy, struct proxy *target)
3037{
3038 struct stream *s = si_strm(si);
3039
3040 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
3041 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
3042
3043 /* any other information should be dumped here */
3044
William Lallemand07a62f72017-05-24 00:57:40 +02003045 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003046 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
3047
Willy Tarreau06d80a92017-10-19 14:32:15 +02003048 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003049 si_applet_cant_put(si);
3050 return 0;
3051 }
3052
3053 return 1;
3054}
3055
3056/* Dump a table entry to a stream interface's
3057 * read buffer. It returns 0 if the output buffer is full
3058 * and needs to be called again, otherwise non-zero.
3059 */
Willy Tarreau83061a82018-07-13 11:56:34 +02003060static int table_dump_entry_to_buffer(struct buffer *msg,
3061 struct stream_interface *si,
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003062 struct proxy *proxy, struct stksess *entry)
3063{
3064 int dt;
3065
3066 chunk_appendf(msg, "%p:", entry);
3067
3068 if (proxy->table.type == SMP_T_IPV4) {
3069 char addr[INET_ADDRSTRLEN];
3070 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
3071 chunk_appendf(msg, " key=%s", addr);
3072 }
3073 else if (proxy->table.type == SMP_T_IPV6) {
3074 char addr[INET6_ADDRSTRLEN];
3075 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
3076 chunk_appendf(msg, " key=%s", addr);
3077 }
3078 else if (proxy->table.type == SMP_T_SINT) {
3079 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
3080 }
3081 else if (proxy->table.type == SMP_T_STR) {
3082 chunk_appendf(msg, " key=");
3083 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
3084 }
3085 else {
3086 chunk_appendf(msg, " key=");
3087 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
3088 }
3089
3090 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
3091
3092 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
3093 void *ptr;
3094
3095 if (proxy->table.data_ofs[dt] == 0)
3096 continue;
3097 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
3098 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
3099 else
3100 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
3101
3102 ptr = stktable_data_ptr(&proxy->table, entry, dt);
3103 switch (stktable_data_types[dt].std_type) {
3104 case STD_T_SINT:
3105 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
3106 break;
3107 case STD_T_UINT:
3108 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
3109 break;
3110 case STD_T_ULL:
3111 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
3112 break;
3113 case STD_T_FRQP:
3114 chunk_appendf(msg, "%d",
3115 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3116 proxy->table.data_arg[dt].u));
3117 break;
3118 }
3119 }
3120 chunk_appendf(msg, "\n");
3121
Willy Tarreau06d80a92017-10-19 14:32:15 +02003122 if (ci_putchk(si_ic(si), msg) == -1) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003123 si_applet_cant_put(si);
3124 return 0;
3125 }
3126
3127 return 1;
3128}
3129
3130
3131/* Processes a single table entry matching a specific key passed in argument.
3132 * returns 0 if wants to be called again, 1 if has ended processing.
3133 */
3134static int table_process_entry_per_key(struct appctx *appctx, char **args)
3135{
3136 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003137 struct proxy *px = appctx->ctx.table.target;
3138 struct stksess *ts;
3139 uint32_t uint32_key;
3140 unsigned char ip6_key[sizeof(struct in6_addr)];
3141 long long value;
3142 int data_type;
3143 int cur_arg;
3144 void *ptr;
3145 struct freq_ctr_period *frqp;
3146
3147 if (!*args[4]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003148 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003149 appctx->ctx.cli.msg = "Key value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003150 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003151 return 1;
3152 }
3153
3154 switch (px->table.type) {
3155 case SMP_T_IPV4:
3156 uint32_key = htonl(inetaddr_host(args[4]));
Christopher Fauletca20d022017-08-29 15:30:31 +02003157 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003158 break;
3159 case SMP_T_IPV6:
3160 inet_pton(AF_INET6, args[4], ip6_key);
Christopher Fauletca20d022017-08-29 15:30:31 +02003161 static_table_key.key = &ip6_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003162 break;
3163 case SMP_T_SINT:
3164 {
3165 char *endptr;
3166 unsigned long val;
3167 errno = 0;
3168 val = strtoul(args[4], &endptr, 10);
3169 if ((errno == ERANGE && val == ULONG_MAX) ||
3170 (errno != 0 && val == 0) || endptr == args[4] ||
3171 val > 0xffffffff) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003172 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003173 appctx->ctx.cli.msg = "Invalid key\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003174 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003175 return 1;
3176 }
3177 uint32_key = (uint32_t) val;
Christopher Fauletca20d022017-08-29 15:30:31 +02003178 static_table_key.key = &uint32_key;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003179 break;
3180 }
3181 break;
3182 case SMP_T_STR:
Christopher Fauletca20d022017-08-29 15:30:31 +02003183 static_table_key.key = args[4];
3184 static_table_key.key_len = strlen(args[4]);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003185 break;
3186 default:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003187 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003188 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003189 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003190 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3191 break;
3192 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003193 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003194 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
3195 break;
3196 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003197 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003198 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
3199 break;
3200 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003201 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003202 appctx->ctx.cli.msg = "Unknown action\n";
3203 break;
3204 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003205 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003206 return 1;
3207 }
3208
3209 /* check permissions */
3210 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3211 return 1;
3212
Willy Tarreaua24bc782016-12-14 15:50:35 +01003213 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003214 case STK_CLI_ACT_SHOW:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003215 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003216 if (!ts)
3217 return 1;
3218 chunk_reset(&trash);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003219 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
3220 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003221 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003222 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003223 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003224 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003225 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003226 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003227 return 0;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003228 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003229 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003230 stktable_release(&px->table, ts);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003231 break;
3232
3233 case STK_CLI_ACT_CLR:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003234 ts = stktable_lookup_key(&px->table, &static_table_key);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003235 if (!ts)
3236 return 1;
Emeric Brun819fc6f2017-06-13 19:37:32 +02003237
3238 if (!stksess_kill(&px->table, ts, 1)) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003239 /* don't delete an entry which is currently referenced */
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003240 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003241 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003242 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003243 return 1;
3244 }
Emeric Brun819fc6f2017-06-13 19:37:32 +02003245
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003246 break;
3247
3248 case STK_CLI_ACT_SET:
Emeric Brun819fc6f2017-06-13 19:37:32 +02003249 ts = stktable_get_entry(&px->table, &static_table_key);
3250 if (!ts) {
3251 /* don't delete an entry which is currently referenced */
3252 appctx->ctx.cli.severity = LOG_ERR;
3253 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
3254 appctx->st0 = CLI_ST_PRINT;
3255 return 1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003256 }
3257
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003258 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003259 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
3260 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003261 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003262 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003263 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003264 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003265 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003266 return 1;
3267 }
3268
3269 data_type = stktable_get_data_type(args[cur_arg] + 5);
3270 if (data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003271 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003272 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003273 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003274 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003275 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003276 return 1;
3277 }
3278
3279 if (!px->table.data_ofs[data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003280 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003281 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003282 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003283 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003284 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003285 return 1;
3286 }
3287
3288 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003289 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003290 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003291 appctx->st0 = CLI_ST_PRINT;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003292 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003293 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003294 return 1;
3295 }
3296
3297 ptr = stktable_data_ptr(&px->table, ts, data_type);
3298
3299 switch (stktable_data_types[data_type].std_type) {
3300 case STD_T_SINT:
3301 stktable_data_cast(ptr, std_t_sint) = value;
3302 break;
3303 case STD_T_UINT:
3304 stktable_data_cast(ptr, std_t_uint) = value;
3305 break;
3306 case STD_T_ULL:
3307 stktable_data_cast(ptr, std_t_ull) = value;
3308 break;
3309 case STD_T_FRQP:
3310 /* We set both the current and previous values. That way
3311 * the reported frequency is stable during all the period
3312 * then slowly fades out. This allows external tools to
3313 * push measures without having to update them too often.
3314 */
3315 frqp = &stktable_data_cast(ptr, std_t_frqp);
Emeric Brunf2fc1fd2017-11-02 17:32:43 +01003316 /* First bit is reserved for the freq_ctr_period lock
3317 Note: here we're still protected by the stksess lock
3318 so we don't need to update the update the freq_ctr_period
3319 using its internal lock */
3320 frqp->curr_tick = now_ms & ~0x1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003321 frqp->prev_ctr = 0;
3322 frqp->curr_ctr = value;
3323 break;
3324 }
3325 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003326 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003327 stktable_touch_local(&px->table, ts, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003328 break;
3329
3330 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003331 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003332 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003333 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003334 break;
3335 }
3336 return 1;
3337}
3338
3339/* Prepares the appctx fields with the data-based filters from the command line.
3340 * Returns 0 if the dump can proceed, 1 if has ended processing.
3341 */
3342static int table_prepare_data_request(struct appctx *appctx, char **args)
3343{
Willy Tarreaua24bc782016-12-14 15:50:35 +01003344 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003345 appctx->ctx.cli.severity = LOG_ERR;
Aurélien Nephtali6e8a41d2018-03-15 21:48:50 +01003346 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003347 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003348 return 1;
3349 }
3350
3351 /* condition on stored data value */
3352 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3353 if (appctx->ctx.table.data_type < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003354 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003355 appctx->ctx.cli.msg = "Unknown data type\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003356 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003357 return 1;
3358 }
3359
3360 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003361 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003362 appctx->ctx.cli.msg = "Data type not stored in this table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003363 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003364 return 1;
3365 }
3366
3367 appctx->ctx.table.data_op = get_std_op(args[4]);
3368 if (appctx->ctx.table.data_op < 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003369 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003370 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003371 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003372 return 1;
3373 }
3374
3375 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003376 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003377 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003378 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003379 return 1;
3380 }
3381
3382 /* OK we're done, all the fields are set */
3383 return 0;
3384}
3385
3386/* returns 0 if wants to be called, 1 if has ended processing */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02003387static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003388{
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003389 appctx->ctx.table.data_type = -1;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003390 appctx->ctx.table.target = NULL;
3391 appctx->ctx.table.proxy = NULL;
3392 appctx->ctx.table.entry = NULL;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003393 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003394
3395 if (*args[2]) {
3396 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3397 if (!appctx->ctx.table.target) {
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003398 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003399 appctx->ctx.cli.msg = "No such table\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003400 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003401 return 1;
3402 }
3403 }
3404 else {
Willy Tarreaua24bc782016-12-14 15:50:35 +01003405 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003406 goto err_args;
3407 return 0;
3408 }
3409
3410 if (strcmp(args[3], "key") == 0)
3411 return table_process_entry_per_key(appctx, args);
3412 else if (strncmp(args[3], "data.", 5) == 0)
3413 return table_prepare_data_request(appctx, args);
3414 else if (*args[3])
3415 goto err_args;
3416
3417 return 0;
3418
3419err_args:
Willy Tarreaua24bc782016-12-14 15:50:35 +01003420 switch (appctx->ctx.table.action) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003421 case STK_CLI_ACT_SHOW:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003422 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003423 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3424 break;
3425 case STK_CLI_ACT_CLR:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003426 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003427 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3428 break;
3429 case STK_CLI_ACT_SET:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003430 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003431 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3432 break;
3433 default:
Andjelko Iharosc3680ec2017-07-20 16:49:14 +02003434 appctx->ctx.cli.severity = LOG_ERR;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003435 appctx->ctx.cli.msg = "Unknown action\n";
3436 break;
3437 }
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003438 appctx->st0 = CLI_ST_PRINT;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003439 return 1;
3440}
3441
3442/* This function is used to deal with table operations (dump or clear depending
3443 * on the action stored in appctx->private). It returns 0 if the output buffer is
3444 * full and it needs to be called again, otherwise non-zero.
3445 */
3446static int cli_io_handler_table(struct appctx *appctx)
3447{
3448 struct stream_interface *si = appctx->owner;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003449 struct stream *s = si_strm(si);
3450 struct ebmb_node *eb;
3451 int dt;
3452 int skip_entry;
Willy Tarreaua24bc782016-12-14 15:50:35 +01003453 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003454
3455 /*
3456 * We have 3 possible states in appctx->st2 :
3457 * - STAT_ST_INIT : the first call
3458 * - STAT_ST_INFO : the proxy pointer points to the next table to
3459 * dump, the entry pointer is NULL ;
3460 * - STAT_ST_LIST : the proxy pointer points to the current table
3461 * and the entry pointer points to the next entry to be dumped,
3462 * and the refcount on the next entry is held ;
3463 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3464 * data though.
3465 */
3466
3467 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3468 /* in case of abort, remove any refcount we might have set on an entry */
3469 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003470 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003471 }
3472 return 1;
3473 }
3474
3475 chunk_reset(&trash);
3476
3477 while (appctx->st2 != STAT_ST_FIN) {
3478 switch (appctx->st2) {
3479 case STAT_ST_INIT:
3480 appctx->ctx.table.proxy = appctx->ctx.table.target;
3481 if (!appctx->ctx.table.proxy)
Olivier Houchardfbc74e82017-11-24 16:54:05 +01003482 appctx->ctx.table.proxy = proxies_list;
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003483
3484 appctx->ctx.table.entry = NULL;
3485 appctx->st2 = STAT_ST_INFO;
3486 break;
3487
3488 case STAT_ST_INFO:
3489 if (!appctx->ctx.table.proxy ||
3490 (appctx->ctx.table.target &&
3491 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3492 appctx->st2 = STAT_ST_END;
3493 break;
3494 }
3495
3496 if (appctx->ctx.table.proxy->table.size) {
3497 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3498 return 0;
3499
3500 if (appctx->ctx.table.target &&
William Lallemand07a62f72017-05-24 00:57:40 +02003501 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003502 /* dump entries only if table explicitly requested */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003503 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003504 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3505 if (eb) {
3506 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3507 appctx->ctx.table.entry->ref_cnt++;
3508 appctx->st2 = STAT_ST_LIST;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003509 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003510 break;
3511 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003512 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003513 }
3514 }
3515 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3516 break;
3517
3518 case STAT_ST_LIST:
3519 skip_entry = 0;
3520
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003521 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003522
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003523 if (appctx->ctx.table.data_type >= 0) {
3524 /* we're filtering on some data contents */
3525 void *ptr;
3526 long long data;
3527
Emeric Brun819fc6f2017-06-13 19:37:32 +02003528
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003529 dt = appctx->ctx.table.data_type;
3530 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3531 appctx->ctx.table.entry,
3532 dt);
3533
3534 data = 0;
3535 switch (stktable_data_types[dt].std_type) {
3536 case STD_T_SINT:
3537 data = stktable_data_cast(ptr, std_t_sint);
3538 break;
3539 case STD_T_UINT:
3540 data = stktable_data_cast(ptr, std_t_uint);
3541 break;
3542 case STD_T_ULL:
3543 data = stktable_data_cast(ptr, std_t_ull);
3544 break;
3545 case STD_T_FRQP:
3546 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3547 appctx->ctx.table.proxy->table.data_arg[dt].u);
3548 break;
3549 }
3550
3551 /* skip the entry if the data does not match the test and the value */
3552 if ((data < appctx->ctx.table.value &&
3553 (appctx->ctx.table.data_op == STD_OP_EQ ||
3554 appctx->ctx.table.data_op == STD_OP_GT ||
3555 appctx->ctx.table.data_op == STD_OP_GE)) ||
3556 (data == appctx->ctx.table.value &&
3557 (appctx->ctx.table.data_op == STD_OP_NE ||
3558 appctx->ctx.table.data_op == STD_OP_GT ||
3559 appctx->ctx.table.data_op == STD_OP_LT)) ||
3560 (data > appctx->ctx.table.value &&
3561 (appctx->ctx.table.data_op == STD_OP_EQ ||
3562 appctx->ctx.table.data_op == STD_OP_LT ||
3563 appctx->ctx.table.data_op == STD_OP_LE)))
3564 skip_entry = 1;
3565 }
3566
3567 if (show && !skip_entry &&
Emeric Brun819fc6f2017-06-13 19:37:32 +02003568 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003569 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003570 return 0;
3571 }
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003572
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003573 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
Emeric Brun819fc6f2017-06-13 19:37:32 +02003574
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003575 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003576 appctx->ctx.table.entry->ref_cnt--;
3577
3578 eb = ebmb_next(&appctx->ctx.table.entry->key);
3579 if (eb) {
3580 struct stksess *old = appctx->ctx.table.entry;
3581 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3582 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003583 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003584 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003585 __stksess_kill(&appctx->ctx.table.proxy->table, old);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003586 appctx->ctx.table.entry->ref_cnt++;
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003587 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003588 break;
3589 }
3590
3591
3592 if (show)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003593 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003594 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
Emeric Brun819fc6f2017-06-13 19:37:32 +02003595 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3596
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003597 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003598
3599 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3600 appctx->st2 = STAT_ST_INFO;
3601 break;
3602
3603 case STAT_ST_END:
3604 appctx->st2 = STAT_ST_FIN;
3605 break;
3606 }
3607 }
3608 return 1;
3609}
3610
3611static void cli_release_show_table(struct appctx *appctx)
3612{
3613 if (appctx->st2 == STAT_ST_LIST) {
Emeric Brun819fc6f2017-06-13 19:37:32 +02003614 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003615 }
3616}
3617
3618/* register cli keywords */
3619static struct cli_kw_list cli_kws = {{ },{
3620 { { "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 },
3621 { { "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 },
3622 { { "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 },
3623 {{},}
3624}};
3625
3626
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003627static struct action_kw_list tcp_conn_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003628 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003629 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003630 { "sc-set-gpt0", parse_set_gpt0, 1 },
3631 { /* END */ }
3632}};
3633
Willy Tarreau620408f2016-10-21 16:37:51 +02003634static struct action_kw_list tcp_sess_kws = { { }, {
3635 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003636 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Willy Tarreau620408f2016-10-21 16:37:51 +02003637 { "sc-set-gpt0", parse_set_gpt0, 1 },
3638 { /* END */ }
3639}};
3640
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003641static struct action_kw_list tcp_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003642 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003643 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003644 { "sc-set-gpt0", parse_set_gpt0, 1 },
3645 { /* END */ }
3646}};
3647
3648static struct action_kw_list tcp_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003649 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003650 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003651 { "sc-set-gpt0", parse_set_gpt0, 1 },
3652 { /* END */ }
3653}};
3654
3655static struct action_kw_list http_req_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003656 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003657 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003658 { "sc-set-gpt0", parse_set_gpt0, 1 },
3659 { /* END */ }
3660}};
3661
3662static struct action_kw_list http_res_kws = { { }, {
Thierry FOURNIERe0627bd2015-08-04 08:20:33 +02003663 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
Frédéric Lécaille6778b272018-01-29 15:22:53 +01003664 { "sc-inc-gpc1", parse_inc_gpc1, 1 },
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003665 { "sc-set-gpt0", parse_set_gpt0, 1 },
3666 { /* END */ }
3667}};
3668
Willy Tarreau7d562212016-11-25 16:10:05 +01003669///* Note: must not be declared <const> as its list will be overwritten.
3670// * Please take care of keeping this list alphabetically sorted.
3671// */
3672//static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3673// { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3674// { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3675// { /* END */ },
3676//}};
3677/* Note: must not be declared <const> as its list will be overwritten.
3678 * Please take care of keeping this list alphabetically sorted.
3679 */
3680static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3681 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3682 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3683 { "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 +01003684 { "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 +01003685 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3686 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3687 { "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 +01003688 { "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 +01003689 { "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 +01003690 { "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 +01003691 { "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 +01003692 { "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 +01003693 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3694 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3695 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3696 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3697 { "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 +01003698 { "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 +01003699 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3700 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3701 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3702 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3703 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3704 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3705 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3706 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3707 { "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 +01003708 { "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 +01003709 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3710 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3711 { "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 +01003712 { "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 +01003713 { "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 +01003714 { "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 +01003715 { "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 +01003716 { "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 +01003717 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3718 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3719 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3720 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3721 { "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 +01003722 { "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 +01003723 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3724 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3725 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3726 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3727 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3728 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3729 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3730 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3731 { "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 +01003732 { "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 +01003733 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3734 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3735 { "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 +01003736 { "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 +01003737 { "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 +01003738 { "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 +01003739 { "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 +01003740 { "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 +01003741 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3742 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3743 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3744 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3745 { "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 +01003746 { "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 +01003747 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3748 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3749 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3750 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3751 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3752 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3753 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3754 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3755 { "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 +01003756 { "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 +01003757 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3758 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3759 { "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 +01003760 { "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 +01003761 { "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 +01003762 { "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 +01003763 { "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 +01003764 { "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 +01003765 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3766 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3767 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3768 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3769 { "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 +01003770 { "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 +01003771 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3772 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3773 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3774 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3775 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3776 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3777 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3778 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3779 { "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 +01003780 { "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 +01003781 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3782 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3783 { "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 +01003784 { "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 +01003785 { "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 +01003786 { "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 +01003787 { "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 +01003788 { "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 +01003789 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3790 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3791 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3792 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3793 { "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 +01003794 { "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 +01003795 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3796 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3797 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3798 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3799 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3800 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3801 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3802 { /* END */ },
3803}};
3804
3805
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003806/* Note: must not be declared <const> as its list will be overwritten */
3807static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Willy Tarreau2d17db52016-05-25 17:16:38 +02003808 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3809 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3810 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3811 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3812 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3813 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3814 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3815 { "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 +01003816 { "table_gpc1", sample_conv_table_gpc1, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreau2d17db52016-05-25 17:16:38 +02003817 { "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 +01003818 { "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 +02003819 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3820 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3821 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3822 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3823 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3824 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3825 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3826 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3827 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3828 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003829 { /* END */ },
3830}};
3831
3832__attribute__((constructor))
3833static void __stick_table_init(void)
3834{
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003835 /* register som action keywords. */
3836 tcp_req_conn_keywords_register(&tcp_conn_kws);
Willy Tarreau620408f2016-10-21 16:37:51 +02003837 tcp_req_sess_keywords_register(&tcp_sess_kws);
Thierry FOURNIER236657b2015-08-19 08:25:14 +02003838 tcp_req_cont_keywords_register(&tcp_req_kws);
3839 tcp_res_cont_keywords_register(&tcp_res_kws);
3840 http_req_keywords_register(&http_req_kws);
3841 http_res_keywords_register(&http_res_kws);
3842
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003843 /* register sample fetch and format conversion keywords */
Willy Tarreau7d562212016-11-25 16:10:05 +01003844 sample_register_fetches(&smp_fetch_keywords);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003845 sample_register_convs(&sample_conv_kws);
Willy Tarreauf13ebdf2016-11-22 18:00:53 +01003846 cli_register_kw(&cli_kws);
Willy Tarreaud9f316a2014-07-10 14:03:38 +02003847}