~ubuntu-branches/debian/stretch/haproxy/stretch

« back to all changes in this revision

Viewing changes to src/stick_table.c

  • Committer: Package Import Robot
  • Author(s): Apollon Oikonomopoulos
  • Date: 2014-06-20 11:05:17 UTC
  • mfrom: (1.1.15) (15.1.12 experimental)
  • Revision ID: package-import@ubuntu.com-20140620110517-u6q5p9kyy2f3ozw9
Tags: 1.5.0-1
* New upstream stable series. Notable changes since the 1.4 series:
  + Native SSL support on both sides with SNI/NPN/ALPN and OCSP stapling.
  + IPv6 and UNIX sockets are supported everywhere
  + End-to-end HTTP keep-alive for better support of NTLM and improved
    efficiency in static farms
  + HTTP/1.1 response compression (deflate, gzip) to save bandwidth
  + PROXY protocol versions 1 and 2 on both sides
  + Data sampling on everything in request or response, including payload
  + ACLs can use any matching method with any input sample
  + Maps and dynamic ACLs updatable from the CLI
  + Stick-tables support counters to track activity on any input sample
  + Custom format for logs, unique-id, header rewriting, and redirects
  + Improved health checks (SSL, scripted TCP, check agent, ...)
  + Much more scalable configuration supports hundreds of thousands of
    backends and certificates without sweating

* Upload to unstable, merge all 1.5 work from experimental. Most important
  packaging changes since 1.4.25-1 include:
  + systemd support.
  + A more sane default config file.
  + Zero-downtime upgrades between 1.5 releases by gracefully reloading
    HAProxy during upgrades.
  + HTML documentation shipped in the haproxy-doc package.
  + kqueue support for kfreebsd.

* Packaging changes since 1.5~dev26-2:
  + Drop patches merged upstream:
    o Fix-reference-location-in-manpage.patch
    o 0001-BUILD-stats-workaround-stupid-and-bogus-Werror-forma.patch
  + d/watch: look for stable 1.5 releases
  + systemd: respect CONFIG and EXTRAOPTS when specified in
    /etc/default/haproxy.
  + initscript: test the configuration before start or reload.
  + initscript: remove the ENABLED flag and logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * Stick tables management functions.
3
3
 *
4
4
 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
 
5
 * Copyright (C) 2010 Willy Tarreau <w@1wt.eu>
5
6
 *
6
7
 * This program is free software; you can redistribute it and/or
7
8
 * modify it under the terms of the GNU General Public License
21
22
#include <ebmbtree.h>
22
23
#include <ebsttree.h>
23
24
 
24
 
#include <types/stick_table.h>
25
 
 
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>
29
32
 
 
33
/* structure used to return a table key built from a sample */
 
34
struct stktable_key *static_table_key;
30
35
 
31
36
/*
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
 
38
 * in table <t>.
34
39
 */
35
40
void stksess_free(struct stktable *t, struct stksess *ts)
36
41
{
37
42
        t->current--;
38
 
        pool_free2(t->pool,ts);
39
 
}
40
 
 
41
 
/*
42
 
 * Init or modify <key> of th sticked session <ts> present in table <t>.
43
 
 */
44
 
void stksess_key(struct stktable *t, struct stksess *ts, struct stktable_key *key)
 
43
        pool_free2(t->pool, (void *)ts - t->data_size);
 
44
}
 
45
 
 
46
/*
 
47
 * Kill an stksess (only if its ref_cnt is zero).
 
48
 */
 
49
void stksess_kill(struct stktable *t, struct stksess *ts)
 
50
{
 
51
        if (ts->ref_cnt)
 
52
                return;
 
53
 
 
54
        eb32_delete(&ts->exp);
 
55
        eb32_delete(&ts->upd);
 
56
        ebmb_delete(&ts->key);
 
57
        stksess_free(t, ts);
 
58
}
 
59
 
 
60
/*
 
61
 * Initialize or update the key in the sticky session <ts> present in table <t>
 
62
 * from the value present in <key>.
 
63
 */
 
