mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-21 13:16:57 +00:00
[MEDIUM] Add stick table configuration and init.
This commit is contained in:
parent
5d16eda210
commit
b982a3d23a
@ -36,6 +36,7 @@
|
||||
#include <eb32tree.h>
|
||||
|
||||
#include <types/acl.h>
|
||||
#include <types/pattern.h>
|
||||
#include <types/backend.h>
|
||||
#include <types/buffers.h>
|
||||
#include <types/counters.h>
|
||||
@ -45,6 +46,7 @@
|
||||
#include <types/protocols.h>
|
||||
#include <types/session.h>
|
||||
#include <types/server.h>
|
||||
#include <types/stick_table.h>
|
||||
|
||||
/* values for proxy->state */
|
||||
#define PR_STNEW 0
|
||||
@ -133,6 +135,12 @@
|
||||
#define PR_O2_AS_M_ANY 0x00010000 /* mask covering all PR_O2_AS_M_* values */
|
||||
|
||||
#define PR_O2_MYSQL_CHK 0x00020000 /* use MYSQL check for server health */
|
||||
/* end of proxy->options2 */
|
||||
|
||||
/* bits for sticking rules */
|
||||
#define STK_IS_MATCH 0x00000001 /* match on request fetch */
|
||||
#define STK_IS_STORE 0x00000002 /* store on request fetch */
|
||||
#define STK_ON_RSP 0x00000004 /* store on response fetch */
|
||||
|
||||
struct error_snapshot {
|
||||
struct timeval when; /* date of this event, (tv_sec == 0) means "never" */
|
||||
@ -163,6 +171,8 @@ struct proxy {
|
||||
struct list block_cond; /* early blocking conditions (chained) */
|
||||
struct list redirect_rules; /* content redirecting rules (chained) */
|
||||
struct list switching_rules; /* content switching rules (chained) */
|
||||
struct list sticking_rules; /* content sticking rules (chained) */
|
||||
struct list storersp_rules; /* content store response rules (chained) */
|
||||
struct { /* TCP request processing */
|
||||
unsigned int inspect_delay; /* inspection delay */
|
||||
struct list inspect_rules; /* inspection rules */
|
||||
@ -253,6 +263,9 @@ struct proxy {
|
||||
struct pool_head *hdr_idx_pool; /* pools of pre-allocated int* used for headers indexing */
|
||||
struct list req_add, rsp_add; /* headers to be added */
|
||||
struct pxcounters counters; /* statistics counters */
|
||||
|
||||
struct stktable table; /* table for storing sticking sessions */
|
||||
|
||||
int grace; /* grace time after stop request */
|
||||
char *check_req; /* HTTP or SSL request to use for PR_O_HTTP_CHK|PR_O_SSL3_CHK */
|
||||
int check_len; /* Length of the HTTP or SSL3 request */
|
||||
@ -284,6 +297,18 @@ struct switching_rule {
|
||||
} be;
|
||||
};
|
||||
|
||||
struct sticking_rule {
|
||||
struct list list; /* list linked to from the proxy */
|
||||
struct acl_cond *cond; /* acl condition to meet */
|
||||
struct pattern_expr *expr; /* fetch expr to fetch key */
|
||||
int flags; /* STK_* */
|
||||
union {
|
||||
struct stktable *t; /* target table */
|
||||
char *name; /* target table name during config parsing */
|
||||
} table;
|
||||
};
|
||||
|
||||
|
||||
struct redirect_rule {
|
||||
struct list list; /* list linked to from the proxy */
|
||||
struct acl_cond *cond; /* acl condition to meet */
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <types/server.h>
|
||||
#include <types/stream_interface.h>
|
||||
#include <types/task.h>
|
||||
#include <types/stick_table.h>
|
||||
|
||||
|
||||
/* various session flags, bits values 0x01 to 0x100 (shift 0) */
|
||||
@ -174,6 +175,14 @@ struct session {
|
||||
struct server *prev_srv; /* the server the was running on, after a redispatch, otherwise NULL */
|
||||
struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
|
||||
struct http_txn txn; /* current HTTP transaction being processed. Should become a list. */
|
||||
|
||||
struct {
|
||||
struct stksess *ts;
|
||||
struct stktable *table;
|
||||
int flags;
|
||||
} store[8]; /* tracked stickiness values to store */
|
||||
int store_count;
|
||||
|
||||
struct {
|
||||
int logwait; /* log fields waiting to be collected : LW_* */
|
||||
struct timeval accept_date; /* date of the accept() in user date */
|
||||
|
267
src/cfgparse.c
267
src/cfgparse.c
@ -47,6 +47,7 @@
|
||||
#include <proto/lb_fwrr.h>
|
||||
#include <proto/lb_map.h>
|
||||
#include <proto/log.h>
|
||||
#include <proto/pattern.h>
|
||||
#include <proto/port_range.h>
|
||||
#include <proto/protocols.h>
|
||||
#include <proto/proto_tcp.h>
|
||||
@ -55,6 +56,7 @@
|
||||
#include <proto/server.h>
|
||||
#include <proto/session.h>
|
||||
#include <proto/task.h>
|
||||
#include <proto/stick_table.h>
|
||||
|
||||
|
||||
/* This is the SSLv3 CLIENT HELLO packet used in conjunction with the
|
||||
@ -795,6 +797,8 @@ static void init_new_proxy(struct proxy *p)
|
||||
LIST_INIT(&p->redirect_rules);
|
||||
LIST_INIT(&p->mon_fail_cond);
|
||||
LIST_INIT(&p->switching_rules);
|
||||
LIST_INIT(&p->sticking_rules);
|
||||
LIST_INIT(&p->storersp_rules);
|
||||
LIST_INIT(&p->tcp_req.inspect_rules);
|
||||
LIST_INIT(&p->req_add);
|
||||
LIST_INIT(&p->rsp_add);
|
||||
@ -1541,7 +1545,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
if (!strncmp(args[1], "rdp-cookie", 10)) {
|
||||
curproxy->options2 |= PR_O2_RDPC_PRST;
|
||||
|
||||
if (*(args[1] + 10 ) == '(') { /* cookie name */
|
||||
if (*(args[1] + 10) == '(') { /* cookie name */
|
||||
const char *beg, *end;
|
||||
|
||||
beg = args[1] + 11;
|
||||
@ -1558,7 +1562,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
curproxy->rdp_cookie_name = my_strndup(beg, end - beg);
|
||||
curproxy->rdp_cookie_len = end-beg;
|
||||
}
|
||||
else if (*(args[1] + 10 ) == '\0') { /* default cookie name 'msts' */
|
||||
else if (*(args[1] + 10) == '\0') { /* default cookie name 'msts' */
|
||||
free(curproxy->rdp_cookie_name);
|
||||
curproxy->rdp_cookie_name = strdup("msts");
|
||||
curproxy->rdp_cookie_len = strlen(curproxy->rdp_cookie_name);
|
||||
@ -1982,6 +1986,199 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
LIST_INIT(&rule->list);
|
||||
LIST_ADDQ(&curproxy->switching_rules, &rule->list);
|
||||
}
|
||||
else if (!strcmp(args[0], "stick-table")) {
|
||||
int myidx = 1;
|
||||
|
||||
curproxy->table.type = (unsigned int)-1;
|
||||
while (*args[myidx]) {
|
||||
const char *err;
|
||||
|
||||
if (strcmp(args[myidx], "size") == 0) {
|
||||
myidx++;
|
||||
if (!*(args[myidx])) {
|
||||
Alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
|
||||
file, linenum, args[myidx-1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
if ((err = parse_size_err(args[myidx], &curproxy->table.size))) {
|
||||
Alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
|
||||
file, linenum, *err, args[myidx-1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (strcmp(args[myidx], "expire") == 0) {
|
||||
myidx++;
|
||||
if (!*(args[myidx])) {
|
||||
Alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n",
|
||||
file, linenum, args[myidx-1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
err = parse_time_err(args[myidx], &val, TIME_UNIT_MS);
|
||||
if (err) {
|
||||
Alert("parsing [%s:%d] : stick-table: unexpected character '%c' in argument of '%s'.\n",
|
||||
file, linenum, *err, args[myidx-1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
curproxy->table.expire = val;
|
||||
}
|
||||
else if (strcmp(args[myidx], "nopurge") == 0) {
|
||||
curproxy->table.nopurge = 1;
|
||||
}
|
||||
else if (strcmp(args[myidx], "type") == 0) {
|
||||
myidx++;
|
||||
if (stktable_parse_type(args, &myidx, &curproxy->table.type, &curproxy->table.key_size) != 0) {
|
||||
Alert("parsing [%s:%d] : stick-table: unknown type '%s'.\n",
|
||||
file, linenum, args[myidx]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
myidx++;
|
||||
}
|
||||
|
||||
if (!curproxy->table.size) {
|
||||
Alert("parsing [%s:%d] : stick-table: missing size.\n",
|
||||
file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (curproxy->table.type == (unsigned int)-1) {
|
||||
Alert("parsing [%s:%d] : stick-table: missing type.\n",
|
||||
file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(args[0], "stick")) {
|
||||
int pol = ACL_COND_NONE;
|
||||
struct acl_cond *cond = NULL;
|
||||
struct sticking_rule *rule;
|
||||
struct pattern_expr *expr;
|
||||
int myidx = 0;
|
||||
const char *name = NULL;
|
||||
int flags;
|
||||
|
||||
if (curproxy == &defproxy) {
|
||||
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
|
||||
err_code |= ERR_WARN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
myidx++;
|
||||
if ((strcmp(args[myidx], "store") == 0) ||
|
||||
(strcmp(args[myidx], "store-request") == 0)) {
|
||||
myidx++;
|
||||
flags = STK_IS_STORE;
|
||||
}
|
||||
else if (strcmp(args[myidx], "store-response") == 0) {
|
||||
myidx++;
|
||||
flags = STK_IS_STORE | STK_ON_RSP;
|
||||
}
|
||||
else if (strcmp(args[myidx], "match") == 0) {
|
||||
myidx++;
|
||||
flags = STK_IS_MATCH;
|
||||
}
|
||||
else if (strcmp(args[myidx], "on") == 0) {
|
||||
myidx++;
|
||||
flags = STK_IS_MATCH | STK_IS_STORE;
|
||||
}
|
||||
else {
|
||||
Alert("parsing [%s:%d] : '%s' expects 'on', 'match', or 'store'.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*(args[myidx]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects a fetch method.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
expr = pattern_parse_expr(args, &myidx);
|
||||
if (!expr) {
|
||||
Alert("parsing [%s:%d] : '%s': unknown fetch method '%s'.\n", file, linenum, args[0], args[myidx]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & STK_ON_RSP) {
|
||||
if (!(expr->fetch->dir & PATTERN_FETCH_RTR)) {
|
||||
Alert("parsing [%s:%d] : '%s': fetch method '%s' can not be used on response.\n",
|
||||
file, linenum, args[0], expr->fetch->kw);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (!(expr->fetch->dir & PATTERN_FETCH_REQ)) {
|
||||
Alert("parsing [%s:%d] : '%s': fetch method '%s' can not be used on request.\n",
|
||||
file, linenum, args[0], expr->fetch->kw);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(args[myidx], "table") == 0) {
|
||||
myidx++;
|
||||
name = args[myidx++];
|
||||
}
|
||||
|
||||
if (*(args[myidx]) == 0)
|
||||
pol = ACL_COND_NONE;
|
||||
else if (strcmp(args[myidx], "if") == 0)
|
||||
pol = ACL_COND_IF;
|
||||
else if (strcmp(args[myidx], "unless") == 0)
|
||||
pol = ACL_COND_UNLESS;
|
||||
else {
|
||||
Alert("parsing [%s:%d] : '%s': unknown keyword '%s'.\n",
|
||||
file, linenum, args[0], args[myidx]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pol != ACL_COND_NONE) {
|
||||
myidx++;
|
||||
if ((cond = parse_acl_cond((const char **)args + myidx, &curproxy->acl, pol)) == NULL) {
|
||||
Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition.\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cond->file = file;
|
||||
cond->line = linenum;
|
||||
curproxy->acl_requires |= cond->requires;
|
||||
if (cond->requires & ACL_USE_RTR_ANY) {
|
||||
struct acl *acl;
|
||||
const char *name;
|
||||
|
||||
acl = cond_find_require(cond, ACL_USE_RTR_ANY);
|
||||
name = acl ? acl->name : "(unknown)";
|
||||
Warning("parsing [%s:%d] : '%s' : acl '%s' involves some response-only criteria which will be ignored.\n",
|
||||
file, linenum, args[0], name);
|
||||
err_code |= ERR_WARN;
|
||||
}
|
||||
}
|
||||
rule = (struct sticking_rule *)calloc(1, sizeof(*rule));
|
||||
rule->cond = cond;
|
||||
rule->expr = expr;
|
||||
rule->flags = flags;
|
||||
rule->table.name = name ? strdup(name) : NULL;
|
||||
LIST_INIT(&rule->list);
|
||||
if (flags & STK_ON_RSP)
|
||||
LIST_ADDQ(&curproxy->storersp_rules, &rule->list);
|
||||
else
|
||||
LIST_ADDQ(&curproxy->sticking_rules, &rule->list);
|
||||
}
|
||||
else if (!strcmp(args[0], "stats")) {
|
||||
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
|
||||
err_code |= ERR_WARN;
|
||||
@ -4085,7 +4282,7 @@ int readcfgfile(const char *file)
|
||||
skip = 1;
|
||||
}
|
||||
else if (line[1] == 'x') {
|
||||
if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
|
||||
if ((line + 3 < end) && ishex(line[2]) && ishex(line[3])) {
|
||||
unsigned char hex1, hex2;
|
||||
hex1 = toupper(line[2]) - '0';
|
||||
hex2 = toupper(line[3]) - '0';
|
||||
@ -4247,6 +4444,7 @@ int check_config_validity()
|
||||
|
||||
while (curproxy != NULL) {
|
||||
struct switching_rule *rule;
|
||||
struct sticking_rule *mrule;
|
||||
struct listener *listener;
|
||||
unsigned int next_id;
|
||||
|
||||
@ -4419,6 +4617,66 @@ int check_config_validity()
|
||||
}
|
||||
}
|
||||
|
||||
/* find the target table for 'stick' rules */
|
||||
list_for_each_entry(mrule, &curproxy->sticking_rules, list) {
|
||||
struct proxy *target;
|
||||
|
||||
if (mrule->table.name)
|
||||
target = findproxy(mrule->table.name, PR_CAP_BE);
|
||||
else
|
||||
target = curproxy;
|
||||
|
||||
if (!target) {
|
||||
Alert("Proxy '%s': unable to find stick-table '%s'.\n",
|
||||
curproxy->id, mrule->table.name);
|
||||
cfgerr++;
|
||||
}
|
||||
else if (target->table.size == 0) {
|
||||
Alert("Proxy '%s': stick-table '%s' used but not configured.\n",
|
||||
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
|
||||
cfgerr++;
|
||||
}
|
||||
else if (pattern_notusable_key(mrule->expr, target->table.type)) {
|
||||
Alert("Proxy '%s': type of pattern not usable with type of stick-table '%s'.\n",
|
||||
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
|
||||
cfgerr++;
|
||||
}
|
||||
else {
|
||||
free((void *)mrule->table.name);
|
||||
mrule->table.t = &(target->table);
|
||||
}
|
||||
}
|
||||
|
||||
/* find the target table for 'store response' rules */
|
||||
list_for_each_entry(mrule, &curproxy->storersp_rules, list) {
|
||||
struct proxy *target;
|
||||
|
||||
if (mrule->table.name)
|
||||
target = findproxy(mrule->table.name, PR_CAP_BE);
|
||||
else
|
||||
target = curproxy;
|
||||
|
||||
if (!target) {
|
||||
Alert("Proxy '%s': unable to find store table '%s'.\n",
|
||||
curproxy->id, mrule->table.name);
|
||||
cfgerr++;
|
||||
}
|
||||
else if (target->table.size == 0) {
|
||||
Alert("Proxy '%s': stick-table '%s' used but not configured.\n",
|
||||
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
|
||||
cfgerr++;
|
||||
}
|
||||
else if (pattern_notusable_key(mrule->expr, target->table.type)) {
|
||||
Alert("Proxy '%s': type of pattern not usable with type of stick-table '%s'.\n",
|
||||
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
|
||||
cfgerr++;
|
||||
}
|
||||
else {
|
||||
free((void *)mrule->table.name);
|
||||
mrule->table.t = &(target->table);
|
||||
}
|
||||
}
|
||||
|
||||
if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
|
||||
(((curproxy->cap & PR_CAP_FE) && !curproxy->timeout.client) ||
|
||||
((curproxy->cap & PR_CAP_BE) && (curproxy->srv) &&
|
||||
@ -4679,6 +4937,9 @@ int check_config_validity()
|
||||
curproxy->be_rsp_ana |= AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_BE;
|
||||
}
|
||||
|
||||
/* init table on backend capabilities proxy */
|
||||
stktable_init(&curproxy->table);
|
||||
|
||||
/* If the backend does requires RDP cookie persistence, we have to
|
||||
* enable the corresponding analyser.
|
||||
*/
|
||||
|
@ -225,6 +225,9 @@ int event_accept(int fd) {
|
||||
s->pend_pos = NULL;
|
||||
s->conn_retries = s->be->conn_retries;
|
||||
|
||||
/* init store persistence */
|
||||
s->store_count = 0;
|
||||
|
||||
/* FIXME: the logs are horribly complicated now, because they are
|
||||
* defined in <p>, <p>, and later <be> and <be>.
|
||||
*/
|
||||
|
@ -6415,6 +6415,9 @@ void http_reset_txn(struct session *s)
|
||||
s->req->analysers = s->listener->analysers;
|
||||
s->logs.logwait = s->fe->to_log;
|
||||
s->srv = s->prev_srv = s->srv_conn = NULL;
|
||||
/* re-init store persistence */
|
||||
s->store_count = 0;
|
||||
|
||||
s->pend_pos = NULL;
|
||||
s->conn_retries = s->be->conn_retries;
|
||||
|
||||
|
@ -476,6 +476,8 @@ int uxst_event_accept(int fd) {
|
||||
s->srv = s->prev_srv = s->srv_conn = NULL;
|
||||
s->pend_pos = NULL;
|
||||
|
||||
s->store_count = 0;
|
||||
|
||||
memset(&s->logs, 0, sizeof(s->logs));
|
||||
memset(&s->txn, 0, sizeof(s->txn));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user