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