64
void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key)
45
65
{
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);
48
68
        else {
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;
51
71
        }
52
72
}
53
73
 
54
74
 
55
75
/*
56
 
 * Init sticked session <ts> using <key>.
 
76
 * Init sticky session <ts> of table <t>. The data parts are cleared and <ts>
 
77
 * is returned.
57
78
 */
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)
59
80
{
60
 
        ts->keys.node.leaf_p = NULL;
61
 
        ts->exps.node.leaf_p = NULL;
62
 
        ts->sid = 0;
63
 
        stksess_key(t, ts, key);
64
 
 
 
81
        memset((void *)ts - t->data_size, 0, t->data_size);
 
82
        ts->ref_cnt = 0;
 
83
        ts->key.node.leaf_p = NULL;
 
84
        ts->exp.node.leaf_p = NULL;
 
85
        ts->upd.node.leaf_p = NULL;
65
86
        return ts;
66
87
}
67
88
 
68
89
/*
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.
71
92
 */
72
 
static int stktable_trash_oldest(struct stktable *t, int to_batch)
 
93
int stktable_trash_oldest(struct stktable *t, int to_batch)
73
94
{
74
95
        struct stksess *ts;
75
96
        struct eb32_node *eb;
76
97
        int batched = 0;
 
98
        int looped = 0;
77
99
 
78
100
        eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
79
101
 
82
104
                if (unlikely(!eb)) {
83
105
                        /* we might have reached the end of the tree, typically because
84
106
                         * <now_ms> is in the first half and we're first scanning the last
85
 
                         * half. Let's loop back to the beginning of the tree now.
 
107
                         * half. Let's loop back to the beginning of the tree now if we
 
108
                         * have not yet visited it.
86
109
                         */
 
110
                        if (looped)
 
111
                                break;
 
112
                        looped = 1;
87
113
                        eb = eb32_first(&t->exps);
88
114
                        if (likely(!eb))
89
115
                                break;
90
116
                }
91
117
 
92
118
                /* timer looks expired, detach it from the queue */
93
 
                ts = eb32_entry(eb, struct stksess, exps);
 
119
                ts = eb32_entry(eb, struct stksess, exp);
94
120
                eb = eb32_next(eb);
95
121
 
96
 
                eb32_delete(&ts->exps);
97
 
 
98
 
                if (ts->expire != ts->exps.key) {
99
 
 
 
122
                /* don't delete an entry which is currently referenced */
 
123
                if (ts->ref_cnt)
 
124
                        continue;
 
125
 
 
126
                eb32_delete(&ts->exp);
 
127
 
 
128
                if (ts->expire != ts->exp.key) {
100
129
                        if (!tick_isset(ts->expire))
101
130
                                continue;
102
131
 
103
 
                        ts->exps.key = ts->expire;
104
 
 
105
 
                        eb32_insert(&t->exps, &ts->exps);
106
 
 
107
 
                        if (!eb || eb->key > ts->exps.key)
108
 
                                eb = &ts->exps;
 
132
                        ts->exp.key = ts->expire;
 
133
                        eb32_insert(&t->exps, &ts->exp);
 
134
 
 
135
                        if (!eb || eb->key > ts->exp.key)
 
136
                                eb = &ts->exp;
109
137
 
110
138
                        continue;
111
139
                }
 
140
 
112
141
                /* session expired, trash it */
113
 
 
114
 
                ebmb_delete(&ts->keys);
 
142
                ebmb_delete(&ts->key);
 
143
                eb32_delete(&ts->upd);
115
144
                stksess_free(t, ts);
116
145
                batched++;
117
146
        }
120
149
}
121
150
 
