1 /*
2 * Stick tables management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
5 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
6 *
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>
15 #include <errno.h>
16
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
26 #include <types/cli.h>
27 #include <types/global.h>
28 #include <types/stats.h>
29
30 #include <proto/arg.h>
31 #include <proto/cli.h>
32 #include <proto/log.h>
33 #include <proto/proto_http.h>
34 #include <proto/proto_tcp.h>
35 #include <proto/proxy.h>
36 #include <proto/sample.h>
37 #include <proto/stream.h>
38 #include <proto/stream_interface.h>
39 #include <proto/stick_table.h>
40 #include <proto/task.h>
41 #include <proto/peers.h>
42 #include <proto/tcp_rules.h>
43
44 /* structure used to return a table key built from a sample */
45 static THREAD_LOCAL struct stktable_key static_table_key;
46
47 #define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
48 /*
49 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
50 * in table <t>.
51 */
__stksess_free(struct stktable * t,struct stksess * ts)52 void __stksess_free(struct stktable *t, struct stksess *ts)
53 {
54 t->current--;
55 pool_free(t->pool, (void *)ts - round_ptr_size(t->data_size));
56 }
57
58 /*
59 * Free an allocated sticky session <ts>, and decrease sticky sessions counter
60 * in table <t>.
61 * This function locks the table
62 */
stksess_free(struct stktable * t,struct stksess * ts)63 void stksess_free(struct stktable *t, struct stksess *ts)
64 {
65 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
66 __stksess_free(t, ts);
67 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
68 }
69
70 /*
71 * Kill an stksess (only if its ref_cnt is zero).
72 */
__stksess_kill(struct stktable * t,struct stksess * ts)73 int __stksess_kill(struct stktable *t, struct stksess *ts)
74 {
75 if (ts->ref_cnt)
76 return 0;
77
78 eb32_delete(&ts->exp);
79 eb32_delete(&ts->upd);
80 ebmb_delete(&ts->key);
81 __stksess_free(t, ts);
82 return 1;
83 }
84
85 /*
86 * Decrease the refcount if decrefcnt is not 0.
87 * and try to kill the stksess
88 * This function locks the table
89 */
stksess_kill(struct stktable * t,struct stksess * ts,int decrefcnt)90 int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcnt)
91 {
92 int ret;
93
94 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
95 if (decrefcnt)
96 ts->ref_cnt--;
97 ret = __stksess_kill(t, ts);
98 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
99
100 return ret;
101 }
102
103 /*
104 * Initialize or update the key in the sticky session <ts> present in table <t>
105 * from the value present in <key>.
106 */
stksess_setkey(struct stktable * t,struct stksess * ts,struct stktable_key * key)107 void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
108 {
109 if (t->type != SMP_T_STR)
110 memcpy(ts->key.key, key->key, t->key_size);
111 else {
112 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;
114 }
115 }
116
117
118 /*
119 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
120 * is returned.
121 */
__stksess_init(struct stktable * t,struct stksess * ts)122 static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
123 {
124 memset((void *)ts - t->data_size, 0, t->data_size);
125 ts->ref_cnt = 0;
126 ts->key.node.leaf_p = NULL;
127 ts->exp.node.leaf_p = NULL;
128 ts->upd.node.leaf_p = NULL;
129 ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
130 HA_RWLOCK_INIT(&ts->lock);
131 return ts;
132 }
133
134 /*
135 * Trash oldest <to_batch> sticky sessions from table <t>
136 * Returns number of trashed sticky sessions.
137 */
__stktable_trash_oldest(struct stktable * t,int to_batch)138 int __stktable_trash_oldest(struct stktable *t, int to_batch)
139 {
140 struct stksess *ts;
141 struct eb32_node *eb;
142 int batched = 0;
143 int looped = 0;
144
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
152 * half. Let's loop back to the beginning of the tree now if we
153 * have not yet visited it.
154 */
155 if (looped)
156 break;
157 looped = 1;
158 eb = eb32_first(&t->exps);
159 if (likely(!eb))
160 break;
161 }
162
163 /* timer looks expired, detach it from the queue */
164 ts = eb32_entry(eb, struct stksess, exp);
165 eb = eb32_next(eb);
166
167 /* don't delete an entry which is currently referenced */
168 if (ts->ref_cnt)
169 continue;
170
171 eb32_delete(&ts->exp);
172
173 if (ts->expire != ts->exp.key) {
174 if (!tick_isset(ts->expire))
175 continue;
176
177 ts->exp.key = ts->expire;
178 eb32_insert(&t->exps, &ts->exp);
179
180 if (!eb || eb->key > ts->exp.key)
181 eb = &ts->exp;
182
183 continue;
184 }
185
186 /* session expired, trash it */
187 ebmb_delete(&ts->key);
188 eb32_delete(&ts->upd);
189 __stksess_free(t, ts);
190 batched++;
191 }
192
193 return batched;
194 }
195
196 /*
197 * Trash oldest <to_batch> sticky sessions from table <t>
198 * Returns number of trashed sticky sessions.
199 * This function locks the table
200 */
stktable_trash_oldest(struct stktable * t,int to_batch)201 int stktable_trash_oldest(struct stktable *t, int to_batch)
202 {
203 int ret;
204
205 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
206 ret = __stktable_trash_oldest(t, to_batch);
207 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
208
209 return ret;
210 }
211 /*
212 * 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
215 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
216 * is not NULL, it is assigned to the new session.
217 */
__stksess_new(struct stktable * t,struct stktable_key * key)218 struct stksess *__stksess_new(struct stktable *t, struct stktable_key *key)
219 {
220 struct stksess *ts;
221
222 if (unlikely(t->current == t->size)) {
223 if ( t->nopurge )
224 return NULL;
225
226 if (!__stktable_trash_oldest(t, (t->size >> 8) + 1))
227 return NULL;
228 }
229
230 ts = pool_alloc(t->pool);
231 if (ts) {
232 t->current++;
233 ts = (void *)ts + round_ptr_size(t->data_size);
234 __stksess_init(t, ts);
235 if (key)
236 stksess_setkey(t, ts, key);
237 }
238
239 return ts;
240 }
241 /*
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 */
stksess_new(struct stktable * t,struct stktable_key * key)249 struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
250 {
251 struct stksess *ts;
252
253 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
254 ts = __stksess_new(t, key);
255 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
256
257 return ts;
258 }
259
260 /*
261 * Looks in table <t> for a sticky session matching key <key>.
262 * Returns pointer on requested sticky session or NULL if none was found.
263 */
__stktable_lookup_key(struct stktable * t,struct stktable_key * key)264 struct stksess *__stktable_lookup_key(struct stktable *t, struct stktable_key *key)
265 {
266 struct ebmb_node *eb;
267
268 if (t->type == SMP_T_STR)
269 eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1);
270 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
278 return ebmb_entry(eb, struct stksess, key);
279 }
280
281 /*
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
286 */
stktable_lookup_key(struct stktable * t,struct stktable_key * key)287 struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
288 {
289 struct stksess *ts;
290
291 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
292 ts = __stktable_lookup_key(t, key);
293 if (ts)
294 ts->ref_cnt++;
295 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
296
297 return ts;
298 }
299
300 /*
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.
303 */
__stktable_lookup(struct stktable * t,struct stksess * ts)304 struct stksess *__stktable_lookup(struct stktable *t, struct stksess *ts)
305 {
306 struct ebmb_node *eb;
307
308 if (t->type == SMP_T_STR)
309 eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
310 else
311 eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
312
313 if (unlikely(!eb))
314 return NULL;
315
316 return ebmb_entry(eb, struct stksess, key);
317 }
318
319 /*
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 */
stktable_lookup(struct stktable * t,struct stksess * ts)325 struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
326 {
327 struct stksess *lts;
328
329 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
330 lts = __stktable_lookup(t, ts);
331 if (lts)
332 lts->ref_cnt++;
333 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
334
335 return lts;
336 }
337
338 /* Update the expiration timer for <ts> but do not touch its expiration node.
339 * The table's expiration timer is updated if set.
340 * 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
342 */
__stktable_touch_with_exp(struct stktable * t,struct stksess * ts,int local,int expire)343 void __stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, int expire)
344 {
345 struct eb32_node * eb;
346 ts->expire = expire;
347 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 }
351
352 /* 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 }
368 }
369 task_wakeup(t->sync_task, TASK_WOKEN_MSG);
370 }
371 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 }
382 }
383 }
384
385 /* Update the expiration timer for <ts> but do not touch its expiration node.
386 * The table's expiration timer is updated using the date of expiration coming from
387 * <t> stick-table configuration.
388 * 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
390 */
stktable_touch_remote(struct stktable * t,struct stksess * ts,int decrefcnt)391 void stktable_touch_remote(struct stktable *t, struct stksess *ts, int decrefcnt)
392 {
393 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
394 __stktable_touch_with_exp(t, ts, 0, ts->expire);
395 if (decrefcnt)
396 ts->ref_cnt--;
397 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
398 }
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 */
stktable_touch_local(struct stktable * t,struct stksess * ts,int decrefcnt)406 void stktable_touch_local(struct stktable *t, struct stksess *ts, int decrefcnt)
407 {
408 int expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
409
410 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
411 __stktable_touch_with_exp(t, ts, 1, expire);
412 if (decrefcnt)
413 ts->ref_cnt--;
414 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
415 }
416 /* Just decrease the ref_cnt of the current session. Does nothing if <ts> is NULL */
stktable_release(struct stktable * t,struct stksess * ts)417 static void stktable_release(struct stktable *t, struct stksess *ts)
418 {
419 if (!ts)
420 return;
421 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
422 ts->ref_cnt--;
423 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
424 }
425
426 /* 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 */
__stktable_store(struct stktable * t,struct stksess * ts)430 void __stktable_store(struct stktable *t, struct stksess *ts)
431 {
432
433 ebmb_insert(&t->keys, &ts->key, t->key_size);
434 ts->exp.key = ts->expire;
435 eb32_insert(&t->exps, &ts->exp);
436 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 }
440 }
441
442 /* 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 */
__stktable_get_entry(struct stktable * table,struct stktable_key * key)446 struct stksess *__stktable_get_entry(struct stktable *table, struct stktable_key *key)
447 {
448 struct stksess *ts;
449
450 if (!key)
451 return NULL;
452
453 ts = __stktable_lookup_key(table, key);
454 if (ts == NULL) {
455 /* entry does not exist, initialize a new one */
456 ts = __stksess_new(table, key);
457 if (!ts)
458 return NULL;
459 __stktable_store(table, ts);
460 }
461 return ts;
462 }
463 /* 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 */
stktable_get_entry(struct stktable * table,struct stktable_key * key)468 struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
469 {
470 struct stksess *ts;
471
472 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
473 ts = __stktable_get_entry(table, key);
474 if (ts)
475 ts->ref_cnt++;
476 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
477
478 return ts;
479 }
480
481 /* Lookup for an entry with the same key and store the submitted
482 * stksess if not found.
483 */
__stktable_set_entry(struct stktable * table,struct stksess * nts)484 struct 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 */
stktable_set_entry(struct stktable * table,struct stksess * nts)500 struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
501 {
502 struct stksess *ts;
503
504 HA_SPIN_LOCK(STK_TABLE_LOCK, &table->lock);
505 ts = __stktable_set_entry(table, nts);
506 ts->ref_cnt++;
507 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &table->lock);
508
509 return ts;
510 }
511 /*
512 * Trash expired sticky sessions from table <t>. The next expiration date is
513 * returned.
514 */
stktable_trash_expired(struct stktable * t)515 static int stktable_trash_expired(struct stktable *t)
516 {
517 struct stksess *ts;
518 struct eb32_node *eb;
519 int looped = 0;
520
521 HA_SPIN_LOCK(STK_TABLE_LOCK, &t->lock);
522 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
528 * half. Let's loop back to the beginning of the tree now if we
529 * have not yet visited it.
530 */
531 if (looped)
532 break;
533 looped = 1;
534 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;
542 goto out_unlock;
543 }
544
545 /* timer looks expired, detach it from the queue */
546 ts = eb32_entry(eb, struct stksess, exp);
547 eb = eb32_next(eb);
548
549 /* don't delete an entry which is currently referenced */
550 if (ts->ref_cnt)
551 continue;
552
553 eb32_delete(&ts->exp);
554
555 if (!tick_is_expired(ts->expire, now_ms)) {
556 if (!tick_isset(ts->expire))
557 continue;
558
559 ts->exp.key = ts->expire;
560 eb32_insert(&t->exps, &ts->exp);
561
562 if (!eb || eb->key > ts->exp.key)
563 eb = &ts->exp;
564 continue;
565 }
566
567 /* session expired, trash it */
568 ebmb_delete(&ts->key);
569 eb32_delete(&ts->upd);
570 __stksess_free(t, ts);
571 }
572
573 /* We have found no task to expire in any tree */
574 t->exp_next = TICK_ETERNITY;
575 out_unlock:
576 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock);
577 return t->exp_next;
578 }
579
580 /*
581 * Task processing function to trash expired sticky sessions. A pointer to the
582 * task itself is returned since it never dies.
583 */
process_table_expire(struct task * task)584 static struct task *process_table_expire(struct task *task)
585 {
586 struct stktable *t = task->context;
587
588 task->expire = stktable_trash_expired(t);
589 return task;
590 }
591
592 /* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
stktable_init(struct stktable * t)593 int stktable_init(struct stktable *t)
594 {
595 if (t->size) {
596 t->keys = EB_ROOT_UNIQUE;
597 memset(&t->exps, 0, sizeof(t->exps));
598 t->updates = EB_ROOT_UNIQUE;
599 HA_SPIN_INIT(&t->lock);
600
601 t->pool = create_pool("sticktables", sizeof(struct stksess) + round_ptr_size(t->data_size) + t->key_size, MEM_F_SHARED);
602
603 t->exp_next = TICK_ETERNITY;
604 if ( t->expire ) {
605 t->exp_task = task_new(MAX_THREADS_MASK);
606 if (!t->exp_task)
607 return 0;
608 t->exp_task->process = process_table_expire;
609 t->exp_task->context = (void *)t;
610 }
611 if (t->peers.p && t->peers.p->peers_fe && t->peers.p->peers_fe->state != PR_STSTOPPED) {
612 peers_register_table(t->peers.p, t);
613 }
614
615 return t->pool != NULL;
616 }
617 return 1;
618 }
619
620 /*
621 * Configuration keywords of known table types
622 */
623 struct stktable_type stktable_types[SMP_TYPES] = {
624 [SMP_T_SINT] = { "integer", 0, 4 },
625 [SMP_T_IPV4] = { "ip", 0, 4 },
626 [SMP_T_IPV6] = { "ipv6", 0, 16 },
627 [SMP_T_STR] = { "string", STK_F_CUSTOM_KEYSIZE, 32 },
628 [SMP_T_BIN] = { "binary", STK_F_CUSTOM_KEYSIZE, 32 }
629 };
630
631 /*
632 * Parse table type configuration.
633 * Returns 0 on successful parsing, else 1.
634 * <myidx> is set at next configuration <args> index.
635 */
stktable_parse_type(char ** args,int * myidx,unsigned long * type,size_t * key_size)636 int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *key_size)
637 {
638 for (*type = 0; *type < SMP_TYPES; (*type)++) {
639 if (!stktable_types[*type].kw)
640 continue;
641 if (strcmp(args[*myidx], stktable_types[*type].kw) != 0)
642 continue;
643
644 *key_size = stktable_types[*type].default_size;
645 (*myidx)++;
646
647 if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
648 if (strcmp("len", args[*myidx]) == 0) {
649 (*myidx)++;
650 *key_size = atol(args[*myidx]);
651 if (!*key_size)
652 break;
653 if (*type == SMP_T_STR) {
654 /* null terminated string needs +1 for '\0'. */
655 (*key_size)++;
656 }
657 (*myidx)++;
658 }
659 }
660 return 0;
661 }
662 return 1;
663 }
664
665 /* Prepares a stktable_key from a sample <smp> to search into table <t>.
666 * Note that the sample *is* modified and that the returned key may point
667 * to it, so the sample must not be modified afterwards before the lookup.
668 * Returns NULL if the sample could not be converted (eg: no matching type),
669 * otherwise a pointer to the static stktable_key filled with what is needed
670 * for the lookup.
671 */
smp_to_stkey(struct sample * smp,struct stktable * t)672 struct stktable_key *smp_to_stkey(struct sample *smp, struct stktable *t)
673 {
674 /* Convert sample. */
675 if (!sample_convert(smp, t->type))
676 return NULL;
677
678 /* Fill static_table_key. */
679 switch (t->type) {
680
681 case SMP_T_IPV4:
682 static_table_key.key = &smp->data.u.ipv4;
683 static_table_key.key_len = 4;
684 break;
685
686 case SMP_T_IPV6:
687 static_table_key.key = &smp->data.u.ipv6;
688 static_table_key.key_len = 16;
689 break;
690
691 case SMP_T_SINT:
692 /* The stick table require a 32bit unsigned int, "sint" is a
693 * signed 64 it, so we can convert it inplace.
694 */
695 smp->data.u.sint = (unsigned int)smp->data.u.sint;
696 static_table_key.key = &smp->data.u.sint;
697 static_table_key.key_len = 4;
698 break;
699
700 case SMP_T_STR:
701 if (!smp_make_safe(smp))
702 return NULL;
703 static_table_key.key = smp->data.u.str.str;
704 static_table_key.key_len = smp->data.u.str.len;
705 break;
706
707 case SMP_T_BIN:
708 if (smp->data.u.str.len < t->key_size) {
709 /* This type needs padding with 0. */
710 if (!smp_make_rw(smp))
711 return NULL;
712
713 if (smp->data.u.str.size < t->key_size)
714 if (!smp_dup(smp))
715 return NULL;
716 if (smp->data.u.str.size < t->key_size)
717 return NULL;
718 memset(smp->data.u.str.str + smp->data.u.str.len, 0,
719 t->key_size - smp->data.u.str.len);
720 smp->data.u.str.len = t->key_size;
721 }
722 static_table_key.key = smp->data.u.str.str;
723 static_table_key.key_len = smp->data.u.str.len;
724 break;
725
726 default: /* impossible case. */
727 return NULL;
728 }
729
730 return &static_table_key;
731 }
732
733 /*
734 * Process a fetch + format conversion as defined by the sample expression <expr>
735 * on request or response considering the <opt> parameter. Returns either NULL if
736 * no key could be extracted, or a pointer to the converted result stored in
737 * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
738 * and its flags will be initialized so that the caller gets a copy of the input
739 * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present
740 * without SMP_OPT_FINAL). The output will be usable like this :
741 *
742 * return MAY_CHANGE FINAL Meaning for the sample
743 * NULL 0 * Not present and will never be (eg: header)
744 * NULL 1 0 Not present or unstable, could change (eg: req_len)
745 * NULL 1 1 Not present, will not change anymore
746 * smp 0 * Present and will not change (eg: header)
747 * smp 1 0 not possible
748 * smp 1 1 Present, last known value (eg: request length)
749 */
stktable_fetch_key(struct stktable * t,struct proxy * px,struct session * sess,struct stream * strm,unsigned int opt,struct sample_expr * expr,struct sample * smp)750 struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *sess, struct stream *strm,
751 unsigned int opt, struct sample_expr *expr, struct sample *smp)
752 {
753 if (smp)
754 memset(smp, 0, sizeof(*smp));
755
756 smp = sample_process(px, sess, strm, opt, expr, smp);
757 if (!smp)
758 return NULL;
759
760 if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
761 return NULL; /* we can only use stable samples */
762
763 return smp_to_stkey(smp, t);
764 }
765
766 /*
767 * Returns 1 if sample expression <expr> result can be converted to table key of
768 * type <table_type>, otherwise zero. Used in configuration check.
769 */
stktable_compatible_sample(struct sample_expr * expr,unsigned long table_type)770 int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
771 {
772 int out_type;
773
774 if (table_type >= SMP_TYPES || !stktable_types[table_type].kw)
775 return 0;
776
777 out_type = smp_expr_output_type(expr);
778
779 /* Convert sample. */
780 if (!sample_casts[out_type][table_type])
781 return 0;
782
783 return 1;
784 }
785
786 /* Extra data types processing : after the last one, some room may remain
787 * before STKTABLE_DATA_TYPES that may be used to register extra data types
788 * at run time.
789 */
790 struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
791 [STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
792 [STKTABLE_DT_GPT0] = { .name = "gpt0", .std_type = STD_T_UINT },
793 [STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
794 [STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
795 [STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
796 [STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
797 [STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
798 [STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
799 [STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
800 [STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
801 [STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
802 [STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
803 [STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
804 [STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
805 [STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
806 [STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
807 [STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
808 };
809
810 /* 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 */
stktable_register_data_store(int idx,const char * name,int std_type,int arg_type)816 int 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
840 /*
841 * Returns the data type number for the stktable_data_type whose name is <name>,
842 * or <0 if not found.
843 */
stktable_get_data_type(char * name)844 int stktable_get_data_type(char *name)
845 {
846 int type;
847
848 for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
849 if (!stktable_data_types[type].name)
850 continue;
851 if (strcmp(name, stktable_data_types[type].name) == 0)
852 return type;
853 }
854 return -1;
855 }
856
857 /* 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 */
sample_conv_in_table(const struct arg * arg_p,struct sample * smp,void * private)864 static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, void *private)
865 {
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
878 smp->data.type = SMP_T_BOOL;
879 smp->data.u.sint = !!ts;
880 smp->flags = SMP_F_VOL_TEST;
881 stktable_release(t, ts);
882 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 */
sample_conv_table_bytes_in_rate(const struct arg * arg_p,struct sample * smp,void * private)891 static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sample *smp, void *private)
892 {
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
904 ts = stktable_lookup_key(t, key);
905
906 smp->flags = SMP_F_VOL_TEST;
907 smp->data.type = SMP_T_SINT;
908 smp->data.u.sint = 0;
909
910 if (!ts) /* key not present */
911 return 1;
912
913 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
914 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);
917
918 stktable_release(t, ts);
919 return !!ptr;
920 }
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 */
sample_conv_table_conn_cnt(const struct arg * arg_p,struct sample * smp,void * private)928 static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *smp, void *private)
929 {
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
941 ts = stktable_lookup_key(t, key);
942
943 smp->flags = SMP_F_VOL_TEST;
944 smp->data.type = SMP_T_SINT;
945 smp->data.u.sint = 0;
946
947 if (!ts) /* key not present */
948 return 1;
949
950 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
951 if (ptr)
952 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
953
954 stktable_release(t, ts);
955 return !!ptr;
956 }
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 */
sample_conv_table_conn_cur(const struct arg * arg_p,struct sample * smp,void * private)964 static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *smp, void *private)
965 {
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
977 ts = stktable_lookup_key(t, key);
978
979 smp->flags = SMP_F_VOL_TEST;
980 smp->data.type = SMP_T_SINT;
981 smp->data.u.sint = 0;
982
983 if (!ts) /* key not present */
984 return 1;
985
986 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CUR);
987 if (ptr)
988 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
989
990 stktable_release(t, ts);
991 return !!ptr;
992 }
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 */
sample_conv_table_conn_rate(const struct arg * arg_p,struct sample * smp,void * private)1000 static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *smp, void *private)
1001 {
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
1013 ts = stktable_lookup_key(t, key);
1014
1015 smp->flags = SMP_F_VOL_TEST;
1016 smp->data.type = SMP_T_SINT;
1017 smp->data.u.sint = 0;
1018
1019 if (!ts) /* key not present */
1020 return 1;
1021
1022 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_RATE);
1023 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);
1026
1027 stktable_release(t, ts);
1028 return !!ptr;
1029 }
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 */
sample_conv_table_bytes_out_rate(const struct arg * arg_p,struct sample * smp,void * private)1037 static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct sample *smp, void *private)
1038 {
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
1050 ts = stktable_lookup_key(t, key);
1051
1052 smp->flags = SMP_F_VOL_TEST;
1053 smp->data.type = SMP_T_SINT;
1054 smp->data.u.sint = 0;
1055
1056 if (!ts) /* key not present */
1057 return 1;
1058
1059 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
1060 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);
1063
1064 stktable_release(t, ts);
1065 return !!ptr;
1066 }
1067
1068 /* Casts sample <smp> to the type of the table specified in arg(0), and looks
1069 * 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 */
sample_conv_table_gpt0(const struct arg * arg_p,struct sample * smp,void * private)1074 static 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
1087 ts = stktable_lookup_key(t, key);
1088
1089 smp->flags = SMP_F_VOL_TEST;
1090 smp->data.type = SMP_T_SINT;
1091 smp->data.u.sint = 0;
1092
1093 if (!ts) /* key not present */
1094 return 1;
1095
1096 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPT0);
1097 if (ptr)
1098 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
1099
1100 stktable_release(t, ts);
1101 return !!ptr;
1102 }
1103
1104 /* Casts sample <smp> to the type of the table specified in arg(0), and looks
1105 * 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 */
sample_conv_table_gpc0(const struct arg * arg_p,struct sample * smp,void * private)1110 static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, void *private)
1111 {
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
1123 ts = stktable_lookup_key(t, key);
1124
1125 smp->flags = SMP_F_VOL_TEST;
1126 smp->data.type = SMP_T_SINT;
1127 smp->data.u.sint = 0;
1128
1129 if (!ts) /* key not present */
1130 return 1;
1131
1132 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0);
1133 if (ptr)
1134 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
1135
1136 stktable_release(t, ts);
1137 return !!ptr;
1138 }
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 */
sample_conv_table_gpc0_rate(const struct arg * arg_p,struct sample * smp,void * private)1146 static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *smp, void *private)
1147 {
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
1159 ts = stktable_lookup_key(t, key);
1160
1161 smp->flags = SMP_F_VOL_TEST;
1162 smp->data.type = SMP_T_SINT;
1163 smp->data.u.sint = 0;
1164
1165 if (!ts) /* key not present */
1166 return 1;
1167
1168 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GPC0_RATE);
1169 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);
1172
1173 stktable_release(t, ts);
1174 return !!ptr;
1175 }
1176
1177 /* Casts sample <smp> to the type of the table specified in arg(0), and looks
1178 * it up into this table. Returns the cumulated number of HTTP request errors
1179 * for the key if the key is present in the table, otherwise zero, so that
1180 * comparisons can be easily performed. If the inspected parameter is not stored
1181 * in the table, <not found> is returned.
1182 */
sample_conv_table_http_err_cnt(const struct arg * arg_p,struct sample * smp,void * private)1183 static int sample_conv_table_http_err_cnt(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_HTTP_ERR_CNT);
1206 if (ptr)
1207 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
1208
1209 stktable_release(t, ts);
1210 return !!ptr;
1211 }
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 HTTP request error rate 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 */
sample_conv_table_http_err_rate(const struct arg * arg_p,struct sample * smp,void * private)1219 static int sample_conv_table_http_err_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_HTTP_ERR_RATE);
1242 if (ptr)
1243 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
1244 t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
1245
1246 stktable_release(t, ts);
1247 return !!ptr;
1248 }
1249
1250 /* Casts sample <smp> to the type of the table specified in arg(0), and looks
1251 * it up into this table. Returns the cumulated number of HTTP request for the
1252 * key if the key is present in the table, otherwise zero, so that comparisons
1253 * can be easily performed. If the inspected parameter is not stored in the
1254 * table, <not found> is returned.
1255 */
sample_conv_table_http_req_cnt(const struct arg * arg_p,struct sample * smp,void * private)1256 static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1257 {
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
1269 ts = stktable_lookup_key(t, key);
1270
1271 smp->flags = SMP_F_VOL_TEST;
1272 smp->data.type = SMP_T_SINT;
1273 smp->data.u.sint = 0;
1274
1275 if (!ts) /* key not present */
1276 return 1;
1277
1278 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
1279 if (ptr)
1280 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
1281
1282 stktable_release(t, ts);
1283 return !!ptr;
1284 }
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 rate the key if the key is
1288 * present in the table, otherwise zero, so that comparisons can be easily
1289 * performed. If the inspected parameter is not stored in the table, <not found>
1290 * is returned.
1291 */
sample_conv_table_http_req_rate(const struct arg * arg_p,struct sample * smp,void * private)1292 static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sample *smp, void *private)
1293 {
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
1305 ts = stktable_lookup_key(t, key);
1306
1307 smp->flags = SMP_F_VOL_TEST;
1308 smp->data.type = SMP_T_SINT;
1309 smp->data.u.sint = 0;
1310
1311 if (!ts) /* key not present */
1312 return 1;
1313
1314 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
1315 if (ptr)
1316 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
1317 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
1318
1319 stktable_release(t, ts);
1320 return !!ptr;
1321 }
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 volume of datareceived from clients in kbytes
1325 * if the key is present in the table, otherwise zero, so that comparisons can
1326 * be easily performed. If the inspected parameter is not stored in the table,
1327 * <not found> is returned.
1328 */
sample_conv_table_kbytes_in(const struct arg * arg_p,struct sample * smp,void * private)1329 static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *smp, void *private)
1330 {
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
1342 ts = stktable_lookup_key(t, key);
1343
1344 smp->flags = SMP_F_VOL_TEST;
1345 smp->data.type = SMP_T_SINT;
1346 smp->data.u.sint = 0;
1347
1348 if (!ts) /* key not present */
1349 return 1;
1350
1351 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_CNT);
1352 if (ptr)
1353 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
1354
1355 stktable_release(t, ts);
1356 return !!ptr;
1357 }
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 volume of data sent to clients in kbytes
1361 * if the key is present in the table, otherwise zero, so that comparisons can
1362 * be easily performed. If the inspected parameter is not stored in the table,
1363 * <not found> is returned.
1364 */
sample_conv_table_kbytes_out(const struct arg * arg_p,struct sample * smp,void * private)1365 static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *smp, void *private)
1366 {
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
1378 ts = stktable_lookup_key(t, key);
1379
1380 smp->flags = SMP_F_VOL_TEST;
1381 smp->data.type = SMP_T_SINT;
1382 smp->data.u.sint = 0;
1383
1384 if (!ts) /* key not present */
1385 return 1;
1386
1387 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_CNT);
1388 if (ptr)
1389 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
1390
1391 stktable_release(t, ts);
1392 return !!ptr;
1393 }
1394
1395 /* Casts sample <smp> to the type of the table specified in arg(0), and looks
1396 * it up into this table. Returns the server ID associated with the key if the
1397 * key is present in the table, otherwise zero, so that comparisons can be
1398 * easily performed. If the inspected parameter is not stored in the table,
1399 * <not found> is returned.
1400 */
sample_conv_table_server_id(const struct arg * arg_p,struct sample * smp,void * private)1401 static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *smp, void *private)
1402 {
1403 struct stktable *t;
1404 struct stktable_key *key;
1405 struct stksess *ts;
1406 void *ptr;
1407
1408 t = &arg_p[0].data.prx->table;
1409
1410 key = smp_to_stkey(smp, t);
1411 if (!key)
1412 return 0;
1413
1414 ts = stktable_lookup_key(t, key);
1415
1416 smp->flags = SMP_F_VOL_TEST;
1417 smp->data.type = SMP_T_SINT;
1418 smp->data.u.sint = 0;
1419
1420 if (!ts) /* key not present */
1421 return 1;
1422
1423 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
1424 if (ptr)
1425 smp->data.u.sint = stktable_data_cast(ptr, server_id);
1426
1427 stktable_release(t, ts);
1428 return !!ptr;
1429 }
1430
1431 /* Casts sample <smp> to the type of the table specified in arg(0), and looks
1432 * it up into this table. Returns the cumulated number of sessions for the
1433 * key if the key is present in the table, otherwise zero, so that comparisons
1434 * can be easily performed. If the inspected parameter is not stored in the
1435 * table, <not found> is returned.
1436 */
sample_conv_table_sess_cnt(const struct arg * arg_p,struct sample * smp,void * private)1437 static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *smp, void *private)
1438 {
1439 struct stktable *t;
1440 struct stktable_key *key;
1441 struct stksess *ts;
1442 void *ptr;
1443
1444 t = &arg_p[0].data.prx->table;
1445
1446 key = smp_to_stkey(smp, t);
1447 if (!key)
1448 return 0;
1449
1450 ts = stktable_lookup_key(t, key);
1451
1452 smp->flags = SMP_F_VOL_TEST;
1453 smp->data.type = SMP_T_SINT;
1454 smp->data.u.sint = 0;
1455
1456 if (!ts) /* key not present */
1457 return 1;
1458
1459 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_CNT);
1460 if (ptr)
1461 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
1462
1463 stktable_release(t, ts);
1464 return !!ptr;
1465 }
1466
1467 /* Casts sample <smp> to the type of the table specified in arg(0), and looks
1468 * it up into this table. Returns the session rate the key if the key is
1469 * present in the table, otherwise zero, so that comparisons can be easily
1470 * performed. If the inspected parameter is not stored in the table, <not found>
1471 * is returned.
1472 */
sample_conv_table_sess_rate(const struct arg * arg_p,struct sample * smp,void * private)1473 static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *smp, void *private)
1474 {
1475 struct stktable *t;
1476 struct stktable_key *key;
1477 struct stksess *ts;
1478 void *ptr;
1479
1480 t = &arg_p[0].data.prx->table;
1481
1482 key = smp_to_stkey(smp, t);
1483 if (!key)
1484 return 0;
1485
1486 ts = stktable_lookup_key(t, key);
1487
1488 smp->flags = SMP_F_VOL_TEST;
1489 smp->data.type = SMP_T_SINT;
1490 smp->data.u.sint = 0;
1491
1492 if (!ts) /* key not present */
1493 return 1;
1494
1495 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_SESS_RATE);
1496 if (ptr)
1497 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
1498 t->data_arg[STKTABLE_DT_SESS_RATE].u);
1499
1500 stktable_release(t, ts);
1501 return !!ptr;
1502 }
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 amount of concurrent connections tracking
1506 * the same key if the key is present in the table, otherwise zero, so that
1507 * comparisons can be easily performed. If the inspected parameter is not
1508 * stored in the table, <not found> is returned.
1509 */
sample_conv_table_trackers(const struct arg * arg_p,struct sample * smp,void * private)1510 static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *smp, void *private)
1511 {
1512 struct stktable *t;
1513 struct stktable_key *key;
1514 struct stksess *ts;
1515
1516 t = &arg_p[0].data.prx->table;
1517
1518 key = smp_to_stkey(smp, t);
1519 if (!key)
1520 return 0;
1521
1522 ts = stktable_lookup_key(t, key);
1523
1524 smp->flags = SMP_F_VOL_TEST;
1525 smp->data.type = SMP_T_SINT;
1526 smp->data.u.sint = 0;
1527
1528 if (!ts)
1529 return 1;
1530
1531 smp->data.u.sint = ts->ref_cnt;
1532
1533 stktable_release(t, ts);
1534 return 1;
1535 }
1536
1537 /* Always returns 1. */
action_inc_gpc0(struct act_rule * rule,struct proxy * px,struct session * sess,struct stream * s,int flags)1538 static enum act_return action_inc_gpc0(struct act_rule *rule, struct proxy *px,
1539 struct session *sess, struct stream *s, int flags)
1540 {
1541 struct stksess *ts;
1542 struct stkctr *stkctr;
1543
1544 /* Extract the stksess, return OK if no stksess available. */
1545 if (s)
1546 stkctr = &s->stkctr[rule->arg.gpc.sc];
1547 else
1548 stkctr = &sess->stkctr[rule->arg.gpc.sc];
1549
1550 ts = stkctr_entry(stkctr);
1551 if (ts) {
1552 void *ptr1, *ptr2;
1553
1554 /* First, update gpc0_rate if it's tracked. Second, update its gpc0 if tracked. */
1555 ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0_RATE);
1556 ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPC0);
1557 if (ptr1 || ptr2) {
1558 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1559
1560 if (ptr1)
1561 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
1562 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
1563
1564 if (ptr2)
1565 stktable_data_cast(ptr2, gpc0)++;
1566
1567 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1568
1569 /* If data was modified, we need to touch to re-schedule sync */
1570 stktable_touch_local(stkctr->table, ts, 0);
1571 }
1572 }
1573 return ACT_RET_CONT;
1574 }
1575
1576 /* This function is a common parser for using variables. It understands
1577 * the formats:
1578 *
1579 * sc-inc-gpc0(<stick-table ID>)
1580 *
1581 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1582 * it returns 1 and the variable <expr> is filled with the pointer to the
1583 * expression to execute.
1584 */
parse_inc_gpc0(const char ** args,int * arg,struct proxy * px,struct act_rule * rule,char ** err)1585 static enum act_parse_ret parse_inc_gpc0(const char **args, int *arg, struct proxy *px,
1586 struct act_rule *rule, char **err)
1587 {
1588 const char *cmd_name = args[*arg-1];
1589 char *error;
1590
1591 cmd_name += strlen("sc-inc-gpc0");
1592 if (*cmd_name == '\0') {
1593 /* default stick table id. */
1594 rule->arg.gpc.sc = 0;
1595 } else {
1596 /* parse the stick table id. */
1597 if (*cmd_name != '(') {
1598 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1599 return ACT_RET_PRS_ERR;
1600 }
1601 cmd_name++; /* jump the '(' */
1602 rule->arg.gpc.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1603 if (*error != ')') {
1604 memprintf(err, "invalid stick table track ID. Expects %s(<Track ID>)", args[*arg-1]);
1605 return ACT_RET_PRS_ERR;
1606 }
1607
1608 if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
1609 memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
1610 MAX_SESS_STKCTR-1);
1611 return ACT_RET_PRS_ERR;
1612 }
1613 }
1614 rule->action = ACT_CUSTOM;
1615 rule->action_ptr = action_inc_gpc0;
1616 return ACT_RET_PRS_OK;
1617 }
1618
1619 /* Always returns 1. */
action_set_gpt0(struct act_rule * rule,struct proxy * px,struct session * sess,struct stream * s,int flags)1620 static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
1621 struct session *sess, struct stream *s, int flags)
1622 {
1623 void *ptr;
1624 struct stksess *ts;
1625 struct stkctr *stkctr;
1626
1627 /* Extract the stksess, return OK if no stksess available. */
1628 if (s)
1629 stkctr = &s->stkctr[rule->arg.gpt.sc];
1630 else
1631 stkctr = &sess->stkctr[rule->arg.gpt.sc];
1632
1633 ts = stkctr_entry(stkctr);
1634 if (!ts)
1635 return ACT_RET_CONT;
1636
1637 /* Store the sample in the required sc, and ignore errors. */
1638 ptr = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GPT0);
1639 if (ptr) {
1640 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
1641
1642 stktable_data_cast(ptr, gpt0) = rule->arg.gpt.value;
1643
1644 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
1645
1646 stktable_touch_local(stkctr->table, ts, 0);
1647 }
1648
1649 return ACT_RET_CONT;
1650 }
1651
1652 /* This function is a common parser for using variables. It understands
1653 * the format:
1654 *
1655 * set-gpt0(<stick-table ID>) <expression>
1656 *
1657 * It returns 0 if fails and <err> is filled with an error message. Otherwise,
1658 * it returns 1 and the variable <expr> is filled with the pointer to the
1659 * expression to execute.
1660 */
parse_set_gpt0(const char ** args,int * arg,struct proxy * px,struct act_rule * rule,char ** err)1661 static enum act_parse_ret parse_set_gpt0(const char **args, int *arg, struct proxy *px,
1662 struct act_rule *rule, char **err)
1663
1664
1665 {
1666 const char *cmd_name = args[*arg-1];
1667 char *error;
1668
1669 cmd_name += strlen("sc-set-gpt0");
1670 if (*cmd_name == '\0') {
1671 /* default stick table id. */
1672 rule->arg.gpt.sc = 0;
1673 } else {
1674 /* parse the stick table id. */
1675 if (*cmd_name != '(') {
1676 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1677 return ACT_RET_PRS_ERR;
1678 }
1679 cmd_name++; /* jump the '(' */
1680 rule->arg.gpt.sc = strtol(cmd_name, &error, 10); /* Convert stick table id. */
1681 if (*error != ')') {
1682 memprintf(err, "invalid stick table track ID '%s'. Expects sc-set-gpt0(<Track ID>)", args[*arg-1]);
1683 return ACT_RET_PRS_ERR;
1684 }
1685
1686 if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
1687 memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
1688 args[*arg-1], MAX_SESS_STKCTR-1);
1689 return ACT_RET_PRS_ERR;
1690 }
1691 }
1692
1693 rule->arg.gpt.value = strtol(args[*arg], &error, 10);
1694 if (*error != '\0') {
1695 memprintf(err, "invalid integer value '%s'", args[*arg]);
1696 return ACT_RET_PRS_ERR;
1697 }
1698 (*arg)++;
1699
1700 rule->action = ACT_CUSTOM;
1701 rule->action_ptr = action_set_gpt0;
1702
1703 return ACT_RET_PRS_OK;
1704 }
1705
1706 /* set temp integer to the number of used entries in the table pointed to by expr.
1707 * Accepts exactly 1 argument of type table.
1708 */
1709 static int
smp_fetch_table_cnt(const struct arg * args,struct sample * smp,const char * kw,void * private)1710 smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1711 {
1712 smp->flags = SMP_F_VOL_TEST;
1713 smp->data.type = SMP_T_SINT;
1714 smp->data.u.sint = args->data.prx->table.current;
1715 return 1;
1716 }
1717
1718 /* set temp integer to the number of free entries in the table pointed to by expr.
1719 * Accepts exactly 1 argument of type table.
1720 */
1721 static int
smp_fetch_table_avl(const struct arg * args,struct sample * smp,const char * kw,void * private)1722 smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
1723 {
1724 struct proxy *px;
1725
1726 px = args->data.prx;
1727 smp->flags = SMP_F_VOL_TEST;
1728 smp->data.type = SMP_T_SINT;
1729 smp->data.u.sint = px->table.size - px->table.current;
1730 return 1;
1731 }
1732
1733 /* Returns a pointer to a stkctr depending on the fetch keyword name.
1734 * It is designed to be called as sc[0-9]_* sc_* or src_* exclusively.
1735 * sc[0-9]_* will return a pointer to the respective field in the
1736 * stream <l4>. sc_* requires an UINT argument specifying the stick
1737 * counter number. src_* will fill a locally allocated structure with
1738 * the table and entry corresponding to what is specified with src_*.
1739 * NULL may be returned if the designated stkctr is not tracked. For
1740 * the sc_* and sc[0-9]_* forms, an optional table argument may be
1741 * passed. When present, the currently tracked key is then looked up
1742 * in the specified table instead of the current table. The purpose is
1743 * to be able to convery multiple values per key (eg: have gpc0 from
1744 * multiple tables). <strm> is allowed to be NULL, in which case only
1745 * the session will be consulted.
1746 */
1747 struct stkctr *
smp_fetch_sc_stkctr(struct session * sess,struct stream * strm,const struct arg * args,const char * kw,struct stkctr * stkctr)1748 smp_fetch_sc_stkctr(struct session *sess, struct stream *strm, const struct arg *args, const char *kw, struct stkctr *stkctr)
1749 {
1750 struct stkctr *stkptr;
1751 struct stksess *stksess;
1752 unsigned int num = kw[2] - '0';
1753 int arg = 0;
1754
1755 if (num == '_' - '0') {
1756 /* sc_* variant, args[0] = ctr# (mandatory) */
1757 num = args[arg++].data.sint;
1758 }
1759 else if (num > 9) { /* src_* variant, args[0] = table */
1760 struct stktable_key *key;
1761 struct connection *conn = objt_conn(sess->origin);
1762 struct sample smp;
1763
1764 if (!conn)
1765 return NULL;
1766
1767 /* Fetch source adress in a sample. */
1768 smp.px = NULL;
1769 smp.sess = sess;
1770 smp.strm = strm;
1771 if (!smp_fetch_src(empty_arg_list, &smp, NULL, NULL))
1772 return NULL;
1773
1774 /* Converts into key. */
1775 key = smp_to_stkey(&smp, &args->data.prx->table);
1776 if (!key)
1777 return NULL;
1778
1779 stkctr->table = &args->data.prx->table;
1780 stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
1781 return stkctr;
1782 }
1783
1784 /* Here, <num> contains the counter number from 0 to 9 for
1785 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
1786 * args[arg] is the first optional argument. We first lookup the
1787 * ctr form the stream, then from the session if it was not there.
1788 * But we must be sure the counter does not exceed MAX_SESS_STKCTR.
1789 */
1790 if (num >= MAX_SESS_STKCTR)
1791 return NULL;
1792
1793 if (strm)
1794 stkptr = &strm->stkctr[num];
1795 if (!strm || !stkctr_entry(stkptr)) {
1796 stkptr = &sess->stkctr[num];
1797 if (!stkctr_entry(stkptr))
1798 return NULL;
1799 }
1800
1801 stksess = stkctr_entry(stkptr);
1802 if (!stksess)
1803 return NULL;
1804
1805 if (unlikely(args[arg].type == ARGT_TAB)) {
1806 /* an alternate table was specified, let's look up the same key there */
1807 stkctr->table = &args[arg].data.prx->table;
1808 stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
1809 return stkctr;
1810 }
1811 return stkptr;
1812 }
1813
1814 /* same as smp_fetch_sc_stkctr() but dedicated to src_* and can create
1815 * the entry if it doesn't exist yet. This is needed for a few fetch
1816 * functions which need to create an entry, such as src_inc_gpc* and
1817 * src_clr_gpc*.
1818 */
1819 struct stkctr *
smp_create_src_stkctr(struct session * sess,struct stream * strm,const struct arg * args,const char * kw,struct stkctr * stkctr)1820 smp_create_src_stkctr(struct session *sess, struct stream *strm, const struct arg *args, const char *kw, struct stkctr *stkctr)
1821 {
1822 struct stktable_key *key;
1823 struct connection *conn = objt_conn(sess->origin);
1824 struct sample smp;
1825
1826 if (strncmp(kw, "src_", 4) != 0)
1827 return NULL;
1828
1829 if (!conn)
1830 return NULL;
1831
1832 /* Fetch source adress in a sample. */
1833 smp.px = NULL;
1834 smp.sess = sess;
1835 smp.strm = strm;
1836 if (!smp_fetch_src(empty_arg_list, &smp, NULL, NULL))
1837 return NULL;
1838
1839 /* Converts into key. */
1840 key = smp_to_stkey(&smp, &args->data.prx->table);
1841 if (!key)
1842 return NULL;
1843
1844 stkctr->table = &args->data.prx->table;
1845 stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
1846 return stkctr;
1847 }
1848
1849 /* set return a boolean indicating if the requested stream counter is
1850 * currently being tracked or not.
1851 * Supports being called as "sc[0-9]_tracked" only.
1852 */
1853 static int
smp_fetch_sc_tracked(const struct arg * args,struct sample * smp,const char * kw,void * private)1854 smp_fetch_sc_tracked(const struct arg *args, struct sample *smp, const char *kw, void *private)
1855 {
1856 struct stkctr tmpstkctr;
1857 struct stkctr *stkctr;
1858
1859 smp->flags = SMP_F_VOL_TEST;
1860 smp->data.type = SMP_T_BOOL;
1861 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
1862 smp->data.u.sint = !!stkctr;
1863
1864 /* release the ref count */
1865 if (stkctr == &tmpstkctr)
1866 stktable_release(stkctr->table, stkctr_entry(stkctr));
1867
1868 return 1;
1869 }
1870
1871 /* set <smp> to the General Purpose Flag 0 value from the stream's tracked
1872 * frontend counters or from the src.
1873 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpt0" only. Value
1874 * zero is returned if the key is new.
1875 */
1876 static int
smp_fetch_sc_get_gpt0(const struct arg * args,struct sample * smp,const char * kw,void * private)1877 smp_fetch_sc_get_gpt0(const struct arg *args, struct sample *smp, const char *kw, void *private)
1878 {
1879 struct stkctr tmpstkctr;
1880 struct stkctr *stkctr;
1881
1882 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
1883 if (!stkctr)
1884 return 0;
1885
1886 smp->flags = SMP_F_VOL_TEST;
1887 smp->data.type = SMP_T_SINT;
1888 smp->data.u.sint = 0;
1889
1890 if (stkctr_entry(stkctr)) {
1891 void *ptr;
1892
1893 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPT0);
1894 if (!ptr) {
1895 if (stkctr == &tmpstkctr)
1896 stktable_release(stkctr->table, stkctr_entry(stkctr));
1897 return 0; /* parameter not stored */
1898 }
1899
1900 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1901
1902 smp->data.u.sint = stktable_data_cast(ptr, gpt0);
1903
1904 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1905
1906 if (stkctr == &tmpstkctr)
1907 stktable_release(stkctr->table, stkctr_entry(stkctr));
1908 }
1909 return 1;
1910 }
1911
1912 /* set <smp> to the General Purpose Counter 0 value from the stream's tracked
1913 * frontend counters or from the src.
1914 * Supports being called as "sc[0-9]_get_gpc0" or "src_get_gpc0" only. Value
1915 * zero is returned if the key is new.
1916 */
1917 static int
smp_fetch_sc_get_gpc0(const struct arg * args,struct sample * smp,const char * kw,void * private)1918 smp_fetch_sc_get_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
1919 {
1920 struct stkctr tmpstkctr;
1921 struct stkctr *stkctr;
1922
1923 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
1924 if (!stkctr)
1925 return 0;
1926
1927 smp->flags = SMP_F_VOL_TEST;
1928 smp->data.type = SMP_T_SINT;
1929 smp->data.u.sint = 0;
1930
1931 if (stkctr_entry(stkctr) != NULL) {
1932 void *ptr;
1933
1934 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
1935 if (!ptr) {
1936 if (stkctr == &tmpstkctr)
1937 stktable_release(stkctr->table, stkctr_entry(stkctr));
1938 return 0; /* parameter not stored */
1939 }
1940
1941 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1942
1943 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
1944
1945 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1946
1947 if (stkctr == &tmpstkctr)
1948 stktable_release(stkctr->table, stkctr_entry(stkctr));
1949 }
1950 return 1;
1951 }
1952
1953 /* set <smp> to the General Purpose Counter 0's event rate from the stream's
1954 * tracked frontend counters or from the src.
1955 * Supports being called as "sc[0-9]_gpc0_rate" or "src_gpc0_rate" only.
1956 * Value zero is returned if the key is new.
1957 */
1958 static int
smp_fetch_sc_gpc0_rate(const struct arg * args,struct sample * smp,const char * kw,void * private)1959 smp_fetch_sc_gpc0_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
1960 {
1961 struct stkctr tmpstkctr;
1962 struct stkctr *stkctr;
1963
1964 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
1965 if (!stkctr)
1966 return 0;
1967
1968 smp->flags = SMP_F_VOL_TEST;
1969 smp->data.type = SMP_T_SINT;
1970 smp->data.u.sint = 0;
1971 if (stkctr_entry(stkctr) != NULL) {
1972 void *ptr;
1973
1974 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
1975 if (!ptr) {
1976 if (stkctr == &tmpstkctr)
1977 stktable_release(stkctr->table, stkctr_entry(stkctr));
1978 return 0; /* parameter not stored */
1979 }
1980
1981 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1982
1983 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, gpc0_rate),
1984 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u);
1985
1986 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
1987
1988 if (stkctr == &tmpstkctr)
1989 stktable_release(stkctr->table, stkctr_entry(stkctr));
1990 }
1991 return 1;
1992 }
1993
1994 /* Increment the General Purpose Counter 0 value from the stream's tracked
1995 * frontend counters and return it into temp integer.
1996 * Supports being called as "sc[0-9]_inc_gpc0" or "src_inc_gpc0" only.
1997 */
1998 static int
smp_fetch_sc_inc_gpc0(const struct arg * args,struct sample * smp,const char * kw,void * private)1999 smp_fetch_sc_inc_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2000 {
2001 struct stkctr tmpstkctr;
2002 struct stkctr *stkctr;
2003
2004 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2005 if (!stkctr)
2006 return 0;
2007
2008 smp->flags = SMP_F_VOL_TEST;
2009 smp->data.type = SMP_T_SINT;
2010 smp->data.u.sint = 0;
2011
2012 if (!stkctr_entry(stkctr))
2013 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2014
2015 if (stkctr && stkctr_entry(stkctr)) {
2016 void *ptr1,*ptr2;
2017
2018
2019 /* First, update gpc0_rate if it's tracked. Second, update its
2020 * gpc0 if tracked. Returns gpc0's value otherwise the curr_ctr.
2021 */
2022 ptr1 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0_RATE);
2023 ptr2 = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2024 if (ptr1 || ptr2) {
2025 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2026
2027 if (ptr1) {
2028 update_freq_ctr_period(&stktable_data_cast(ptr1, gpc0_rate),
2029 stkctr->table->data_arg[STKTABLE_DT_GPC0_RATE].u, 1);
2030 smp->data.u.sint = (&stktable_data_cast(ptr1, gpc0_rate))->curr_ctr;
2031 }
2032
2033 if (ptr2)
2034 smp->data.u.sint = ++stktable_data_cast(ptr2, gpc0);
2035
2036 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2037
2038 /* If data was modified, we need to touch to re-schedule sync */
2039 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2040 }
2041 else if (stkctr == &tmpstkctr)
2042 stktable_release(stkctr->table, stkctr_entry(stkctr));
2043 }
2044 return 1;
2045 }
2046
2047 /* Clear the General Purpose Counter 0 value from the stream's tracked
2048 * frontend counters and return its previous value into temp integer.
2049 * Supports being called as "sc[0-9]_clr_gpc0" or "src_clr_gpc0" only.
2050 */
2051 static int
smp_fetch_sc_clr_gpc0(const struct arg * args,struct sample * smp,const char * kw,void * private)2052 smp_fetch_sc_clr_gpc0(const struct arg *args, struct sample *smp, const char *kw, void *private)
2053 {
2054 struct stkctr tmpstkctr;
2055 struct stkctr *stkctr;
2056
2057 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2058 if (!stkctr)
2059 return 0;
2060
2061 smp->flags = SMP_F_VOL_TEST;
2062 smp->data.type = SMP_T_SINT;
2063 smp->data.u.sint = 0;
2064
2065 if (!stkctr_entry(stkctr))
2066 stkctr = smp_create_src_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2067
2068 if (stkctr && stkctr_entry(stkctr)) {
2069 void *ptr;
2070
2071 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GPC0);
2072 if (!ptr) {
2073 if (stkctr == &tmpstkctr)
2074 stktable_release(stkctr->table, stkctr_entry(stkctr));
2075 return 0; /* parameter not stored */
2076 }
2077
2078 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2079
2080 smp->data.u.sint = stktable_data_cast(ptr, gpc0);
2081 stktable_data_cast(ptr, gpc0) = 0;
2082
2083 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2084
2085 /* If data was modified, we need to touch to re-schedule sync */
2086 stktable_touch_local(stkctr->table, stkctr_entry(stkctr), (stkctr == &tmpstkctr) ? 1 : 0);
2087 }
2088 return 1;
2089 }
2090
2091 /* set <smp> to the cumulated number of connections from the stream's tracked
2092 * frontend counters. Supports being called as "sc[0-9]_conn_cnt" or
2093 * "src_conn_cnt" only.
2094 */
2095 static int
smp_fetch_sc_conn_cnt(const struct arg * args,struct sample * smp,const char * kw,void * private)2096 smp_fetch_sc_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2097 {
2098 struct stkctr tmpstkctr;
2099 struct stkctr *stkctr;
2100
2101 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2102 if (!stkctr)
2103 return 0;
2104
2105 smp->flags = SMP_F_VOL_TEST;
2106 smp->data.type = SMP_T_SINT;
2107 smp->data.u.sint = 0;
2108 if (stkctr_entry(stkctr) != NULL) {
2109 void *ptr;
2110
2111 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CNT);
2112 if (!ptr) {
2113 if (stkctr == &tmpstkctr)
2114 stktable_release(stkctr->table, stkctr_entry(stkctr));
2115 return 0; /* parameter not stored */
2116 }
2117
2118 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2119
2120 smp->data.u.sint = stktable_data_cast(ptr, conn_cnt);
2121
2122 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2123
2124 if (stkctr == &tmpstkctr)
2125 stktable_release(stkctr->table, stkctr_entry(stkctr));
2126
2127
2128 }
2129 return 1;
2130 }
2131
2132 /* set <smp> to the connection rate from the stream's tracked frontend
2133 * counters. Supports being called as "sc[0-9]_conn_rate" or "src_conn_rate"
2134 * only.
2135 */
2136 static int
smp_fetch_sc_conn_rate(const struct arg * args,struct sample * smp,const char * kw,void * private)2137 smp_fetch_sc_conn_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2138 {
2139 struct stkctr tmpstkctr;
2140 struct stkctr *stkctr;
2141
2142 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2143 if (!stkctr)
2144 return 0;
2145
2146 smp->flags = SMP_F_VOL_TEST;
2147 smp->data.type = SMP_T_SINT;
2148 smp->data.u.sint = 0;
2149 if (stkctr_entry(stkctr) != NULL) {
2150 void *ptr;
2151
2152 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_RATE);
2153 if (!ptr) {
2154 if (stkctr == &tmpstkctr)
2155 stktable_release(stkctr->table, stkctr_entry(stkctr));
2156 return 0; /* parameter not stored */
2157 }
2158
2159 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2160
2161 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, conn_rate),
2162 stkctr->table->data_arg[STKTABLE_DT_CONN_RATE].u);
2163
2164 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2165
2166 if (stkctr == &tmpstkctr)
2167 stktable_release(stkctr->table, stkctr_entry(stkctr));
2168 }
2169 return 1;
2170 }
2171
2172 /* set temp integer to the number of connections from the stream's source address
2173 * in the table pointed to by expr, after updating it.
2174 * Accepts exactly 1 argument of type table.
2175 */
2176 static int
smp_fetch_src_updt_conn_cnt(const struct arg * args,struct sample * smp,const char * kw,void * private)2177 smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2178 {
2179 struct connection *conn = objt_conn(smp->sess->origin);
2180 struct stksess *ts;
2181 struct stktable_key *key;
2182 void *ptr;
2183 struct proxy *px;
2184
2185 if (!conn)
2186 return 0;
2187
2188 /* Fetch source adress in a sample. */
2189 if (!smp_fetch_src(empty_arg_list, smp, NULL, NULL))
2190 return 0;
2191
2192 /* Converts into key. */
2193 key = smp_to_stkey(smp, &args->data.prx->table);
2194 if (!key)
2195 return 0;
2196
2197 px = args->data.prx;
2198
2199 if ((ts = stktable_get_entry(&px->table, key)) == NULL)
2200 /* entry does not exist and could not be created */
2201 return 0;
2202
2203 ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
2204 if (!ptr) {
2205 return 0; /* parameter not stored in this table */
2206 }
2207
2208 smp->data.type = SMP_T_SINT;
2209
2210 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2211
2212 smp->data.u.sint = ++stktable_data_cast(ptr, conn_cnt);
2213
2214 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2215
2216 smp->flags = SMP_F_VOL_TEST;
2217
2218 stktable_touch_local(&px->table, ts, 1);
2219
2220 /* Touch was previously performed by stktable_update_key */
2221 return 1;
2222 }
2223
2224 /* set <smp> to the number of concurrent connections from the stream's tracked
2225 * frontend counters. Supports being called as "sc[0-9]_conn_cur" or
2226 * "src_conn_cur" only.
2227 */
2228 static int
smp_fetch_sc_conn_cur(const struct arg * args,struct sample * smp,const char * kw,void * private)2229 smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw, void *private)
2230 {
2231 struct stkctr tmpstkctr;
2232 struct stkctr *stkctr;
2233
2234 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2235 if (!stkctr)
2236 return 0;
2237
2238 smp->flags = SMP_F_VOL_TEST;
2239 smp->data.type = SMP_T_SINT;
2240 smp->data.u.sint = 0;
2241 if (stkctr_entry(stkctr) != NULL) {
2242 void *ptr;
2243
2244 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_CONN_CUR);
2245 if (!ptr) {
2246 if (stkctr == &tmpstkctr)
2247 stktable_release(stkctr->table, stkctr_entry(stkctr));
2248 return 0; /* parameter not stored */
2249 }
2250
2251 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2252
2253 smp->data.u.sint = stktable_data_cast(ptr, conn_cur);
2254
2255 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2256
2257 if (stkctr == &tmpstkctr)
2258 stktable_release(stkctr->table, stkctr_entry(stkctr));
2259 }
2260 return 1;
2261 }
2262
2263 /* set <smp> to the cumulated number of streams from the stream's tracked
2264 * frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
2265 * "src_sess_cnt" only.
2266 */
2267 static int
smp_fetch_sc_sess_cnt(const struct arg * args,struct sample * smp,const char * kw,void * private)2268 smp_fetch_sc_sess_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2269 {
2270 struct stkctr tmpstkctr;
2271 struct stkctr *stkctr;
2272
2273 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2274 if (!stkctr)
2275 return 0;
2276
2277 smp->flags = SMP_F_VOL_TEST;
2278 smp->data.type = SMP_T_SINT;
2279 smp->data.u.sint = 0;
2280 if (stkctr_entry(stkctr) != NULL) {
2281 void *ptr;
2282
2283 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
2284 if (!ptr) {
2285 if (stkctr == &tmpstkctr)
2286 stktable_release(stkctr->table, stkctr_entry(stkctr));
2287 return 0; /* parameter not stored */
2288 }
2289
2290 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2291
2292 smp->data.u.sint = stktable_data_cast(ptr, sess_cnt);
2293
2294 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2295
2296 if (stkctr == &tmpstkctr)
2297 stktable_release(stkctr->table, stkctr_entry(stkctr));
2298 }
2299 return 1;
2300 }
2301
2302 /* set <smp> to the stream rate from the stream's tracked frontend counters.
2303 * Supports being called as "sc[0-9]_sess_rate" or "src_sess_rate" only.
2304 */
2305 static int
smp_fetch_sc_sess_rate(const struct arg * args,struct sample * smp,const char * kw,void * private)2306 smp_fetch_sc_sess_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2307 {
2308 struct stkctr tmpstkctr;
2309 struct stkctr *stkctr;
2310
2311 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2312 if (!stkctr)
2313 return 0;
2314
2315 smp->flags = SMP_F_VOL_TEST;
2316 smp->data.type = SMP_T_SINT;
2317 smp->data.u.sint = 0;
2318 if (stkctr_entry(stkctr) != NULL) {
2319 void *ptr;
2320
2321 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
2322 if (!ptr) {
2323 if (stkctr == &tmpstkctr)
2324 stktable_release(stkctr->table, stkctr_entry(stkctr));
2325 return 0; /* parameter not stored */
2326 }
2327
2328 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2329
2330 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
2331 stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u);
2332
2333 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2334
2335 if (stkctr == &tmpstkctr)
2336 stktable_release(stkctr->table, stkctr_entry(stkctr));
2337 }
2338 return 1;
2339 }
2340
2341 /* set <smp> to the cumulated number of HTTP requests from the stream's tracked
2342 * frontend counters. Supports being called as "sc[0-9]_http_req_cnt" or
2343 * "src_http_req_cnt" only.
2344 */
2345 static int
smp_fetch_sc_http_req_cnt(const struct arg * args,struct sample * smp,const char * kw,void * private)2346 smp_fetch_sc_http_req_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2347 {
2348 struct stkctr tmpstkctr;
2349 struct stkctr *stkctr;
2350
2351 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2352 if (!stkctr)
2353 return 0;
2354
2355 smp->flags = SMP_F_VOL_TEST;
2356 smp->data.type = SMP_T_SINT;
2357 smp->data.u.sint = 0;
2358 if (stkctr_entry(stkctr) != NULL) {
2359 void *ptr;
2360
2361 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_CNT);
2362 if (!ptr) {
2363 if (stkctr == &tmpstkctr)
2364 stktable_release(stkctr->table, stkctr_entry(stkctr));
2365 return 0; /* parameter not stored */
2366 }
2367
2368 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2369
2370 smp->data.u.sint = stktable_data_cast(ptr, http_req_cnt);
2371
2372 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2373
2374 if (stkctr == &tmpstkctr)
2375 stktable_release(stkctr->table, stkctr_entry(stkctr));
2376 }
2377 return 1;
2378 }
2379
2380 /* set <smp> to the HTTP request rate from the stream's tracked frontend
2381 * counters. Supports being called as "sc[0-9]_http_req_rate" or
2382 * "src_http_req_rate" only.
2383 */
2384 static int
smp_fetch_sc_http_req_rate(const struct arg * args,struct sample * smp,const char * kw,void * private)2385 smp_fetch_sc_http_req_rate(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 if (stkctr_entry(stkctr) != NULL) {
2398 void *ptr;
2399
2400 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_REQ_RATE);
2401 if (!ptr) {
2402 if (stkctr == &tmpstkctr)
2403 stktable_release(stkctr->table, stkctr_entry(stkctr));
2404 return 0; /* parameter not stored */
2405 }
2406
2407 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2408
2409 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
2410 stkctr->table->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u);
2411
2412 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2413
2414 if (stkctr == &tmpstkctr)
2415 stktable_release(stkctr->table, stkctr_entry(stkctr));
2416 }
2417 return 1;
2418 }
2419
2420 /* set <smp> to the cumulated number of HTTP requests errors from the stream's
2421 * tracked frontend counters. Supports being called as "sc[0-9]_http_err_cnt" or
2422 * "src_http_err_cnt" only.
2423 */
2424 static int
smp_fetch_sc_http_err_cnt(const struct arg * args,struct sample * smp,const char * kw,void * private)2425 smp_fetch_sc_http_err_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
2426 {
2427 struct stkctr tmpstkctr;
2428 struct stkctr *stkctr;
2429
2430 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2431 if (!stkctr)
2432 return 0;
2433
2434 smp->flags = SMP_F_VOL_TEST;
2435 smp->data.type = SMP_T_SINT;
2436 smp->data.u.sint = 0;
2437 if (stkctr_entry(stkctr) != NULL) {
2438 void *ptr;
2439
2440 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_CNT);
2441 if (!ptr) {
2442 if (stkctr == &tmpstkctr)
2443 stktable_release(stkctr->table, stkctr_entry(stkctr));
2444 return 0; /* parameter not stored */
2445 }
2446
2447 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2448
2449 smp->data.u.sint = stktable_data_cast(ptr, http_err_cnt);
2450
2451 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2452
2453 if (stkctr == &tmpstkctr)
2454 stktable_release(stkctr->table, stkctr_entry(stkctr));
2455 }
2456 return 1;
2457 }
2458
2459 /* set <smp> to the HTTP request error rate from the stream's tracked frontend
2460 * counters. Supports being called as "sc[0-9]_http_err_rate" or
2461 * "src_http_err_rate" only.
2462 */
2463 static int
smp_fetch_sc_http_err_rate(const struct arg * args,struct sample * smp,const char * kw,void * private)2464 smp_fetch_sc_http_err_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2465 {
2466 struct stkctr tmpstkctr;
2467 struct stkctr *stkctr;
2468
2469 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2470 if (!stkctr)
2471 return 0;
2472
2473 smp->flags = SMP_F_VOL_TEST;
2474 smp->data.type = SMP_T_SINT;
2475 smp->data.u.sint = 0;
2476 if (stkctr_entry(stkctr) != NULL) {
2477 void *ptr;
2478
2479 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_HTTP_ERR_RATE);
2480 if (!ptr) {
2481 if (stkctr == &tmpstkctr)
2482 stktable_release(stkctr->table, stkctr_entry(stkctr));
2483 return 0; /* parameter not stored */
2484 }
2485
2486 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2487
2488 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, http_err_rate),
2489 stkctr->table->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u);
2490
2491 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2492
2493 if (stkctr == &tmpstkctr)
2494 stktable_release(stkctr->table, stkctr_entry(stkctr));
2495 }
2496 return 1;
2497 }
2498
2499 /* set <smp> to the number of kbytes received from clients, as found in the
2500 * stream's tracked frontend counters. Supports being called as
2501 * "sc[0-9]_kbytes_in" or "src_kbytes_in" only.
2502 */
2503 static int
smp_fetch_sc_kbytes_in(const struct arg * args,struct sample * smp,const char * kw,void * private)2504 smp_fetch_sc_kbytes_in(const struct arg *args, struct sample *smp, const char *kw, void *private)
2505 {
2506 struct stkctr tmpstkctr;
2507 struct stkctr *stkctr;
2508
2509 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2510 if (!stkctr)
2511 return 0;
2512
2513 smp->flags = SMP_F_VOL_TEST;
2514 smp->data.type = SMP_T_SINT;
2515 smp->data.u.sint = 0;
2516 if (stkctr_entry(stkctr) != NULL) {
2517 void *ptr;
2518
2519 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
2520 if (!ptr) {
2521 if (stkctr == &tmpstkctr)
2522 stktable_release(stkctr->table, stkctr_entry(stkctr));
2523 return 0; /* parameter not stored */
2524 }
2525
2526 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2527
2528 smp->data.u.sint = stktable_data_cast(ptr, bytes_in_cnt) >> 10;
2529
2530 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2531
2532 if (stkctr == &tmpstkctr)
2533 stktable_release(stkctr->table, stkctr_entry(stkctr));
2534 }
2535 return 1;
2536 }
2537
2538 /* set <smp> to the data rate received from clients in bytes/s, as found
2539 * in the stream's tracked frontend counters. Supports being called as
2540 * "sc[0-9]_bytes_in_rate" or "src_bytes_in_rate" only.
2541 */
2542 static int
smp_fetch_sc_bytes_in_rate(const struct arg * args,struct sample * smp,const char * kw,void * private)2543 smp_fetch_sc_bytes_in_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2544 {
2545 struct stkctr tmpstkctr;
2546 struct stkctr *stkctr;
2547
2548 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2549 if (!stkctr)
2550 return 0;
2551
2552 smp->flags = SMP_F_VOL_TEST;
2553 smp->data.type = SMP_T_SINT;
2554 smp->data.u.sint = 0;
2555 if (stkctr_entry(stkctr) != NULL) {
2556 void *ptr;
2557
2558 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
2559 if (!ptr) {
2560 if (stkctr == &tmpstkctr)
2561 stktable_release(stkctr->table, stkctr_entry(stkctr));
2562 return 0; /* parameter not stored */
2563 }
2564
2565 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2566
2567 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
2568 stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
2569
2570 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2571
2572 if (stkctr == &tmpstkctr)
2573 stktable_release(stkctr->table, stkctr_entry(stkctr));
2574 }
2575 return 1;
2576 }
2577
2578 /* set <smp> to the number of kbytes sent to clients, as found in the
2579 * stream's tracked frontend counters. Supports being called as
2580 * "sc[0-9]_kbytes_out" or "src_kbytes_out" only.
2581 */
2582 static int
smp_fetch_sc_kbytes_out(const struct arg * args,struct sample * smp,const char * kw,void * private)2583 smp_fetch_sc_kbytes_out(const struct arg *args, struct sample *smp, const char *kw, void *private)
2584 {
2585 struct stkctr tmpstkctr;
2586 struct stkctr *stkctr;
2587
2588 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2589 if (!stkctr)
2590 return 0;
2591
2592 smp->flags = SMP_F_VOL_TEST;
2593 smp->data.type = SMP_T_SINT;
2594 smp->data.u.sint = 0;
2595 if (stkctr_entry(stkctr) != NULL) {
2596 void *ptr;
2597
2598 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
2599 if (!ptr) {
2600 if (stkctr == &tmpstkctr)
2601 stktable_release(stkctr->table, stkctr_entry(stkctr));
2602 return 0; /* parameter not stored */
2603 }
2604
2605 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2606
2607 smp->data.u.sint = stktable_data_cast(ptr, bytes_out_cnt) >> 10;
2608
2609 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2610
2611 if (stkctr == &tmpstkctr)
2612 stktable_release(stkctr->table, stkctr_entry(stkctr));
2613 }
2614 return 1;
2615 }
2616
2617 /* set <smp> to the data rate sent to clients in bytes/s, as found in the
2618 * stream's tracked frontend counters. Supports being called as
2619 * "sc[0-9]_bytes_out_rate" or "src_bytes_out_rate" only.
2620 */
2621 static int
smp_fetch_sc_bytes_out_rate(const struct arg * args,struct sample * smp,const char * kw,void * private)2622 smp_fetch_sc_bytes_out_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
2623 {
2624 struct stkctr tmpstkctr;
2625 struct stkctr *stkctr;
2626
2627 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2628 if (!stkctr)
2629 return 0;
2630
2631 smp->flags = SMP_F_VOL_TEST;
2632 smp->data.type = SMP_T_SINT;
2633 smp->data.u.sint = 0;
2634 if (stkctr_entry(stkctr) != NULL) {
2635 void *ptr;
2636
2637 ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
2638 if (!ptr) {
2639 if (stkctr == &tmpstkctr)
2640 stktable_release(stkctr->table, stkctr_entry(stkctr));
2641 return 0; /* parameter not stored */
2642 }
2643
2644 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2645
2646 smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
2647 stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
2648
2649 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
2650
2651 if (stkctr == &tmpstkctr)
2652 stktable_release(stkctr->table, stkctr_entry(stkctr));
2653 }
2654 return 1;
2655 }
2656
2657 /* set <smp> to the number of active trackers on the SC entry in the stream's
2658 * tracked frontend counters. Supports being called as "sc[0-9]_trackers" only.
2659 */
2660 static int
smp_fetch_sc_trackers(const struct arg * args,struct sample * smp,const char * kw,void * private)2661 smp_fetch_sc_trackers(const struct arg *args, struct sample *smp, const char *kw, void *private)
2662 {
2663 struct stkctr tmpstkctr;
2664 struct stkctr *stkctr;
2665
2666 stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
2667 if (!stkctr)
2668 return 0;
2669
2670 smp->flags = SMP_F_VOL_TEST;
2671 smp->data.type = SMP_T_SINT;
2672 if (stkctr == &tmpstkctr) {
2673 smp->data.u.sint = stkctr_entry(stkctr) ? (stkctr_entry(stkctr)->ref_cnt-1) : 0;
2674 stktable_release(stkctr->table, stkctr_entry(stkctr));
2675 }
2676 else {
2677 smp->data.u.sint = stkctr_entry(stkctr) ? stkctr_entry(stkctr)->ref_cnt : 0;
2678 }
2679
2680 return 1;
2681 }
2682
2683
2684 /* The functions below are used to manipulate table contents from the CLI.
2685 * There are 3 main actions, "clear", "set" and "show". The code is shared
2686 * between all actions, and the action is encoded in the void *private in
2687 * the appctx as well as in the keyword registration, among one of the
2688 * following values.
2689 */
2690
2691 enum {
2692 STK_CLI_ACT_CLR,
2693 STK_CLI_ACT_SET,
2694 STK_CLI_ACT_SHOW,
2695 };
2696
2697 /* Dump the status of a table to a stream interface's
2698 * read buffer. It returns 0 if the output buffer is full
2699 * and needs to be called again, otherwise non-zero.
2700 */
table_dump_head_to_buffer(struct chunk * msg,struct stream_interface * si,struct proxy * proxy,struct proxy * target)2701 static int table_dump_head_to_buffer(struct chunk *msg, struct stream_interface *si,
2702 struct proxy *proxy, struct proxy *target)
2703 {
2704 struct stream *s = si_strm(si);
2705
2706 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
2707 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
2708
2709 /* any other information should be dumped here */
2710
2711 if (target && (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER)
2712 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
2713
2714 if (ci_putchk(si_ic(si), msg) == -1) {
2715 si_applet_cant_put(si);
2716 return 0;
2717 }
2718
2719 return 1;
2720 }
2721
2722 /* Dump a table entry to a stream interface's
2723 * read buffer. It returns 0 if the output buffer is full
2724 * and needs to be called again, otherwise non-zero.
2725 */
table_dump_entry_to_buffer(struct chunk * msg,struct stream_interface * si,struct proxy * proxy,struct stksess * entry)2726 static int table_dump_entry_to_buffer(struct chunk *msg, struct stream_interface *si,
2727 struct proxy *proxy, struct stksess *entry)
2728 {
2729 int dt;
2730
2731 chunk_appendf(msg, "%p:", entry);
2732
2733 if (proxy->table.type == SMP_T_IPV4) {
2734 char addr[INET_ADDRSTRLEN];
2735 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
2736 chunk_appendf(msg, " key=%s", addr);
2737 }
2738 else if (proxy->table.type == SMP_T_IPV6) {
2739 char addr[INET6_ADDRSTRLEN];
2740 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
2741 chunk_appendf(msg, " key=%s", addr);
2742 }
2743 else if (proxy->table.type == SMP_T_SINT) {
2744 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
2745 }
2746 else if (proxy->table.type == SMP_T_STR) {
2747 chunk_appendf(msg, " key=");
2748 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
2749 }
2750 else {
2751 chunk_appendf(msg, " key=");
2752 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
2753 }
2754
2755 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
2756
2757 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
2758 void *ptr;
2759
2760 if (proxy->table.data_ofs[dt] == 0)
2761 continue;
2762 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
2763 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
2764 else
2765 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
2766
2767 ptr = stktable_data_ptr(&proxy->table, entry, dt);
2768 switch (stktable_data_types[dt].std_type) {
2769 case STD_T_SINT:
2770 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
2771 break;
2772 case STD_T_UINT:
2773 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
2774 break;
2775 case STD_T_ULL:
2776 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
2777 break;
2778 case STD_T_FRQP:
2779 chunk_appendf(msg, "%d",
2780 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
2781 proxy->table.data_arg[dt].u));
2782 break;
2783 }
2784 }
2785 chunk_appendf(msg, "\n");
2786
2787 if (ci_putchk(si_ic(si), msg) == -1) {
2788 si_applet_cant_put(si);
2789 return 0;
2790 }
2791
2792 return 1;
2793 }
2794
2795
2796 /* Processes a single table entry matching a specific key passed in argument.
2797 * returns 0 if wants to be called again, 1 if has ended processing.
2798 */
table_process_entry_per_key(struct appctx * appctx,char ** args)2799 static int table_process_entry_per_key(struct appctx *appctx, char **args)
2800 {
2801 struct stream_interface *si = appctx->owner;
2802 struct proxy *px = appctx->ctx.table.target;
2803 struct stksess *ts;
2804 uint32_t uint32_key;
2805 unsigned char ip6_key[sizeof(struct in6_addr)];
2806 long long value;
2807 int data_type;
2808 int cur_arg;
2809 void *ptr;
2810 struct freq_ctr_period *frqp;
2811
2812 if (!*args[4]) {
2813 appctx->ctx.cli.severity = LOG_ERR;
2814 appctx->ctx.cli.msg = "Key value expected\n";
2815 appctx->st0 = CLI_ST_PRINT;
2816 return 1;
2817 }
2818
2819 switch (px->table.type) {
2820 case SMP_T_IPV4:
2821 uint32_key = htonl(inetaddr_host(args[4]));
2822 static_table_key.key = &uint32_key;
2823 break;
2824 case SMP_T_IPV6:
2825 inet_pton(AF_INET6, args[4], ip6_key);
2826 static_table_key.key = &ip6_key;
2827 break;
2828 case SMP_T_SINT:
2829 {
2830 char *endptr;
2831 unsigned long val;
2832 errno = 0;
2833 val = strtoul(args[4], &endptr, 10);
2834 if ((errno == ERANGE && val == ULONG_MAX) ||
2835 (errno != 0 && val == 0) || endptr == args[4] ||
2836 val > 0xffffffff) {
2837 appctx->ctx.cli.severity = LOG_ERR;
2838 appctx->ctx.cli.msg = "Invalid key\n";
2839 appctx->st0 = CLI_ST_PRINT;
2840 return 1;
2841 }
2842 uint32_key = (uint32_t) val;
2843 static_table_key.key = &uint32_key;
2844 break;
2845 }
2846 break;
2847 case SMP_T_STR:
2848 static_table_key.key = args[4];
2849 static_table_key.key_len = strlen(args[4]);
2850 break;
2851 default:
2852 switch (appctx->ctx.table.action) {
2853 case STK_CLI_ACT_SHOW:
2854 appctx->ctx.cli.severity = LOG_ERR;
2855 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
2856 break;
2857 case STK_CLI_ACT_CLR:
2858 appctx->ctx.cli.severity = LOG_ERR;
2859 appctx->ctx.cli.msg = "Removing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
2860 break;
2861 case STK_CLI_ACT_SET:
2862 appctx->ctx.cli.severity = LOG_ERR;
2863 appctx->ctx.cli.msg = "Inserting keys into tables of type other than ip, ipv6, string and integer is not supported\n";
2864 break;
2865 default:
2866 appctx->ctx.cli.severity = LOG_ERR;
2867 appctx->ctx.cli.msg = "Unknown action\n";
2868 break;
2869 }
2870 appctx->st0 = CLI_ST_PRINT;
2871 return 1;
2872 }
2873
2874 /* check permissions */
2875 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
2876 return 1;
2877
2878 switch (appctx->ctx.table.action) {
2879 case STK_CLI_ACT_SHOW:
2880 ts = stktable_lookup_key(&px->table, &static_table_key);
2881 if (!ts)
2882 return 1;
2883 chunk_reset(&trash);
2884 if (!table_dump_head_to_buffer(&trash, si, px, px)) {
2885 stktable_release(&px->table, ts);
2886 return 0;
2887 }
2888 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
2889 if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
2890 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
2891 stktable_release(&px->table, ts);
2892 return 0;
2893 }
2894 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
2895 stktable_release(&px->table, ts);
2896 break;
2897
2898 case STK_CLI_ACT_CLR:
2899 ts = stktable_lookup_key(&px->table, &static_table_key);
2900 if (!ts)
2901 return 1;
2902
2903 if (!stksess_kill(&px->table, ts, 1)) {
2904 /* don't delete an entry which is currently referenced */
2905 appctx->ctx.cli.severity = LOG_ERR;
2906 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
2907 appctx->st0 = CLI_ST_PRINT;
2908 return 1;
2909 }
2910
2911 break;
2912
2913 case STK_CLI_ACT_SET:
2914 ts = stktable_get_entry(&px->table, &static_table_key);
2915 if (!ts) {
2916 /* don't delete an entry which is currently referenced */
2917 appctx->ctx.cli.severity = LOG_ERR;
2918 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
2919 appctx->st0 = CLI_ST_PRINT;
2920 return 1;
2921 }
2922
2923 HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
2924 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
2925 if (strncmp(args[cur_arg], "data.", 5) != 0) {
2926 appctx->ctx.cli.severity = LOG_ERR;
2927 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
2928 appctx->st0 = CLI_ST_PRINT;
2929 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2930 stktable_touch_local(&px->table, ts, 1);
2931 return 1;
2932 }
2933
2934 data_type = stktable_get_data_type(args[cur_arg] + 5);
2935 if (data_type < 0) {
2936 appctx->ctx.cli.severity = LOG_ERR;
2937 appctx->ctx.cli.msg = "Unknown data type\n";
2938 appctx->st0 = CLI_ST_PRINT;
2939 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2940 stktable_touch_local(&px->table, ts, 1);
2941 return 1;
2942 }
2943
2944 if (!px->table.data_ofs[data_type]) {
2945 appctx->ctx.cli.severity = LOG_ERR;
2946 appctx->ctx.cli.msg = "Data type not stored in this table\n";
2947 appctx->st0 = CLI_ST_PRINT;
2948 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2949 stktable_touch_local(&px->table, ts, 1);
2950 return 1;
2951 }
2952
2953 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
2954 appctx->ctx.cli.severity = LOG_ERR;
2955 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
2956 appctx->st0 = CLI_ST_PRINT;
2957 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2958 stktable_touch_local(&px->table, ts, 1);
2959 return 1;
2960 }
2961
2962 ptr = stktable_data_ptr(&px->table, ts, data_type);
2963
2964 switch (stktable_data_types[data_type].std_type) {
2965 case STD_T_SINT:
2966 stktable_data_cast(ptr, std_t_sint) = value;
2967 break;
2968 case STD_T_UINT:
2969 stktable_data_cast(ptr, std_t_uint) = value;
2970 break;
2971 case STD_T_ULL:
2972 stktable_data_cast(ptr, std_t_ull) = value;
2973 break;
2974 case STD_T_FRQP:
2975 /* We set both the current and previous values. That way
2976 * the reported frequency is stable during all the period
2977 * then slowly fades out. This allows external tools to
2978 * push measures without having to update them too often.
2979 */
2980 frqp = &stktable_data_cast(ptr, std_t_frqp);
2981 /* First bit is reserved for the freq_ctr_period lock
2982 Note: here we're still protected by the stksess lock
2983 so we don't need to update the update the freq_ctr_period
2984 using its internal lock */
2985 frqp->curr_tick = now_ms & ~0x1;
2986 frqp->prev_ctr = 0;
2987 frqp->curr_ctr = value;
2988 break;
2989 }
2990 }
2991 HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
2992 stktable_touch_local(&px->table, ts, 1);
2993 break;
2994
2995 default:
2996 appctx->ctx.cli.severity = LOG_ERR;
2997 appctx->ctx.cli.msg = "Unknown action\n";
2998 appctx->st0 = CLI_ST_PRINT;
2999 break;
3000 }
3001 return 1;
3002 }
3003
3004 /* Prepares the appctx fields with the data-based filters from the command line.
3005 * Returns 0 if the dump can proceed, 1 if has ended processing.
3006 */
table_prepare_data_request(struct appctx * appctx,char ** args)3007 static int table_prepare_data_request(struct appctx *appctx, char **args)
3008 {
3009 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) {
3010 appctx->ctx.cli.severity = LOG_ERR;
3011 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions";
3012 appctx->st0 = CLI_ST_PRINT;
3013 return 1;
3014 }
3015
3016 /* condition on stored data value */
3017 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
3018 if (appctx->ctx.table.data_type < 0) {
3019 appctx->ctx.cli.severity = LOG_ERR;
3020 appctx->ctx.cli.msg = "Unknown data type\n";
3021 appctx->st0 = CLI_ST_PRINT;
3022 return 1;
3023 }
3024
3025 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
3026 appctx->ctx.cli.severity = LOG_ERR;
3027 appctx->ctx.cli.msg = "Data type not stored in this table\n";
3028 appctx->st0 = CLI_ST_PRINT;
3029 return 1;
3030 }
3031
3032 appctx->ctx.table.data_op = get_std_op(args[4]);
3033 if (appctx->ctx.table.data_op < 0) {
3034 appctx->ctx.cli.severity = LOG_ERR;
3035 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
3036 appctx->st0 = CLI_ST_PRINT;
3037 return 1;
3038 }
3039
3040 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
3041 appctx->ctx.cli.severity = LOG_ERR;
3042 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
3043 appctx->st0 = CLI_ST_PRINT;
3044 return 1;
3045 }
3046
3047 /* OK we're done, all the fields are set */
3048 return 0;
3049 }
3050
3051 /* returns 0 if wants to be called, 1 if has ended processing */
cli_parse_table_req(char ** args,struct appctx * appctx,void * private)3052 static int cli_parse_table_req(char **args, struct appctx *appctx, void *private)
3053 {
3054 appctx->ctx.table.data_type = -1;
3055 appctx->ctx.table.target = NULL;
3056 appctx->ctx.table.proxy = NULL;
3057 appctx->ctx.table.entry = NULL;
3058 appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
3059
3060 if (*args[2]) {
3061 appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
3062 if (!appctx->ctx.table.target) {
3063 appctx->ctx.cli.severity = LOG_ERR;
3064 appctx->ctx.cli.msg = "No such table\n";
3065 appctx->st0 = CLI_ST_PRINT;
3066 return 1;
3067 }
3068 }
3069 else {
3070 if (appctx->ctx.table.action != STK_CLI_ACT_SHOW)
3071 goto err_args;
3072 return 0;
3073 }
3074
3075 if (strcmp(args[3], "key") == 0)
3076 return table_process_entry_per_key(appctx, args);
3077 else if (strncmp(args[3], "data.", 5) == 0)
3078 return table_prepare_data_request(appctx, args);
3079 else if (*args[3])
3080 goto err_args;
3081
3082 return 0;
3083
3084 err_args:
3085 switch (appctx->ctx.table.action) {
3086 case STK_CLI_ACT_SHOW:
3087 appctx->ctx.cli.severity = LOG_ERR;
3088 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
3089 break;
3090 case STK_CLI_ACT_CLR:
3091 appctx->ctx.cli.severity = LOG_ERR;
3092 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
3093 break;
3094 case STK_CLI_ACT_SET:
3095 appctx->ctx.cli.severity = LOG_ERR;
3096 appctx->ctx.cli.msg = "Required arguments: <table> key <key> [data.<store_data_type> <value>]*\n";
3097 break;
3098 default:
3099 appctx->ctx.cli.severity = LOG_ERR;
3100 appctx->ctx.cli.msg = "Unknown action\n";
3101 break;
3102 }
3103 appctx->st0 = CLI_ST_PRINT;
3104 return 1;
3105 }
3106
3107 /* This function is used to deal with table operations (dump or clear depending
3108 * on the action stored in appctx->private). It returns 0 if the output buffer is
3109 * full and it needs to be called again, otherwise non-zero.
3110 */
cli_io_handler_table(struct appctx * appctx)3111 static int cli_io_handler_table(struct appctx *appctx)
3112 {
3113 struct stream_interface *si = appctx->owner;
3114 struct stream *s = si_strm(si);
3115 struct ebmb_node *eb;
3116 int dt;
3117 int skip_entry;
3118 int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
3119
3120 /*
3121 * We have 3 possible states in appctx->st2 :
3122 * - STAT_ST_INIT : the first call
3123 * - STAT_ST_INFO : the proxy pointer points to the next table to
3124 * dump, the entry pointer is NULL ;
3125 * - STAT_ST_LIST : the proxy pointer points to the current table
3126 * and the entry pointer points to the next entry to be dumped,
3127 * and the refcount on the next entry is held ;
3128 * - STAT_ST_END : nothing left to dump, the buffer may contain some
3129 * data though.
3130 */
3131
3132 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
3133 /* in case of abort, remove any refcount we might have set on an entry */
3134 if (appctx->st2 == STAT_ST_LIST) {
3135 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
3136 }
3137 return 1;
3138 }
3139
3140 chunk_reset(&trash);
3141
3142 while (appctx->st2 != STAT_ST_FIN) {
3143 switch (appctx->st2) {
3144 case STAT_ST_INIT:
3145 appctx->ctx.table.proxy = appctx->ctx.table.target;
3146 if (!appctx->ctx.table.proxy)
3147 appctx->ctx.table.proxy = proxies_list;
3148
3149 appctx->ctx.table.entry = NULL;
3150 appctx->st2 = STAT_ST_INFO;
3151 break;
3152
3153 case STAT_ST_INFO:
3154 if (!appctx->ctx.table.proxy ||
3155 (appctx->ctx.table.target &&
3156 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
3157 appctx->st2 = STAT_ST_END;
3158 break;
3159 }
3160
3161 if (appctx->ctx.table.proxy->table.size) {
3162 if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
3163 return 0;
3164
3165 if (appctx->ctx.table.target &&
3166 (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
3167 /* dump entries only if table explicitly requested */
3168 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
3169 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
3170 if (eb) {
3171 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3172 appctx->ctx.table.entry->ref_cnt++;
3173 appctx->st2 = STAT_ST_LIST;
3174 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
3175 break;
3176 }
3177 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
3178 }
3179 }
3180 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3181 break;
3182
3183 case STAT_ST_LIST:
3184 skip_entry = 0;
3185
3186 HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
3187
3188 if (appctx->ctx.table.data_type >= 0) {
3189 /* we're filtering on some data contents */
3190 void *ptr;
3191 long long data;
3192
3193
3194 dt = appctx->ctx.table.data_type;
3195 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
3196 appctx->ctx.table.entry,
3197 dt);
3198
3199 data = 0;
3200 switch (stktable_data_types[dt].std_type) {
3201 case STD_T_SINT:
3202 data = stktable_data_cast(ptr, std_t_sint);
3203 break;
3204 case STD_T_UINT:
3205 data = stktable_data_cast(ptr, std_t_uint);
3206 break;
3207 case STD_T_ULL:
3208 data = stktable_data_cast(ptr, std_t_ull);
3209 break;
3210 case STD_T_FRQP:
3211 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
3212 appctx->ctx.table.proxy->table.data_arg[dt].u);
3213 break;
3214 }
3215
3216 /* skip the entry if the data does not match the test and the value */
3217 if ((data < appctx->ctx.table.value &&
3218 (appctx->ctx.table.data_op == STD_OP_EQ ||
3219 appctx->ctx.table.data_op == STD_OP_GT ||
3220 appctx->ctx.table.data_op == STD_OP_GE)) ||
3221 (data == appctx->ctx.table.value &&
3222 (appctx->ctx.table.data_op == STD_OP_NE ||
3223 appctx->ctx.table.data_op == STD_OP_GT ||
3224 appctx->ctx.table.data_op == STD_OP_LT)) ||
3225 (data > appctx->ctx.table.value &&
3226 (appctx->ctx.table.data_op == STD_OP_EQ ||
3227 appctx->ctx.table.data_op == STD_OP_LT ||
3228 appctx->ctx.table.data_op == STD_OP_LE)))
3229 skip_entry = 1;
3230 }
3231
3232 if (show && !skip_entry &&
3233 !table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
3234 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
3235 return 0;
3236 }
3237
3238 HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
3239
3240 HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
3241 appctx->ctx.table.entry->ref_cnt--;
3242
3243 eb = ebmb_next(&appctx->ctx.table.entry->key);
3244 if (eb) {
3245 struct stksess *old = appctx->ctx.table.entry;
3246 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
3247 if (show)
3248 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
3249 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
3250 __stksess_kill(&appctx->ctx.table.proxy->table, old);
3251 appctx->ctx.table.entry->ref_cnt++;
3252 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
3253 break;
3254 }
3255
3256
3257 if (show)
3258 __stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3259 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
3260 __stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
3261
3262 HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
3263
3264 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
3265 appctx->st2 = STAT_ST_INFO;
3266 break;
3267
3268 case STAT_ST_END:
3269 appctx->st2 = STAT_ST_FIN;
3270 break;
3271 }
3272 }
3273 return 1;
3274 }
3275
cli_release_show_table(struct appctx * appctx)3276 static void cli_release_show_table(struct appctx *appctx)
3277 {
3278 if (appctx->st2 == STAT_ST_LIST) {
3279 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
3280 }
3281 }
3282
3283 /* register cli keywords */
3284 static struct cli_kw_list cli_kws = {{ },{
3285 { { "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 },
3286 { { "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 },
3287 { { "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 },
3288 {{},}
3289 }};
3290
3291
3292 static struct action_kw_list tcp_conn_kws = { { }, {
3293 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
3294 { "sc-set-gpt0", parse_set_gpt0, 1 },
3295 { /* END */ }
3296 }};
3297
3298 static struct action_kw_list tcp_sess_kws = { { }, {
3299 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
3300 { "sc-set-gpt0", parse_set_gpt0, 1 },
3301 { /* END */ }
3302 }};
3303
3304 static struct action_kw_list tcp_req_kws = { { }, {
3305 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
3306 { "sc-set-gpt0", parse_set_gpt0, 1 },
3307 { /* END */ }
3308 }};
3309
3310 static struct action_kw_list tcp_res_kws = { { }, {
3311 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
3312 { "sc-set-gpt0", parse_set_gpt0, 1 },
3313 { /* END */ }
3314 }};
3315
3316 static struct action_kw_list http_req_kws = { { }, {
3317 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
3318 { "sc-set-gpt0", parse_set_gpt0, 1 },
3319 { /* END */ }
3320 }};
3321
3322 static struct action_kw_list http_res_kws = { { }, {
3323 { "sc-inc-gpc0", parse_inc_gpc0, 1 },
3324 { "sc-set-gpt0", parse_set_gpt0, 1 },
3325 { /* END */ }
3326 }};
3327
3328 ///* Note: must not be declared <const> as its list will be overwritten.
3329 // * Please take care of keeping this list alphabetically sorted.
3330 // */
3331 //static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3332 // { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3333 // { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3334 // { /* END */ },
3335 //}};
3336 /* Note: must not be declared <const> as its list will be overwritten.
3337 * Please take care of keeping this list alphabetically sorted.
3338 */
3339 static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
3340 { "sc_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3341 { "sc_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3342 { "sc_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3343 { "sc_conn_cnt", smp_fetch_sc_conn_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3344 { "sc_conn_cur", smp_fetch_sc_conn_cur, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3345 { "sc_conn_rate", smp_fetch_sc_conn_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3346 { "sc_get_gpt0", smp_fetch_sc_get_gpt0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3347 { "sc_get_gpc0", smp_fetch_sc_get_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3348 { "sc_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3349 { "sc_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3350 { "sc_http_err_rate", smp_fetch_sc_http_err_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3351 { "sc_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3352 { "sc_http_req_rate", smp_fetch_sc_http_req_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3353 { "sc_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3354 { "sc_kbytes_in", smp_fetch_sc_kbytes_in, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3355 { "sc_kbytes_out", smp_fetch_sc_kbytes_out, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3356 { "sc_sess_cnt", smp_fetch_sc_sess_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3357 { "sc_sess_rate", smp_fetch_sc_sess_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3358 { "sc_tracked", smp_fetch_sc_tracked, ARG2(1,SINT,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3359 { "sc_trackers", smp_fetch_sc_trackers, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3360 { "sc0_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3361 { "sc0_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3362 { "sc0_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3363 { "sc0_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3364 { "sc0_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3365 { "sc0_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3366 { "sc0_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3367 { "sc0_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3368 { "sc0_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3369 { "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3370 { "sc0_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3371 { "sc0_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3372 { "sc0_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3373 { "sc0_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3374 { "sc0_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3375 { "sc0_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3376 { "sc0_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3377 { "sc0_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3378 { "sc0_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3379 { "sc0_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3380 { "sc1_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3381 { "sc1_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3382 { "sc1_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3383 { "sc1_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3384 { "sc1_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3385 { "sc1_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3386 { "sc1_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3387 { "sc1_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3388 { "sc1_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3389 { "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3390 { "sc1_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3391 { "sc1_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3392 { "sc1_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3393 { "sc1_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3394 { "sc1_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3395 { "sc1_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3396 { "sc1_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3397 { "sc1_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3398 { "sc1_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3399 { "sc1_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3400 { "sc2_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3401 { "sc2_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3402 { "sc2_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3403 { "sc2_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3404 { "sc2_conn_cur", smp_fetch_sc_conn_cur, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3405 { "sc2_conn_rate", smp_fetch_sc_conn_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3406 { "sc2_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3407 { "sc2_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3408 { "sc2_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3409 { "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3410 { "sc2_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3411 { "sc2_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3412 { "sc2_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3413 { "sc2_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3414 { "sc2_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3415 { "sc2_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3416 { "sc2_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3417 { "sc2_sess_rate", smp_fetch_sc_sess_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3418 { "sc2_tracked", smp_fetch_sc_tracked, ARG1(0,TAB), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
3419 { "sc2_trackers", smp_fetch_sc_trackers, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3420 { "src_bytes_in_rate", smp_fetch_sc_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3421 { "src_bytes_out_rate", smp_fetch_sc_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3422 { "src_clr_gpc0", smp_fetch_sc_clr_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3423 { "src_conn_cnt", smp_fetch_sc_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3424 { "src_conn_cur", smp_fetch_sc_conn_cur, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3425 { "src_conn_rate", smp_fetch_sc_conn_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3426 { "src_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3427 { "src_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3428 { "src_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3429 { "src_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3430 { "src_http_err_rate", smp_fetch_sc_http_err_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3431 { "src_http_req_cnt", smp_fetch_sc_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3432 { "src_http_req_rate", smp_fetch_sc_http_req_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3433 { "src_inc_gpc0", smp_fetch_sc_inc_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3434 { "src_kbytes_in", smp_fetch_sc_kbytes_in, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3435 { "src_kbytes_out", smp_fetch_sc_kbytes_out, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3436 { "src_sess_cnt", smp_fetch_sc_sess_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3437 { "src_sess_rate", smp_fetch_sc_sess_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3438 { "src_updt_conn_cnt", smp_fetch_src_updt_conn_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
3439 { "table_avl", smp_fetch_table_avl, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3440 { "table_cnt", smp_fetch_table_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
3441 { /* END */ },
3442 }};
3443
3444
3445 /* Note: must not be declared <const> as its list will be overwritten */
3446 static struct sample_conv_kw_list sample_conv_kws = {ILH, {
3447 { "in_table", sample_conv_in_table, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_BOOL },
3448 { "table_bytes_in_rate", sample_conv_table_bytes_in_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3449 { "table_bytes_out_rate", sample_conv_table_bytes_out_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3450 { "table_conn_cnt", sample_conv_table_conn_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3451 { "table_conn_cur", sample_conv_table_conn_cur, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3452 { "table_conn_rate", sample_conv_table_conn_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3453 { "table_gpt0", sample_conv_table_gpt0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3454 { "table_gpc0", sample_conv_table_gpc0, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3455 { "table_gpc0_rate", sample_conv_table_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3456 { "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3457 { "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3458 { "table_http_req_cnt", sample_conv_table_http_req_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3459 { "table_http_req_rate", sample_conv_table_http_req_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3460 { "table_kbytes_in", sample_conv_table_kbytes_in, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3461 { "table_kbytes_out", sample_conv_table_kbytes_out, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3462 { "table_server_id", sample_conv_table_server_id, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3463 { "table_sess_cnt", sample_conv_table_sess_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3464 { "table_sess_rate", sample_conv_table_sess_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3465 { "table_trackers", sample_conv_table_trackers, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
3466 { /* END */ },
3467 }};
3468
3469 __attribute__((constructor))
__stick_table_init(void)3470 static void __stick_table_init(void)
3471 {
3472 /* register som action keywords. */
3473 tcp_req_conn_keywords_register(&tcp_conn_kws);
3474 tcp_req_sess_keywords_register(&tcp_sess_kws);
3475 tcp_req_cont_keywords_register(&tcp_req_kws);
3476 tcp_res_cont_keywords_register(&tcp_res_kws);
3477 http_req_keywords_register(&http_req_kws);
3478 http_res_keywords_register(&http_res_kws);
3479
3480 /* register sample fetch and format conversion keywords */
3481 sample_register_fetches(&smp_fetch_keywords);
3482 sample_register_convs(&sample_conv_kws);
3483 cli_register_kw(&cli_kws);
3484 }
3485