diff --git a/include/proto/stick_table.h b/include/proto/stick_table.h index 40bb8ca6c..962c95a1f 100644 --- a/include/proto/stick_table.h +++ b/include/proto/stick_table.h @@ -38,6 +38,8 @@ int stksess_kill(struct stktable *t, struct stksess *ts, int decrefcount); int stktable_init(struct stktable *t); int stktable_parse_type(char **args, int *idx, unsigned long *type, size_t *key_size); +int parse_stick_table(const char *file, int linenum, char **args, + struct stktable *t, char *id, struct peers *peers); struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key); struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts); void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int decrefcount, int expire); diff --git a/include/types/stick_table.h b/include/types/stick_table.h index 28e255fb8..695a75c9a 100644 --- a/include/types/stick_table.h +++ b/include/types/stick_table.h @@ -144,6 +144,13 @@ struct stksess { /* stick table */ struct stktable { char *id; /* table id name */ + struct stktable *next; /* The stick-table may be linked when belonging to + * the same configuration section. + */ + struct { + const char *file; /* The file where the stick-table is declared. */ + int line; /* The line in this the stick-table is declared. */ + } conf; struct eb_root keys; /* head of sticky session tree */ struct eb_root exps; /* head of sticky session expiration tree */ struct eb_root updates; /* head of sticky updates sequence tree */ @@ -175,6 +182,7 @@ struct stktable { unsigned int u; void *p; } data_arg[STKTABLE_DATA_TYPES]; /* optional argument of each data type */ + struct proxy *proxy; /* The proxy this stick-table is attached to, if any.*/ }; extern struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES]; diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index e7cd0663e..c0f4a4669 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -25,6 +25,7 @@ #include #include #include +#include /* Report a warning if a rule is placed after a 'tcp-request session' rule. * Return 1 if the warning has been emitted, otherwise 0. @@ -1710,7 +1711,6 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) LIST_ADDQ(&curproxy->persist_rules, &rule->list); } else if (!strcmp(args[0], "stick-table")) { - int myidx = 1; struct proxy *other; if (curproxy == &defproxy) { @@ -1728,163 +1728,12 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - curproxy->table.id = curproxy->id; - curproxy->table.type = (unsigned int)-1; - while (*args[myidx]) { - const char *err; - - if (strcmp(args[myidx], "size") == 0) { - myidx++; - if (!*(args[myidx])) { - ha_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))) { - ha_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; - } - myidx++; - } - else if (strcmp(args[myidx], "peers") == 0) { - myidx++; - if (!*(args[myidx])) { - ha_alert("parsing [%s:%d] : stick-table: missing argument after '%s'.\n", - file, linenum, args[myidx-1]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - curproxy->table.peers.name = strdup(args[myidx++]); - } - else if (strcmp(args[myidx], "expire") == 0) { - myidx++; - if (!*(args[myidx])) { - ha_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) { - ha_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; - } - if (val > INT_MAX) { - ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n", - file, linenum, val); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - curproxy->table.expire = val; - myidx++; - } - else if (strcmp(args[myidx], "nopurge") == 0) { - curproxy->table.nopurge = 1; - myidx++; - } - else if (strcmp(args[myidx], "type") == 0) { - myidx++; - if (stktable_parse_type(args, &myidx, &curproxy->table.type, &curproxy->table.key_size) != 0) { - ha_alert("parsing [%s:%d] : stick-table: unknown type '%s'.\n", - file, linenum, args[myidx]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - /* myidx already points to next arg */ - } - else if (strcmp(args[myidx], "store") == 0) { - int type, err; - char *cw, *nw, *sa; - - myidx++; - nw = args[myidx]; - while (*nw) { - /* the "store" keyword supports a comma-separated list */ - cw = nw; - sa = NULL; /* store arg */ - while (*nw && *nw != ',') { - if (*nw == '(') { - *nw = 0; - sa = ++nw; - while (*nw != ')') { - if (!*nw) { - ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n", - file, linenum, args[0], cw); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - nw++; - } - *nw = '\0'; - } - nw++; - } - if (*nw) - *nw++ = '\0'; - type = stktable_get_data_type(cw); - if (type < 0) { - ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n", - file, linenum, args[0], cw); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - err = stktable_alloc_data_type(&curproxy->table, type, sa); - switch (err) { - case PE_NONE: break; - case PE_EXIST: - ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n", - file, linenum, args[0], cw); - err_code |= ERR_WARN; - break; - - case PE_ARG_MISSING: - ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n", - file, linenum, args[0], cw); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - - case PE_ARG_NOT_USED: - ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n", - file, linenum, args[0], cw); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - - default: - ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n", - file, linenum, args[0], cw); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - } - myidx++; - } - else { - ha_alert("parsing [%s:%d] : stick-table: unknown argument '%s'.\n", - file, linenum, args[myidx]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - } - - if (!curproxy->table.size) { - ha_alert("parsing [%s:%d] : stick-table: missing size.\n", - file, linenum); - err_code |= ERR_ALERT | ERR_FATAL; + err_code |= parse_stick_table(file, linenum, args, &curproxy->table, curproxy->id, NULL); + if (err_code & ERR_FATAL) goto out; - } - if (curproxy->table.type == (unsigned int)-1) { - ha_alert("parsing [%s:%d] : stick-table: missing type.\n", - file, linenum); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } + /* Store the proxy in the stick-table. */ + curproxy->table->proxy = curproxy; } else if (!strcmp(args[0], "stick")) { struct sticking_rule *rule; diff --git a/src/stick_table.c b/src/stick_table.c index e24ef65b6..d8053dc04 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -664,6 +665,197 @@ int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *ke return 1; } +/* + * Parse a line with as number in configuration file to configure the + * stick-table with as address and as ID. + * provides the "peers" section pointer only if this function is called from a "peers" section. + * Return an error status with ERR_* flags set if required, 0 if no error was encountered. + */ +int parse_stick_table(const char *file, int linenum, char **args, + struct stktable *t, char *id, struct peers *peers) +{ + int err_code = 0; + int idx = 1; + unsigned int val; + + if (!id || !*id) { + ha_alert("parsing [%s:%d] : %s: ID not provided.\n", file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + + /* Store the "peers" section if this function is called from a "peers" section. */ + if (peers) { + t->peers.p = peers; + idx++; + } + + t->id = id; + t->type = (unsigned int)-1; + t->conf.file = file; + t->conf.line = linenum; + + while (*args[idx]) { + const char *err; + + if (strcmp(args[idx], "size") == 0) { + idx++; + if (!*(args[idx])) { + ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n", + file, linenum, args[0], args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + if ((err = parse_size_err(args[idx], &t->size))) { + ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n", + file, linenum, args[0], *err, args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + idx++; + } + /* This argument does not exit in "peers" section. */ + else if (!peers && strcmp(args[idx], "peers") == 0) { + idx++; + if (!*(args[idx])) { + ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n", + file, linenum, args[0], args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + t->peers.name = strdup(args[idx++]); + } + else if (strcmp(args[idx], "expire") == 0) { + idx++; + if (!*(args[idx])) { + ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n", + file, linenum, args[0], args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + err = parse_time_err(args[idx], &val, TIME_UNIT_MS); + if (err) { + ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n", + file, linenum, args[0], *err, args[idx-1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + if (val > INT_MAX) { + ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n", + file, linenum, val); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + t->expire = val; + idx++; + } + else if (strcmp(args[idx], "nopurge") == 0) { + t->nopurge = 1; + idx++; + } + else if (strcmp(args[idx], "type") == 0) { + idx++; + if (stktable_parse_type(args, &idx, &t->type, &t->key_size) != 0) { + ha_alert("parsing [%s:%d] : %s: unknown type '%s'.\n", + file, linenum, args[0], args[idx]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + /* idx already points to next arg */ + } + else if (strcmp(args[idx], "store") == 0) { + int type, err; + char *cw, *nw, *sa; + + idx++; + nw = args[idx]; + while (*nw) { + /* the "store" keyword supports a comma-separated list */ + cw = nw; + sa = NULL; /* store arg */ + while (*nw && *nw != ',') { + if (*nw == '(') { + *nw = 0; + sa = ++nw; + while (*nw != ')') { + if (!*nw) { + ha_alert("parsing [%s:%d] : %s: missing closing parenthesis after store option '%s'.\n", + file, linenum, args[0], cw); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + nw++; + } + *nw = '\0'; + } + nw++; + } + if (*nw) + *nw++ = '\0'; + type = stktable_get_data_type(cw); + if (type < 0) { + ha_alert("parsing [%s:%d] : %s: unknown store option '%s'.\n", + file, linenum, args[0], cw); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + err = stktable_alloc_data_type(t, type, sa); + switch (err) { + case PE_NONE: break; + case PE_EXIST: + ha_warning("parsing [%s:%d]: %s: store option '%s' already enabled, ignored.\n", + file, linenum, args[0], cw); + err_code |= ERR_WARN; + break; + + case PE_ARG_MISSING: + ha_alert("parsing [%s:%d] : %s: missing argument to store option '%s'.\n", + file, linenum, args[0], cw); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + + case PE_ARG_NOT_USED: + ha_alert("parsing [%s:%d] : %s: unexpected argument to store option '%s'.\n", + file, linenum, args[0], cw); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + + default: + ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n", + file, linenum, args[0], cw); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + idx++; + } + else { + ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n", + file, linenum, args[0], args[idx]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + + if (!t->size) { + ha_alert("parsing [%s:%d] : %s: missing size.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + if (t->type == (unsigned int)-1) { + ha_alert("parsing [%s:%d] : %s: missing type.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + out: + return err_code; +} + /* Prepares a stktable_key from a sample to search into table . * Note that the sample *is* modified and that the returned key may point * to it, so the sample must not be modified afterwards before the lookup.