122
151
/*
123
 
 *  Allocate and initialise a new sticked session.
124
 
 *  The new sticked session is returned or NULL in case of lack of memory.
125
 
 *  Sticked sessions should only be allocated this way, and must be
126
 
 *  freed using stksess_free().
127
 
 *  Increase table <t> sticked session counter.
 
152
 * Allocate and initialise a new sticky session.
 
153
 * The new sticky session is returned or NULL in case of lack of memory.
 
154
 * Sticky sessions should only be allocated this way, and must be freed using
 
155
 * stksess_free(). Table <t>'s sticky session counter is increased. If <key>
 
156
 * is not NULL, it is assigned to the new session.
128
157
 */
129
158
struct stksess *stksess_new(struct stktable *t, struct stktable_key *key)
130
159
{
134
163
                if ( t->nopurge )
135
164
                        return NULL;
136
165
 
137
 
                if (!stktable_trash_oldest(t, t->size >> 8))
 
166
                if (!stktable_trash_oldest(t, (t->size >> 8) + 1))
138
167
                        return NULL;
139
168
        }
140
169
 
141
 
        ts = pool_alloc2(t->pool);
 
170
        ts = pool_alloc2(t->pool) + t->data_size;
142
171
        if (ts) {
143
172
                t->current++;
144
 
                stksess_init(t, ts, key);
 
173
                stksess_init(t, ts);
 
174
                if (key)
 
175
                        stksess_setkey(t, ts, key);
145
176
        }
146
177
 
147
178
        return ts;
148
179
}
149
180
 
150
181
/*
151
 
 * Lookup in table <t> for a sticked session identified by <key>.
152
 
 * Returns pointer on requested sticked session or NULL if no one found.
 
182
 * Looks in table <t> for a sticky session matching key <key>.
 
183
 * Returns pointer on requested sticky session or NULL if none was found.
153
184
 */
154
 
struct stksess *stktable_lookup(struct stktable *t, struct stktable_key *key)
 
185
struct stksess *stktable_lookup_key(struct stktable *t, struct stktable_key *key)
155
186
{
156
187
        struct ebmb_node *eb;
157
188
 
158
 
        /* lookup on track session */
159
189
        if (t->type == STKTABLE_TYPE_STRING)
160
 
                eb = ebst_lookup_len(&t->keys, key->key, key->key_len);
 
190
                eb = ebst_lookup_len(&t->keys, key->key, key->key_len+1 < t->key_size ? key->key_len : t->key_size-1);
161
191
        else
162
192
                eb = ebmb_lookup(&t->keys, key->key, t->key_size);
163
193
 
166
196
                return NULL;
167
197
        }
168
198
 
169
 
        /* Existing session, returns server id */
170
 
        return ebmb_entry(eb, struct stksess, keys);
 
199
        return ebmb_entry(eb, struct stksess, key);
 
200
}
 
201
 
 
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.
 
206
 */
 
207
struct stksess *stktable_update_key(struct stktable *table, struct stktable_key *key)
 
208
{
 
209
        struct stksess *ts;
 
210
 
 
211
        ts = stktable_lookup_key(table, key);
 
212
        if (likely(ts))
 
213
                return stktable_touch(table, ts, 1);
 
214
 
 
215
        /* entry does not exist, initialize a new one */
 
216
        ts = stksess_new(table, key);
 
217
        if (likely(ts))
 
218
                stktable_store(table, ts, 1);
 
219
        return ts;
171
220
}
172
221
 
173
222
/*
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.
176
225
 */
177
 
int stktable_store(struct stktable *t, struct stksess *tsess, int sid)
 
226
struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts)
178
227
{
179
 
        struct stksess *ts;
180
228
        struct ebmb_node *eb;
181
229
 
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);
184
232
        else
185
 
                eb = ebmb_lookup(&(t->keys), tsess->keys.key, t->key_size);
186
 
 
187
 
        if (unlikely(!eb)) {
188
 
                tsess->sid = sid;
189
 
                ebmb_insert(&t->keys, &tsess->keys, t->key_size);
190
 
 
191
 
                tsess->exps.key = tsess->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
192
 
                eb32_insert(&t->exps, &tsess->exps);
193
 
 
194
 
                if (t->expire) {
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);
 
234
 
 
235
        if (unlikely(!eb))
 
236
                return NULL;
 
237
 
 
238
        return ebmb_entry(eb, struct stksess, key);
 
239
}
 
