21
22
#include <ebmbtree.h>
22
23
#include <ebsttree.h>
24
#include <types/stick_table.h>
26
25
#include <proto/proxy.h>
26
#include <proto/sample.h>
27
27
#include <proto/session.h>
28
#include <proto/stick_table.h>
28
29
#include <proto/task.h>
30
#include <proto/peers.h>
31
#include <types/global.h>
33
/* structure used to return a table key built from a sample */
34
struct stktable_key *static_table_key;
32
* Free an allocate sticked session <ts>.
33
* Decrease table <t> sticked session counter .
37
* Free an allocated sticky session <ts>, and decrease sticky sessions counter
35
40
void stksess_free(struct stktable *t, struct stksess *ts)
38
pool_free2(t->pool,ts);
42
* Init or modify <key> of th sticked session <ts> present in table <t>.
44
void stksess_key(struct stktable *t, struct stksess *ts, struct stktable_key *key)
43
pool_free2(t->pool, (void *)ts - t->data_size);
47
* Kill an stksess (only if its ref_cnt is zero).
49
void stksess_kill(struct stktable *t, struct stksess *ts)
54
eb32_delete(&ts->exp);
55
eb32_delete(&ts->upd);
56
ebmb_delete(&ts->key);
61
* Initialize or update the key in the sticky session <ts> present in table <t>
62
* from the value present in <key>.
64
void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
46
66
if (t->type != STKTABLE_TYPE_STRING)
47
memcpy(ts->keys.key, key->key , t->key_size);
67
memcpy(ts->key.key, key->key, t->key_size);
49
memcpy(ts->keys.key, key->key, MIN(t->key_size - 1, key->key_len));
50
ts->keys.key[MIN(t->key_size - 1, key->key_len)] = 0;
69
memcpy(ts->key.key, key->key, MIN(t->key_size - 1, key->key_len));
70
ts->key.key[MIN(t->key_size - 1, key->key_len)] = 0;
56
* Init sticked session <ts> using <key>.
76
* Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
58
struct stksess *stksess_init(struct stktable *t, struct stksess * ts, struct stktable_key *key)
79
static struct stksess *stksess_init(struct stktable *t, struct stksess * ts)
60
ts->keys.node.leaf_p = NULL;
61
ts->exps.node.leaf_p = NULL;
63
stksess_key(t, ts, key);
81
memset((void *)ts - t->data_size, 0, t->data_size);
83
ts->key.node.leaf_p = NULL;
84
ts->exp.node.leaf_p = NULL;
85
ts->upd.node.leaf_p = NULL;
69
* Trash oldest <to_batch> sticked sessions from table <t>
70
* Returns number of trashed sticked session.
90
* Trash oldest <to_batch> sticky sessions from table <t>
91
* Returns number of trashed sticky sessions.
72
static int stktable_trash_oldest(struct stktable *t, int to_batch)
93
int stktable_trash_oldest(struct stktable *t, int to_batch)
74
95
struct stksess *ts;
75
96
struct eb32_node *eb;
78
100
eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
169
/* Existing session, returns server id */
170
return ebmb_entry(eb, struct stksess, keys);
199
return ebmb_entry(eb, struct stksess, key);
202
/* Lookup and touch <key> in <table>, or create the entry if it does not exist.
203
* This is mainly used for situations where we want to refresh a key's usage so
204
* that it does not expire, and we want to have it created if it was not there.
205
* The stksess is returned, or NULL if it could not be created.
207
struct stksess *stktable_update_key(struct stktable *table, struct stktable_key *key)
211
ts = stktable_lookup_key(table, key);
213
return stktable_touch(table, ts, 1);
215
/* entry does not exist, initialize a new one */
216
ts = stksess_new(table, key);
218
stktable_store(table, ts, 1);
174
* Store sticked session if not present in table.
175
* Il already present, update the existing session.
223
* Looks in table <t> for a sticky session with same key as <ts>.
224
* Returns pointer on requested sticky session or NULL if none was found.
177
int stktable_store(struct stktable *t, struct stksess *tsess, int sid)
226
struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
180
228
struct ebmb_node *eb;
182
230
if (t->type == STKTABLE_TYPE_STRING)
183
eb = ebst_lookup(&(t->keys), (char *)tsess->keys.key);
231
eb = ebst_lookup(&(t->keys), (char *)ts->key.key);
185
eb = ebmb_lookup(&(t->keys), tsess->keys.key, t->key_size);
189
ebmb_insert(&t->keys, &tsess->keys, t->key_size);
191
tsess->exps.key = tsess->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
192
eb32_insert(&t->exps, &tsess->exps);
195
t->exp_task->expire = t->exp_next = tick_first(tsess->expire, t->exp_next);
196
task_queue(t->exp_task);
233
eb = ebmb_lookup(&(t->keys), ts->key.key, t->key_size);
238
return ebmb_entry(eb, struct stksess, key);
241
/* Update the expiration timer for <ts> but do not touch its expiration node.
242
* The table's expiration timer is updated if set.
244
struct stksess *stktable_touch(struct stktable *t, struct stksess *ts, int local)
246
struct eb32_node * eb;
247
ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
249
t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
250
task_queue(t->exp_task);
253
if (t->sync_task && local) {
254
ts->upd.key = ++t->update;
255
t->localupdate = t->update;
256
eb32_delete(&ts->upd);
257
eb = eb32_insert(&t->updates, &ts->upd);
258
if (eb != &ts->upd) {
260
eb32_insert(&t->updates, &ts->upd);
201
/* Existing track session */
202
ts = ebmb_entry(eb, struct stksess, keys);
204
if ( ts->sid != sid )
262
task_wakeup(t->sync_task, TASK_WOKEN_MSG);
267
/* Insert new sticky session <ts> in the table. It is assumed that it does not
268
* yet exist (the caller must check this). The table's timeout is updated if it
269
* is set. <ts> is returned.
271
struct stksess *stktable_store(struct stktable *t, struct stksess *ts, int local)
273
ebmb_insert(&t->keys, &ts->key, t->key_size);
274
stktable_touch(t, ts, local);
275
ts->exp.key = ts->expire;
276
eb32_insert(&t->exps, &ts->exp);
280
/* Returns a valid or initialized stksess for the specified stktable_key in the
281
* specified table, or NULL if the key was NULL, or if no entry was found nor
282
* could be created. The entry's expiration is updated.
284
struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
291
ts = stktable_lookup_key(table, key);
293
/* entry does not exist, initialize a new one */
294
ts = stksess_new(table, key);
297
stktable_store(table, ts, 1);
300
stktable_touch(table, ts, 1);
210
* Trash expired sticked sessions from table <t>.
305
* Trash expired sticky sessions from table <t>. The next expiration date is
212
308
static int stktable_trash_expired(struct stktable *t)
214
310
struct stksess *ts;
215
311
struct eb32_node *eb;
217
314
eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
449
/*****************************************************************/
450
/* typed sample to typed table key functions */
451
/*****************************************************************/
453
static void *k_int2int(struct sample *smp, union stktable_key_data *kdata, size_t *len)
455
return (void *)&smp->data.uint;
458
static void *k_ip2ip(struct sample *smp, union stktable_key_data *kdata, size_t *len)
460
if (smp->type == SMP_T_IPV6) {
461
v6tov4(&kdata->ip, &smp->data.ipv6);
462
return (void *)&kdata->ip.s_addr;
465
return (void *)&smp->data.ipv4.s_addr;
469
static void *k_ip2ipv6(struct sample *smp, union stktable_key_data *kdata, size_t *len)
471
if (smp->type == SMP_T_IPV6) {
472
return (void *)&smp->data.ipv6.s6_addr;
475
v4tov6(&kdata->ipv6, &smp->data.ipv4);
476
return (void *)&kdata->ipv6.s6_addr;
480
static void *k_ip2int(struct sample *smp, union stktable_key_data *kdata, size_t *len)
482
if (smp->type == SMP_T_IPV6) {
483
if (!v6tov4(&kdata->ip, &smp->data.ipv6))
485
kdata->integer = ntohl(kdata->ip.s_addr);
488
kdata->integer = ntohl(smp->data.ipv4.s_addr);
490
return (void *)&kdata->integer;
493
static void *k_int2ip(struct sample *smp, union stktable_key_data *kdata, size_t *len)
495
kdata->ip.s_addr = htonl(smp->data.uint);
496
return (void *)&kdata->ip.s_addr;
499
static void *k_str2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
501
*len = smp->data.str.len;
502
return (void *)smp->data.str.str;
505
static void *k_ip2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
507
if (smp->type == SMP_T_IPV6) {
508
if (!inet_ntop(AF_INET6, &smp->data.ipv6, kdata->buf, *len))
512
if (!inet_ntop(AF_INET, &smp->data.ipv4, kdata->buf, *len))
516
*len = strlen((const char *)kdata->buf);
517
return (void *)kdata->buf;
520
static void *k_bin2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
527
while (ptr < smp->data.str.len && size <= max - 2) {
528
c = smp->data.str.str[ptr++];
529
kdata->buf[size++] = hextab[(c >> 4) & 0xF];
530
kdata->buf[size++] = hextab[c & 0xF];
533
return (void *)kdata->buf;
536
static void *k_int2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
540
key = (void *)ultoa_r(smp->data.uint, kdata->buf, *len);
544
*len = strlen((const char *)key);
548
static void *k_str2ip(struct sample *smp, union stktable_key_data *kdata, size_t *len)
550
if (!buf2ip(smp->data.str.str, smp->data.str.len, &kdata->ip))
553
return (void *)&kdata->ip.s_addr;
556
static void *k_str2ipv6(struct sample *smp, union stktable_key_data *kdata, size_t *len)
558
if (!inet_pton(AF_INET6, smp->data.str.str, &kdata->ipv6))
561
return (void *)&kdata->ipv6.s6_addr;
564
static void *k_str2int(struct sample *smp, union stktable_key_data *kdata, size_t *len)
569
for (i = 0; i < smp->data.str.len; i++) {
570
uint32_t val = smp->data.str.str[i] - '0';
575
kdata->integer = kdata->integer * 10 + val;
577
return (void *)&kdata->integer;
580
/*****************************************************************/
581
/* typed sample to typed table key matrix: */
582
/* sample_to_key[from sample type][to table key type] */
583
/* NULL pointer used for impossible sample casts */
584
/*****************************************************************/
586
typedef void *(*sample_to_key_fct)(struct sample *smp, union stktable_key_data *kdata, size_t *len);
587
static sample_to_key_fct sample_to_key[SMP_TYPES][STKTABLE_TYPES] = {
588
/* table type: IP IPV6 INTEGER STRING BINARY */
589
/* patt. type: BOOL */ { NULL, NULL, k_int2int, k_int2str, NULL },
590
/* UINT */ { k_int2ip, NULL, k_int2int, k_int2str, NULL },
591
/* SINT */ { k_int2ip, NULL, k_int2int, k_int2str, NULL },
592
/* ADDR */ { k_ip2ip, k_ip2ipv6, k_ip2int, k_ip2str, NULL },
593
/* IPV4 */ { k_ip2ip, k_ip2ipv6, k_ip2int, k_ip2str, NULL },
594
/* IPV6 */ { k_ip2ip, k_ip2ipv6, k_ip2int, k_ip2str, NULL },
595
/* STR */ { k_str2ip, k_str2ipv6, k_str2int, k_str2str, k_str2str },
596
/* BIN */ { NULL, NULL, NULL, k_bin2str, k_str2str },
601
* Process a fetch + format conversion as defined by the sample expression <expr>
602
* on request or response considering the <opt> parameter. Returns either NULL if
603
* no key could be extracted, or a pointer to the converted result stored in
604
* static_table_key in format <table_type>.
606
struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *l4, void *l7,
608
struct sample_expr *expr)
612
smp = sample_process(px, l4, l7, opt, expr, NULL);
616
if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
617
return NULL; /* we can only use stable samples */
619
if (!sample_to_key[smp->type][t->type])
622
static_table_key->key_len = t->key_size;
623
static_table_key->key = sample_to_key[smp->type][t->type](smp, &static_table_key->data, &static_table_key->key_len);
625
if (!static_table_key->key)
628
if (static_table_key->key_len == 0)
631
if ((static_table_key->key_len < t->key_size) && (t->type != STKTABLE_TYPE_STRING)) {
632
/* need padding with null */
634
/* assume static_table_key.key_len is less than sizeof(static_table_key.data.buf)
635
cause t->key_size is necessary less than sizeof(static_table_key.data) */
637
if ((char *)static_table_key->key > (char *)&static_table_key->data &&
638
(char *)static_table_key->key < (char *)&static_table_key->data + global.tune.bufsize) {
639
/* key buffer is part of the static_table_key private data buffer, but is not aligned */
641
if (global.tune.bufsize - ((char *)static_table_key->key - (char *)&static_table_key->data) < t->key_size) {
642
/* if not remain enough place for padding , process a realign */
643
memmove(static_table_key->data.buf, static_table_key->key, static_table_key->key_len);
644
static_table_key->key = static_table_key->data.buf;
647
else if (static_table_key->key != static_table_key->data.buf) {
648
/* key definitly not part of the static_table_key private data buffer */
650
memcpy(static_table_key->data.buf, static_table_key->key, static_table_key->key_len);
651
static_table_key->key = static_table_key->data.buf;
654
memset(static_table_key->key + static_table_key->key_len, 0, t->key_size - static_table_key->key_len);
657
return static_table_key;
661
* Returns 1 if sample expression <expr> result can be converted to table key of
662
* type <table_type>, otherwise zero. Used in configuration check.
664
int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
668
if (table_type >= STKTABLE_TYPES)
671
out_type = smp_expr_output_type(expr);
672
if (!sample_to_key[out_type][table_type])
678
/* Extra data types processing */
679
struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
680
[STKTABLE_DT_SERVER_ID] = { .name = "server_id", .std_type = STD_T_SINT },
681
[STKTABLE_DT_GPC0] = { .name = "gpc0", .std_type = STD_T_UINT },
682
[STKTABLE_DT_GPC0_RATE] = { .name = "gpc0_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
683
[STKTABLE_DT_CONN_CNT] = { .name = "conn_cnt", .std_type = STD_T_UINT },
684
[STKTABLE_DT_CONN_RATE] = { .name = "conn_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
685
[STKTABLE_DT_CONN_CUR] = { .name = "conn_cur", .std_type = STD_T_UINT },
686
[STKTABLE_DT_SESS_CNT] = { .name = "sess_cnt", .std_type = STD_T_UINT },
687
[STKTABLE_DT_SESS_RATE] = { .name = "sess_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
688
[STKTABLE_DT_HTTP_REQ_CNT] = { .name = "http_req_cnt", .std_type = STD_T_UINT },
689
[STKTABLE_DT_HTTP_REQ_RATE] = { .name = "http_req_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
690
[STKTABLE_DT_HTTP_ERR_CNT] = { .name = "http_err_cnt", .std_type = STD_T_UINT },
691
[STKTABLE_DT_HTTP_ERR_RATE] = { .name = "http_err_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
692
[STKTABLE_DT_BYTES_IN_CNT] = { .name = "bytes_in_cnt", .std_type = STD_T_ULL },
693
[STKTABLE_DT_BYTES_IN_RATE] = { .name = "bytes_in_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
694
[STKTABLE_DT_BYTES_OUT_CNT] = { .name = "bytes_out_cnt", .std_type = STD_T_ULL },
695
[STKTABLE_DT_BYTES_OUT_RATE]= { .name = "bytes_out_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
699
* Returns the data type number for the stktable_data_type whose name is <name>,
700
* or <0 if not found.
702
int stktable_get_data_type(char *name)
706
for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
707
if (strcmp(name, stktable_data_types[type].name) == 0)
713
/* Returns pointer to proxy containing table <name> or NULL if not found */
714
struct proxy *find_stktable(const char *name)
717
struct ebpt_node *node;
719
for (node = ebis_lookup(&proxy_by_name, name); node; node = ebpt_next(node)) {
720
px = container_of(node, struct proxy, conf.by_name);
722
if (strcmp(px->id, name) != 0)