MINOR: config: Extract the code of "stick-table" line parsing.

With this patch we move the code responsible of parsing "stick-table"
lines to implement parse_stick_table() function in src/stick-tabble.c
so that to be able to parse "stick-table" elsewhere than in proxy sections.
We have have also added a conf struct to stktable struct to store the filename
and the line in the file the stick-table has been parsed to help in
diagnosing and displaying any configuration issue.
This commit is contained in:
Frdric Lcaille 2019-03-08 14:47:00 +01:00 committed by Willy Tarreau
parent 034c88cf03
commit d456aa4ac2
4 changed files with 207 additions and 156 deletions

View File

@ -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);

View File

@ -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 <file> 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];

View File

@ -25,6 +25,7 @@
#include <proto/protocol.h>
#include <proto/proxy.h>
#include <proto/server.h>
#include <proto/stick_table.h>
/* 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;

View File

@ -15,6 +15,7 @@
#include <errno.h>
#include <common/config.h>
#include <common/cfgparse.h>
#include <common/initcall.h>
#include <common/memory.h>
#include <common/mini-clist.h>
@ -664,6 +665,197 @@ int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *ke
return 1;
}
/*
* Parse a line with <linenum> as number in <file> configuration file to configure the
* stick-table with <t> as address and <id> as ID.
* <peers> 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 <smp> to search into table <t>.
* 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.