240
 
 
241
/* Update the expiration timer for <ts> but do not touch its expiration node.
 
242
 * The table's expiration timer is updated if set.
 
243
 */
 
244
struct stksess *stktable_touch(struct stktable *t, struct stksess *ts, int local)
 
245
{
 
246
        struct eb32_node * eb;
 
247
        ts->expire = tick_add(now_ms, MS_TO_TICKS(t->expire));
 
248
        if (t->expire) {
 
249
                t->exp_task->expire = t->exp_next = tick_first(ts->expire, t->exp_next);
 
250
                task_queue(t->exp_task);
 
251
        }
 
252
 
 
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)  {
 
259
                        eb32_delete(eb);
 
260
                        eb32_insert(&t->updates, &ts->upd);
197
261
                }
198
 
                return 0;
199
 
        }
200
 
 
201
 
        /* Existing track session */
202
 
        ts = ebmb_entry(eb, struct stksess, keys);
203
 
 
204
 
        if ( ts->sid != sid )
205
 
                ts->sid = sid;
206
 
        return 1;
 
262
                task_wakeup(t->sync_task, TASK_WOKEN_MSG);
 
263
        }
 
264
        return ts;
 
265
}
 
266
 
 
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.
 
270
 */
 
271
struct stksess *stktable_store(struct stktable *t, struct stksess *ts, int local)
 
272
{
 
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);
 
277
        return ts;
 
278
}
 
279
 
 
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.
 
283
 */
 
284
struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key)
 
285
{
 
286
        struct stksess *ts;
 
287
 
 
288
        if (!key)
 
289
                return NULL;
 
290
 
 
291
        ts = stktable_lookup_key(table, key);
 
292
        if (ts == NULL) {
 
293
                /* entry does not exist, initialize a new one */
 
294
                ts = stksess_new(table, key);
 
295
                if (!ts)
 
296
                        return NULL;
 
297
                stktable_store(table, ts, 1);
 
298
        }
 
299
        else
 
300
                stktable_touch(table, ts, 1);
 
301
        return ts;
207
302
}
208
303
 
209
304
/*
210
 
 * Trash expired sticked sessions from table <t>.
 
305
 * Trash expired sticky sessions from table <t>. The next expiration date is
 
306
 * returned.
211
307
 */
212
308
static int stktable_trash_expired(struct stktable *t)
213
309
{
214
310
        struct stksess *ts;
215
311
        struct eb32_node *eb;
 
312
        int looped = 0;
216
313
 
217
314
        eb = eb32_lookup_ge(&t->exps, now_ms - TIMER_LOOK_BACK);
218
315
 
220
317
                if (unlikely(!eb)) {
221
318
                        /* we might have reached the end of the tree, typically because
222
319
                         * <now_ms> is in the first half and we're first scanning the last
223
 
                         * half. Let's loop back to the beginning of the tree now.
 
320
                         * half. Let's loop back to the beginning of the tree now if we
 
321
                         * have not yet visited it.
224
322
                         */
 
323
                        if (looped)
 
324
                                break;
 
325
                        looped = 1;
225
326
                        eb = eb32_first(&t->exps);
226
327
                        if (likely(!eb))
227
328
                                break;
234
335
                }
235
336
 
236
337
                /* timer looks expired, detach it from the queue */
237
 
                ts = eb32_entry(eb, struct stksess, exps);
 
338
                ts = eb32_entry(eb, struct stksess, exp);
238
339
                eb = eb32_next(eb);
239
340
 
240
 
                eb32_delete(&ts->exps);
 
341
                /* don't delete an entry which is currently referenced */
 
342
                if (ts->ref_cnt)
 
343
                        continue;
 
344
 
 
345
                eb32_delete(&ts->exp);
241
346
 
242
347
                if (!tick_is_expired(ts->expire, now_ms)) {
243
348
                        if (!tick_isset(ts->expire))
244
349
                                continue;
245
350
 
246
 
                        ts->exps.key = ts->expire;
247
 
                        eb32_insert(&t->exps, &ts->exps);
 
351
                        ts->exp.key = ts->expire;
 
352
                        eb32_insert(&t->exps, &ts->exp);
248
353
 
249
 
                        if (!eb || eb->key > ts->exps.key)
250
 
                                eb = &ts->exps;
 
354
                        if (!eb || eb->key > ts->exp.key)
 
355
                                eb = &ts->exp;
251
356
                        continue;
252
357
                }
253
358
 
254
359
                /* session expired, trash it */
255
 
                ebmb_delete(&ts->keys);
 
360
                ebmb_delete(&ts->key);
 
361
                eb32_delete(&ts->upd);
256
362
                stksess_free(t, ts);
257
363
        }
258
364
 
262
368
}
263
369
 
264
370
/*
265
 
 * Task processing function to trash expired sticked sessions.
 
371
 * Task processing function to trash expired sticky sessions. A pointer to the
 
372
 * task itself is returned since it never dies.
266
373
 */
267
 
static struct task *process_table_expire(struct task * task)
 
374
static struct task *process_table_expire(struct task *task)
268
375
{
269
376
        struct stktable *t = (struct stktable *)task->context;
270
377
 
272
379
        return task;
273
380
}
274
381
 
275
 
/* Perform minimal intializations, report 0 in case of error, 1 if OK. */
 
382
/* Perform minimal stick table intializations, report 0 in case of error, 1 if OK. */
276
383
int stktable_init(struct stktable *t)
277
384
{
278
385
        if (t->size) {
279
386
                memset(&t->keys, 0, sizeof(t->keys));
280
387
                memset(&t->exps, 0, sizeof(t->exps));
281
388
 
282
 
                t->pool = create_pool("sticktables", sizeof(struct stksess) + t->key_size, MEM_F_SHARED);
 
389
                t->pool = create_pool("sticktables", sizeof(struct stksess) + t->data_size + t->key_size, MEM_F_SHARED);
283
390
 
284
391
                t->exp_next = TICK_ETERNITY;
285
392
                if ( t->expire ) {
288
395
                        t->exp_task->expire = TICK_ETERNITY;
289
396
                        t->exp_task->context = (void *)t;
290
397
                }
 
398
                if (t->peers.p && t->peers.p->peers_fe) {
 
399
                        peers_register_table(t->peers.p, t);
 
400
                }
 
401
 
291
402
                return t->pool != NULL;
292
403
        }
293
404
        return 1;
296
407
/*
297
408
 * Configuration keywords of known table types
298
409
 */
299
 
struct stktable_type stktable_types[STKTABLE_TYPES] = { { "ip", 0, 4 } ,
 
410
struct stktable_type stktable_types[STKTABLE_TYPES] =  {{ "ip", 0, 4 },
 
411
                                                        { "ipv6", 0, 16 },
300
412
                                                        { "integer", 0, 4 },
301
 
                                                        { "string", STKTABLE_TYPEFLAG_CUSTOMKEYSIZE, 32 } };
 
413
                                                        { "string", STK_F_CUSTOM_KEYSIZE, 32 },
 
414
                                                        { "binary", STK_F_CUSTOM_KEYSIZE, 32 } };
302
415
 
303
416
 
304
417
/*
315
428
                *key_size =  stktable_types[*type].default_size;
316
429
                (*myidx)++;
317
430
 
318
 
                if (stktable_types[*type].flags & STKTABLE_TYPEFLAG_CUSTOMKEYSIZE) {
 
431
                if (stktable_types[*type].flags & STK_F_CUSTOM_KEYSIZE) {
319
432
                        if (strcmp("len", args[*myidx]) == 0) {
320
433
                                (*myidx)++;
321
434
                                *key_size = atol(args[*myidx]);
322
 
                                if ( !*key_size )
 
435
                                if (!*key_size)
323
436
                                        break;
324
 
                                /* null terminated string needs +1 for '\0'. */
325
 
                                (*key_size)++;
 
437
                                if (*type == STKTABLE_TYPE_STRING) {
 
438
                                        /* null terminated string needs +1 for '\0'. */
 
439
                                        (*key_size)++;
 
440
                                }
326
441
                                (*myidx)++;
327
442
                        }
328
443
                }
331
446
        return 1;
332
447
}
333
448
 
334
 
 
 
449
/*****************************************************************/
 
450
/*    typed sample to typed table key functions                  */
 
451
/*****************************************************************/
 
452
 
 
453
static void *k_int2int(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
454
{
 
455
        return (void *)&smp->data.uint;
 
456
}
 
457
 
 
458
static void *k_ip2ip(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
459
{
 
460
        if (smp->type == SMP_T_IPV6) {
 
461
                v6tov4(&kdata->ip, &smp->data.ipv6);
 
462
                return (void *)&kdata->ip.s_addr;
 
463
        }
 
464
        else {
 
465
                return (void *)&smp->data.ipv4.s_addr;
 
466
        }
 
467
}
 
468
 
 
469
static void *k_ip2ipv6(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
470
{
 
471
        if (smp->type == SMP_T_IPV6) {
 
472
                return (void *)&smp->data.ipv6.s6_addr;
 
473
        }
 
474
        else {
 
475
                v4tov6(&kdata->ipv6, &smp->data.ipv4);
 
476
                return (void *)&kdata->ipv6.s6_addr;
 
477
        }
 
478
}
 
479
 
 
480
static void *k_ip2int(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
481
{
 
482
        if (smp->type == SMP_T_IPV6) {
 
483
                if (!v6tov4(&kdata->ip, &smp->data.ipv6))
 
484
                        return NULL;
 
485
                kdata->integer = ntohl(kdata->ip.s_addr);
 
486
        }
 
487
        else {
 
488
                kdata->integer = ntohl(smp->data.ipv4.s_addr);
 
489
        }
 
490
        return (void *)&kdata->integer;
 
491
}
 
492
 
 
493
static void *k_int2ip(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
494
{
 
495
        kdata->ip.s_addr = htonl(smp->data.uint);
 
496
        return (void *)&kdata->ip.s_addr;
 
497
}
 
498
 
 
499
static void *k_str2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
500
{
 
501
        *len = smp->data.str.len;
 
502
        return (void *)smp->data.str.str;
 
503
}
 
504
 
 
505
static void *k_ip2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
506
{
 
507
        if (smp->type == SMP_T_IPV6) {
 
508
                if (!inet_ntop(AF_INET6, &smp->data.ipv6, kdata->buf, *len))
 
509
                        return NULL;
 
510
        }
 
511
        else {
 
512
                if (!inet_ntop(AF_INET, &smp->data.ipv4, kdata->buf, *len))
 
513
                        return NULL;
 
514
        }
 
515
 
 
516
        *len = strlen((const char *)kdata->buf);
 
517
        return (void *)kdata->buf;
 
518
}
 
519
 
 
520
static void *k_bin2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
521
{
 
522
        unsigned char c;
 
523
        int ptr = 0;
 
524
        int max = *len;
 
525
        int size = 0;
 
526
 
 
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];
 
531
        }
 
532
        *len = size;
 
533
        return (void *)kdata->buf;
 
534
}
 
535
 
 
536
static void *k_int2str(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
537
{
 
538
        void *key;
 
539
 
 
540
        key = (void *)ultoa_r(smp->data.uint, kdata->buf, *len);
 
541
        if (!key)
 
542
                return NULL;
 
543
 
 
544
        *len = strlen((const char *)key);
 
545
        return key;
 
546
}
 
547
 
 
548
static void *k_str2ip(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
549
{
 
550
        if (!buf2ip(smp->data.str.str, smp->data.str.len, &kdata->ip))
 
551
                return NULL;
 
552
 
 
553
        return (void *)&kdata->ip.s_addr;
 
554
}
 
555
 
 
556
static void *k_str2ipv6(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
557
{
 
558
        if (!inet_pton(AF_INET6, smp->data.str.str, &kdata->ipv6))
 
559
                return NULL;
 
560
 
 
561
        return (void *)&kdata->ipv6.s6_addr;
 
562
}
 
563
 
 
564
static void *k_str2int(struct sample *smp, union stktable_key_data *kdata, size_t *len)
 
565
{
 
566
        int i;
 
567
 
 
568
        kdata->integer = 0;
 
569
        for (i = 0; i < smp->data.str.len; i++) {
 
570
                uint32_t val = smp->data.str.str[i] - '0';
 
571
 
 
572
                if (val > 9)
 
573
                        break;
 
574
 
 
575
                kdata->integer = kdata->integer * 10 + val;
 
576
        }
 
577
        return (void *)&kdata->integer;
 
578
}
 
579
 
 
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
/*****************************************************************/
 
585
 
 
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 },
 
597
};
 
598
 
 
599
 
 
600
/*
 
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>.
 
605
 */
 
606
struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *l4, void *l7,
 
607
                                        unsigned int opt,
 
608
                                        struct sample_expr *expr)
 
609
{
 
610
        struct sample *smp;
 
611
 
 
612
        smp = sample_process(px, l4, l7, opt, expr, NULL);
 
613
        if (!smp)
 
614
                return NULL;
 
615
 
 
616
        if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
 
617
                return NULL; /* we can only use stable samples */
 
618
 
 
619
        if (!sample_to_key[smp->type][t->type])
 
620
                return NULL;
 
621
 
 
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);
 
624
 
 
625
        if (!static_table_key->key)
 
626
                return NULL;
 
627
 
 
628
        if (static_table_key->key_len == 0)
 
629
                return NULL;
 
630
 
 
631
        if ((static_table_key->key_len < t->key_size) && (t->type != STKTABLE_TYPE_STRING)) {
 
632
                /* need padding with null */
 
633
 
 
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) */
 
636
 
 
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 */
 
640
 
 
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;
 
645
                        }
 
646
                }
 
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 */
 
649
 
 
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;
 
652
                }
 
653
 
 
654
                memset(static_table_key->key + static_table_key->key_len, 0, t->key_size - static_table_key->key_len);
 
655
        }
 
656
 
 
657
        return static_table_key;
 
658
}
 
659
 
 
660
/*
 
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.
 
663
 */
 
664
int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type)
 
665
{
 
666
        int out_type;
 
667
 
 
668
        if (table_type >= STKTABLE_TYPES)
 
669
                return 0;
 
670
 
 
671
        out_type = smp_expr_output_type(expr);
 
672
        if (!sample_to_key[out_type][table_type])
 
673
                return 0;
 
674
 
 
675
        return 1;
 
676
}
 
677
 
 
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 },
 
696
};
 
697
 
 
698
/*
 
699
 * Returns the data type number for the stktable_data_type whose name is <name>,
 
700
 * or <0 if not found.
 
701
 */
 
702
int stktable_get_data_type(char *name)
 
703
{
 
704
        int type;
 
705
 
 
706
        for (type = 0; type < STKTABLE_DATA_TYPES; type++) {
 
707
                if (strcmp(name, stktable_data_types[type].name) == 0)
 
708
                        return type;
 
709
        }
 
710
        return -1;
 
711
}
 
712
 
 
713
/* Returns pointer to proxy containing table <name> or NULL if not found */
 
714
struct proxy *find_stktable(const char *name)
 
715
{
 
716
        struct proxy *px;
 
717
        struct ebpt_node *node;
 
718
 
 
719
        for (node = ebis_lookup(&proxy_by_name, name); node; node = ebpt_next(node)) {
 
720
                px = container_of(node, struct proxy, conf.by_name);
 
721
 
 
722
                if (strcmp(px->id, name) != 0)
 
723
                        break;
 
724
 
 
725
                if (px->table.size)
 
726
                        return px;
 
727
        }
 
728
        return NULL;
 
729
}