--- Hello haproxy team.
This patch covers issue https://github.com/haproxy/haproxy/issues/3221. And also following https://www.mail-archive.com/[email protected]/msg46391.html. I've fixed bug that -dKall doesn't prints out "peers" section by registering all sub keywords of "peers" and set new detect logic with list_for_each_entry(). Since there are several branches and complex logics, I've created dedicate file with cfg_parse_peers() function and new register logics in src/cfgparse-peers.c. Also changed Makefile to link cfgparse-peers.o in build time. Since there are a little bit of difference between cfg_keyword and peers_keyword structure, I wrote down a new list_for_each_entry() logic for cfg_keyword parsing in parallel in cfgparse-peers.c. Regards, Hyeonggeun. --- Makefile | 2 +- src/cfgparse-peers.c | 391 +++++++++++++++++++++------- src/cfgparse.c | 608 ------------------------------------------- 3 files changed, 293 insertions(+), 708 deletions(-) diff --git a/Makefile b/Makefile index c4d1d0b72..41f99f3cb 100644 --- a/Makefile +++ b/Makefile @@ -964,7 +964,7 @@ endif OBJS += src/mux_h2.o src/mux_h1.o src/mux_fcgi.o src/log.o \ src/server.o src/stream.o src/tcpcheck.o src/http_ana.o \ src/stick_table.o src/tools.o src/mux_spop.o src/sample.o \ - src/activity.o src/cfgparse.o src/peers.o src/cli.o \ + src/activity.o src/cfgparse.o src/cfgparse-peers.o src/peers.o src/cli.o \ src/backend.o src/connection.o src/resolvers.o src/proxy.o \ src/cache.o src/stconn.o src/http_htx.o src/debug.o \ src/check.o src/stats-html.o src/haproxy.o src/listener.o \ diff --git a/src/cfgparse-peers.c b/src/cfgparse-peers.c index 2307f1c43..0001ae124 100644 --- a/src/cfgparse-peers.c +++ b/src/cfgparse-peers.c @@ -75,14 +75,11 @@ #include <haproxy/uri_auth.h> /* Helper functions from cfgparse.c */ -extern int init_peers_frontend(const char *file, int linenum, const char *id, struct peers *peers); -extern struct bind_conf *bind_conf_uniq_alloc(struct proxy *p, const char *file, int line, const char *arg, struct xprt_ops *xprt); -extern struct peer *cfg_peers_add_peer(struct peers *peers, const char *file, int linenum, const char *id, int local); extern int parse_logger(char **args, struct list *logs, int reuse, const char *file, int linenum, char **err); extern int alertif_too_many_args(int last, const char *file, int linenum, char **args, int *err_code); -extern int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy, int parse_flags); +extern int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, const struct proxy *defproxy, int parse_flags); extern int parse_stick_table(const char *file, int linenum, char **args, struct stktable *tab, char *id, char *name, struct peers *peers); -extern struct cf_section *cursection; +extern char *cursection; extern struct cfg_kw_list cfg_keywords; @@ -99,34 +96,239 @@ static int err_code = 0; /* 'err' was a const char * pointer to error messages or return of invalid_char */ static const char *err_msg = NULL; -/* Functions for sub-keywords */ +/* Allocate and initialize the frontend of a "peers" section found in + * file <file> at line <linenum> with <id> as ID. + * Return 0 if succeeded, -1 if not. + * Note that this function may be called from "default-server" + * or "peer" lines. + */ +static int init_peers_frontend(const char *file, int linenum, + const char *id, struct peers *peers) +{ + struct proxy *p; + char *errmsg = NULL; + + if (peers->peers_fe) { + p = peers->peers_fe; + goto out; + } + + p = alloc_new_proxy(NULL, PR_CAP_FE | PR_CAP_BE, &errmsg); + if (!p) { + ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); + ha_free(&errmsg); + return -1; + } + + peers_setup_frontend(p); + p->parent = peers; + /* Finally store this frontend. */ + peers->peers_fe = p; + + out: + if (id && !p->id) + p->id = strdup(id); + drop_file_name(&p->conf.file); + p->conf.args.file = p->conf.file = copy_file_name(file); + if (linenum != -1) + p->conf.args.line = p->conf.line = linenum; + + return 0; +} + +/* Only change ->file, ->line and ->arg struct bind_conf member values + * if already present. + */ +static struct bind_conf *bind_conf_uniq_alloc(struct proxy *p, + const char *file, int line, + const char *arg, struct xprt_ops *xprt) +{ + struct bind_conf *bind_conf; + + if (!LIST_ISEMPTY(&p->conf.bind)) { + bind_conf = LIST_ELEM((&p->conf.bind)->n, typeof(bind_conf), by_fe); + /* + * We keep bind_conf->file and bind_conf->line unchanged + * to make them available for error messages + */ + if (arg) { + ha_free(&bind_conf->arg); + bind_conf->arg = strdup(arg); + } + } + else { + bind_conf = bind_conf_alloc(p, file, line, arg, xprt); + } + + return bind_conf; +} + +/* + * Allocate a new struct peer parsed at line <linenum> in file <file> + * to be added to <peers>. + * Returns the new allocated structure if succeeded, NULL if not. + */ +static struct peer *cfg_peers_add_peer(struct peers *peers, + const char *file, int linenum, + const char *id, int local) +{ + struct peer *p; + + p = calloc(1, sizeof *p); + if (!p) { + ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); + return NULL; + } + + /* the peers are linked backwards first */ + peers->count++; + p->peers = peers; + p->next = peers->remote; + peers->remote = p; + p->conf.file = strdup(file); + p->conf.line = linenum; + p->last_change = ns_to_sec(now_ns); + HA_SPIN_INIT(&p->lock); + if (id) + p->id = strdup(id); + if (local) { + p->local = 1; + peers->local = p; + } + + return p; +} + +int cfg_parse_peers_bind_default_bind(char **args, int section_type, struct proxy *curproxy, const struct proxy *defproxy, const char *file, int linenum, char **err) +{ + int cur_arg; + int ret; + + cur_arg = 1; + + if (init_peers_frontend(file, linenum, NULL, curpeers) != 0) { + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + + bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, + args[1], xprt_get(XPRT_RAW)); + if (!bind_conf) { + ha_alert("parsing [%s:%d] : '%s %s' : cannot allocate memory.\n", file, linenum, args[0], args[1]); + err_code |= ERR_FATAL; + goto out; + } + + bind_conf->maxaccept = 1; + bind_conf->accept = session_accept_fd; + bind_conf->options |= BC_O_UNLIMITED; /* don't make the peers subject to global limits */ + + if (*args[0] == 'b') { + struct listener *l; + + if (peer_line) { + ha_alert("parsing [%s:%d] : mixing \"peer\" and \"bind\" line is forbidden\n", file, linenum); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + if (!LIST_ISEMPTY(&bind_conf->listeners)) { + ha_alert("parsing [%s:%d] : One listener per \"peers\" section is authorized but another is already configured at [%s:%d].\n", file, linenum, bind_conf->file, bind_conf->line); + err_code |= ERR_FATAL; + } + + if (!str2listener(args[1], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { + if (errmsg) { + indent_msg(&errmsg, 2); + ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); + } + else + ha_alert("parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s.\n", + file, linenum, args[0], args[1], args[1]); + err_code |= ERR_FATAL; + goto out; + } + + /* Only one listener supported. Compare first listener + * against the last one. It must be the same one. + */ + if (bind_conf->listeners.n != bind_conf->listeners.p) { + ha_alert("parsing [%s:%d] : Only one listener per \"peers\" section is authorized. Multiple listening addresses or port range are not supported.\n", file, linenum); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + /* + * Newly allocated listener is at the end of the list + */ + l = LIST_ELEM(bind_conf->listeners.p, typeof(l), by_bind); + bind_addr = &l->rx.addr; + + global.maxsock++; /* for the listening socket */ + + bind_line = 1; + if (cfg_peers->local) { + /* Local peer already defined using "server" line has no + * address yet, we should update its server's addr:port + * settings + */ + newpeer = cfg_peers->local; + BUG_ON(!newpeer->srv); + newpeer->srv->addr = *bind_addr; + newpeer->srv->svc_port = get_host_port(bind_addr); + } + else { + /* This peer is local. + * Note that we do not set the peer ID. This latter is initialized + * when parsing "peer" or "server" line. + */ + newpeer = cfg_peers_add_peer(curpeers, file, linenum, NULL, 1); + if (!newpeer) { + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + } + cur_arg++; + } + + ret = bind_parse_args_list(bind_conf, args, cur_arg, cursection, file, linenum); + err_code |= ret; + if (ret != 0) + goto out; + +out: + ha_free(&errmsg); + return err_code; +} + -int parse_peers_log(const char *file, int linenum, char **args, int kwm) { +int cfg_parse_peers_log(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int linenum, char **err) { if (init_peers_frontend(file, linenum, NULL, curpeers) != 0) { err_code |= ERR_ALERT | ERR_ABORT; - return 1; + goto out; } - if (!parse_logger(args, &curpeers->peers_fe->loggers, (kwm == KWM_NO), file, linenum, &errmsg)) { + if (!parse_logger(args, &curpeers->peers_fe->loggers, (strcmp(args[0], "no") == 0), file, linenum, &errmsg)) { ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } - return 0; +out: + ha_free(&errmsg); + return err_code; } -int parse_peers_section(const char *file, int linenum, char **args) { +int cfg_parse_peers_peers(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int linenum, char **err) { /* Initialize these static variables when entering a new "peers" section*/ bind_line = peer_line = 0; bind_addr = NULL; if (!*args[1]) { ha_alert("parsing [%s:%d] : missing name for peers section.\n", file, linenum); err_code |= ERR_ALERT | ERR_ABORT; - return 1; + goto out; } if (alertif_too_many_args(1, file, linenum, args, &err_code)) { err_code |= ERR_ABORT; - return 1; + goto out; } err_msg = invalid_char(args[1]); @@ -134,7 +336,7 @@ int parse_peers_section(const char *file, int linenum, char **args) { ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n", file, linenum, *err_msg, args[0], args[1]); err_code |= ERR_ALERT | ERR_ABORT; - return 1; + goto out; } for (curpeers = cfg_peers; curpeers != NULL; curpeers = curpeers->next) { @@ -148,7 +350,7 @@ int parse_peers_section(const char *file, int linenum, char **args) { if ((curpeers = calloc(1, sizeof(*curpeers))) == NULL) { ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); err_code |= ERR_ALERT | ERR_ABORT; - return 1; + goto out; } curpeers->next = cfg_peers; @@ -158,10 +360,13 @@ int parse_peers_section(const char *file, int linenum, char **args) { curpeers->last_change = ns_to_sec(now_ns); curpeers->id = strdup(args[1]); curpeers->disabled = 0; - return 0; + +out: + ha_free(&errmsg); + return err_code; } -int parse_peers_peer_server(const char *file, int linenum, char **args) { +int cfg_parse_peers_peer_server(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int linenum, char **err) { struct server *prev_srv; int local_peer, peer; int parse_addr = 0; @@ -173,7 +378,7 @@ int parse_peers_peer_server(const char *file, int linenum, char **args) { if (bind_line) { ha_alert("parsing [%s:%d] : mixing \"peer\" and \"bind\" line is forbidden\n", file, linenum); err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } peer_line = 1; } @@ -187,12 +392,12 @@ int parse_peers_peer_server(const char *file, int linenum, char **args) { file, linenum, args[0], args[1], curpeers->peers_fe->conf.file, curpeers->peers_fe->conf.line, cfg_peers->local->id); err_code |= ERR_FATAL; - return 1; + goto out; } newpeer = cfg_peers_add_peer(curpeers, file, linenum, args[1], local_peer); if (!newpeer) { err_code |= ERR_ALERT | ERR_ABORT; - return 1; + goto out; } } @@ -201,7 +406,7 @@ int parse_peers_peer_server(const char *file, int linenum, char **args) { newpeer->local ? newpeer->id : NULL, curpeers) != 0) { err_code |= ERR_ALERT | ERR_ABORT; - return 1; + goto out; } parse_addr = (peer || !local_peer) ? SRV_PARSE_PARSE_ADDR : 0; @@ -222,13 +427,13 @@ int parse_peers_peer_server(const char *file, int linenum, char **args) { p = curpeers->remote; curpeers->remote = curpeers->remote->next; - free(p->id); - free(p); + ha_free(&p->id); + ha_free(&p); if (local_peer) { curpeers->local = NULL; ha_free(&curpeers->peers_fe->id); } - return 0; // Handled error condition + goto out; // Handled error condition } if (!parse_addr && bind_addr) { @@ -253,21 +458,21 @@ int parse_peers_peer_server(const char *file, int linenum, char **args) { newpeer->srv = curpeers->peers_fe->srv; if (!newpeer->local) - return 0; + goto out; /* The lines above are reserved to "peer" lines. */ if (*args[0] == 's') - return 0; + goto out; bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, args[2], xprt_get(XPRT_RAW)); if (!bind_conf) { ha_alert("parsing [%s:%d] : '%s %s' : Cannot allocate memory.\n", file, linenum, args[0], args[1]); err_code |= ERR_FATAL; - return 1; + goto out; } bind_conf->maxaccept = 1; - bind_conf->accept = session_accept_fd; + bind_conf->accept = session_accept_fd; bind_conf->options |= BC_O_UNLIMITED; if (!LIST_ISEMPTY(&bind_conf->listeners)) { @@ -276,7 +481,7 @@ int parse_peers_peer_server(const char *file, int linenum, char **args) { } if (!str2listener(args[2], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { - if (errmsg && *errmsg) { + if (errmsg) { indent_msg(&errmsg, 2); ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); } @@ -284,20 +489,23 @@ int parse_peers_peer_server(const char *file, int linenum, char **args) { ha_alert("parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s.\n", file, linenum, args[0], args[1], args[2]); err_code |= ERR_FATAL; - return 1; + goto out; } global.maxsock++; - return 0; + goto out; +out: + ha_free(&errmsg); + return err_code; } -int parse_peers_shards(const char *file, int linenum, char **args) { +int cfg_parse_peers_shards(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int linenum, char **err) { char *endptr; if (!*args[1]) { ha_alert("parsing [%s:%d] : '%s' : missing value\n", file, linenum, args[0]); err_code |= ERR_FATAL; - return 1; + goto out; } curpeers->nb_shards = strtol(args[1], &endptr, 10); @@ -305,28 +513,30 @@ int parse_peers_shards(const char *file, int linenum, char **args) { ha_alert("parsing [%s:%d] : '%s' : expects an integer argument, found '%s'\n", file, linenum, args[0], args[1]); err_code |= ERR_FATAL; - return 1; + goto out; } if (!curpeers->nb_shards) { ha_alert("parsing [%s:%d] : '%s' : expects a strictly positive integer argument\n", file, linenum, args[0]); err_code |= ERR_FATAL; - return 1; + goto out; } nb_shards = curpeers->nb_shards; - return 0; +out: + ha_free(&errmsg); + return err_code; } -int parse_peers_table(const char *file, int linenum, char **args) { +int cfg_parse_peers_table(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int linenum, char **err) { struct stktable *t, *other; char *id; size_t prefix_len; if (init_peers_frontend(file, -1, NULL, curpeers) != 0) { err_code |= ERR_ALERT | ERR_ABORT; - return 1; + goto out; } chunk_reset(&trash); @@ -334,7 +544,7 @@ int parse_peers_table(const char *file, int linenum, char **args) { ha_alert("parsing [%s:%d]: '%s %s' : stick-table name too long.\n", file, linenum, args[0], args[1]); err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } prefix_len = trash.data; @@ -342,7 +552,7 @@ int parse_peers_table(const char *file, int linenum, char **args) { ha_alert("parsing [%s:%d]: '%s %s' : stick-table name too long.\n", file, linenum, args[0], args[1]); err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } t = calloc(1, sizeof *t); @@ -350,10 +560,10 @@ int parse_peers_table(const char *file, int linenum, char **args) { if (!t || !id) { ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n", file, linenum, args[0], args[1]); - free(t); - free(id); + ha_free(&t); + ha_free(&id); err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } other = stktable_find_by_name(trash.area); @@ -364,36 +574,39 @@ int parse_peers_table(const char *file, int linenum, char **args) { other->proxy ? other->id : other->peers.p->id, other->conf.file, other->conf.line); err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } err_code |= parse_stick_table(file, linenum, args, t, id, id + prefix_len, curpeers); if (err_code & ERR_FATAL) { - free(t); - free(id); - return 1; + ha_free(&t); + ha_free(&id); + goto out; } stktable_store_name(t); t->next = stktables_list; stktables_list = t; - return 0; +out: + ha_free(&errmsg); + return err_code; } -int parse_peers_disabled(char **args) { +int cfg_parse_peers_disabled(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int linenum, char **err) { curpeers->disabled |= PR_FL_DISABLED; - return 0; + ha_free(&errmsg); + return err_code; } -int parse_peers_enabled(char **args) { +int cfg_parse_peers_enabled(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int linenum, char **err) { curpeers->disabled = 0; - return 0; + ha_free(&errmsg); + return err_code; } /* Helper for unknown keywords using peers_keywords list */ -/* This part accesses peers_keywords which is extern */ -int parse_peers_unknown(const char *file, int linenum, char **args) { +int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) { struct peers_kw_list *pkwl; struct cfg_kw_list *kwl; int index; @@ -405,13 +618,14 @@ int parse_peers_unknown(const char *file, int linenum, char **args) { if (rc < 0) { ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); /* errmsg might be confusing here, using global */ err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } else if (rc > 0) { ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg); err_code |= ERR_WARN; - return 1; + goto out; } + goto out; } } } @@ -424,56 +638,35 @@ int parse_peers_unknown(const char *file, int linenum, char **args) { if (errmsg) { ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); err_code |= ERR_ALERT | ERR_FATAL; - return 1; + goto out; } + goto out; } } } ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection); err_code |= ERR_ALERT | ERR_FATAL; - return 1; -} - -/* Main dispatcher */ -int cfg_parse_peers_new(const char *file, int linenum, char **args, int kwm) -{ - errmsg = NULL; - /* err_code is global, but we should reset it or accumulate? - Usually parse functions return 0 or error. - The global err_code is used inside sub-functions. - We should probably zero it at start of each line parsing if it tracks per-line status? - Wait, cfg_parse_peers in cfgparse.c: - int err_code = 0; - So it is per-call. - */ - err_code = 0; - - if (strcmp(args[0], "log") == 0) { - parse_peers_log(file, linenum, args, kwm); - } - else if (strcmp(args[0], "peers") == 0) { - parse_peers_section(file, linenum, args); - } - else if (strcmp(args[0], "peer") == 0 || strcmp(args[0], "server") == 0) { - parse_peers_peer_server(file, linenum, args); - } - else if (strcmp(args[0], "shards") == 0) { - parse_peers_shards(file, linenum, args); - } - else if (strcmp(args[0], "table") == 0) { - parse_peers_table(file, linenum, args); - } - else if (strcmp(args[0], "disabled") == 0) { - parse_peers_disabled(args); - } - else if (strcmp(args[0], "enabled") == 0) { - parse_peers_enabled(args); - } - else if (*args[0] != 0) { - parse_peers_unknown(file, linenum, args); - } + goto out; +out: ha_free(&errmsg); return err_code; } + +REGISTER_CONFIG_SECTION("peers", cfg_parse_peers, NULL); + +static struct cfg_kw_list cfg_kws = {{ }, { + { CFG_PEERS, "bind", cfg_parse_peers_bind_default_bind }, + { CFG_PEERS, "default-bind", cfg_parse_peers_bind_default_bind }, + { CFG_PEERS, "log", cfg_parse_peers_log }, + { CFG_PEERS, "peers", cfg_parse_peers_peers }, + { CFG_PEERS, "peer", cfg_parse_peers_peer_server }, + { CFG_PEERS, "server", cfg_parse_peers_peer_server }, + { CFG_PEERS, "shards", cfg_parse_peers_shards }, + { CFG_PEERS, "table", cfg_parse_peers_table }, + { CFG_PEERS, "disabled", cfg_parse_peers_disabled }, + { CFG_PEERS, "enabled", cfg_parse_peers_enabled }, +}}; + +INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws); \ No newline at end of file diff --git a/src/cfgparse.c b/src/cfgparse.c index 8853fac8b..d6418b782 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -549,611 +549,6 @@ int parse_process_number(const char *arg, unsigned long *proc, int max, int *aut return 0; } -/* Allocate and initialize the frontend of a "peers" section found in - * file <file> at line <linenum> with <id> as ID. - * Return 0 if succeeded, -1 if not. - * Note that this function may be called from "default-server" - * or "peer" lines. - */ -int init_peers_frontend(const char *file, int linenum, - const char *id, struct peers *peers) -{ - struct proxy *p; - char *errmsg = NULL; - - if (peers->peers_fe) { - p = peers->peers_fe; - goto out; - } - - p = alloc_new_proxy(NULL, PR_CAP_FE | PR_CAP_BE, &errmsg); - if (!p) { - ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); - ha_free(&errmsg); - return -1; - } - - peers_setup_frontend(p); - p->parent = peers; - /* Finally store this frontend. */ - peers->peers_fe = p; - - out: - if (id && !p->id) - p->id = strdup(id); - drop_file_name(&p->conf.file); - p->conf.args.file = p->conf.file = copy_file_name(file); - if (linenum != -1) - p->conf.args.line = p->conf.line = linenum; - - return 0; -} - -/* Only change ->file, ->line and ->arg struct bind_conf member values - * if already present. - */ -struct bind_conf *bind_conf_uniq_alloc(struct proxy *p, - const char *file, int line, - const char *arg, struct xprt_ops *xprt) -{ - struct bind_conf *bind_conf; - - if (!LIST_ISEMPTY(&p->conf.bind)) { - bind_conf = LIST_ELEM((&p->conf.bind)->n, typeof(bind_conf), by_fe); - /* - * We keep bind_conf->file and bind_conf->line unchanged - * to make them available for error messages - */ - if (arg) { - free(bind_conf->arg); - bind_conf->arg = strdup(arg); - } - } - else { - bind_conf = bind_conf_alloc(p, file, line, arg, xprt); - } - - return bind_conf; -} - -/* - * Allocate a new struct peer parsed at line <linenum> in file <file> - * to be added to <peers>. - * Returns the new allocated structure if succeeded, NULL if not. - */ -struct peer *cfg_peers_add_peer(struct peers *peers, - const char *file, int linenum, - const char *id, int local) -{ - struct peer *p; - - p = calloc(1, sizeof *p); - if (!p) { - ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); - return NULL; - } - - /* the peers are linked backwards first */ - peers->count++; - p->peers = peers; - p->next = peers->remote; - peers->remote = p; - p->conf.file = strdup(file); - p->conf.line = linenum; - p->last_change = ns_to_sec(now_ns); - HA_SPIN_INIT(&p->lock); - if (id) - p->id = strdup(id); - if (local) { - p->local = 1; - peers->local = p; - } - - return p; -} - -int cfg_parse_default_server(char **args, struct peers *curpeers, const char *file, int linenum, char **errmsg) -{ - int err_code = 0; - - if (init_peers_frontend(file, -1, NULL, curpeers) != 0) { - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, - SRV_PARSE_DEFAULT_SERVER|SRV_PARSE_IN_PEER_SECTION|SRV_PARSE_INITIAL_RESOLVE); - -out: - return err_code; -} - -int -cfg_parse_peers_bind_default_bind(char **args, int section_type, struct proxy *curproxy, const struct proxy *defproxy, const char *file, int linenum, char **errmsg) -{ - static struct peers *curpeers = NULL; - static struct sockaddr_storage *bind_addr = NULL; - struct peer *newpeer = NULL; - int cur_arg; - struct bind_conf *bind_conf; - int ret; - int err_code = 0; - static int bind_line, peer_line; - - cur_arg = 1; - - if (init_peers_frontend(file, linenum, NULL, curpeers) != 0) { - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - - bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, - args[1], xprt_get(XPRT_RAW)); - if (!bind_conf) { - ha_alert("parsing [%s:%d] : '%s %s' : cannot allocate memory.\n", file, linenum, args[0], args[1]); - err_code |= ERR_FATAL; - goto out; - } - - bind_conf->maxaccept = 1; - bind_conf->accept = session_accept_fd; - bind_conf->options |= BC_O_UNLIMITED; /* don't make the peers subject to global limits */ - - if (*args[0] == 'b') { - struct listener *l; - - if (peer_line) { - ha_alert("parsing [%s:%d] : mixing \"peer\" and \"bind\" line is forbidden\n", file, linenum); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - if (!LIST_ISEMPTY(&bind_conf->listeners)) { - ha_alert("parsing [%s:%d] : One listener per \"peers\" section is authorized but another is already configured at [%s:%d].\n", file, linenum, bind_conf->file, bind_conf->line); - err_code |= ERR_FATAL; - } - - if (!str2listener(args[1], curpeers->peers_fe, bind_conf, file, linenum, errmsg)) { - if (errmsg && *errmsg) { - indent_msg(errmsg, 2); - ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], *errmsg); - } - else - ha_alert("parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s.\n", - file, linenum, args[0], args[1], args[1]); - err_code |= ERR_FATAL; - goto out; - } - - /* Only one listener supported. Compare first listener - * against the last one. It must be the same one. - */ - if (bind_conf->listeners.n != bind_conf->listeners.p) { - ha_alert("parsing [%s:%d] : Only one listener per \"peers\" section is authorized. Multiple listening addresses or port range are not supported.\n", file, linenum); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - /* - * Newly allocated listener is at the end of the list - */ - l = LIST_ELEM(bind_conf->listeners.p, typeof(l), by_bind); - bind_addr = &l->rx.addr; - - global.maxsock++; /* for the listening socket */ - - bind_line = 1; - if (cfg_peers->local) { - /* Local peer already defined using "server" line has no - * address yet, we should update its server's addr:port - * settings - */ - newpeer = cfg_peers->local; - BUG_ON(!newpeer->srv); - newpeer->srv->addr = *bind_addr; - newpeer->srv->svc_port = get_host_port(bind_addr); - } - else { - /* This peer is local. - * Note that we do not set the peer ID. This latter is initialized - * when parsing "peer" or "server" line. - */ - newpeer = cfg_peers_add_peer(curpeers, file, linenum, NULL, 1); - if (!newpeer) { - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - } - cur_arg++; - } - - ret = bind_parse_args_list(bind_conf, args, cur_arg, cursection, file, linenum); - err_code |= ret; - if (ret != 0) - goto out; - -out: - return err_code; -} - -/* - * Parse a line in a <listen>, <frontend> or <backend> section. - * Returns the error code, 0 if OK, or any combination of : - * - ERR_ABORT: must abort ASAP - * - ERR_FATAL: we can continue parsing but not start the service - * - ERR_WARN: a warning has been emitted - * - ERR_ALERT: an alert has been emitted - * Only the two first ones can stop processing, the two others are just - * indicators. - */ -int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) -{ - static struct peers *curpeers = NULL; - static struct sockaddr_storage *bind_addr = NULL; - static int nb_shards = 0; - struct peer *newpeer = NULL; - const char *err; - struct bind_conf *bind_conf; - int err_code = 0; - char *errmsg = NULL; - static int bind_line, peer_line; - - - if (strcmp(args[0], "log") == 0) { - if (init_peers_frontend(file, linenum, NULL, curpeers) != 0) { - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - if (!parse_logger(args, &curpeers->peers_fe->loggers, (kwm == KWM_NO), file, linenum, &errmsg)) { - ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - } - else if (strcmp(args[0], "peers") == 0) { /* new peers section */ - /* Initialize these static variables when entering a new "peers" section*/ - bind_line = peer_line = 0; - bind_addr = NULL; - if (!*args[1]) { - ha_alert("parsing [%s:%d] : missing name for peers section.\n", file, linenum); - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - - if (alertif_too_many_args(1, file, linenum, args, &err_code)) { - err_code |= ERR_ABORT; - goto out; - } - - err = invalid_char(args[1]); - if (err) { - ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n", - file, linenum, *err, args[0], args[1]); - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - - for (curpeers = cfg_peers; curpeers != NULL; curpeers = curpeers->next) { - /* - * If there are two proxies with the same name only following - * combinations are allowed: - */ - if (strcmp(curpeers->id, args[1]) == 0) { - ha_alert("Parsing [%s:%d]: peers section '%s' has the same name as another peers section declared at %s:%d.\n", - file, linenum, args[1], curpeers->conf.file, curpeers->conf.line); - err_code |= ERR_ALERT | ERR_FATAL; - } - } - - if ((curpeers = calloc(1, sizeof(*curpeers))) == NULL) { - ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum); - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - - curpeers->next = cfg_peers; - cfg_peers = curpeers; - curpeers->conf.file = strdup(file); - curpeers->conf.line = linenum; - curpeers->last_change = ns_to_sec(now_ns); - curpeers->id = strdup(args[1]); - curpeers->disabled = 0; - } - else if (strcmp(args[0], "peer") == 0 || - strcmp(args[0], "server") == 0) { /* peer or server definition */ - struct server *prev_srv; - int local_peer, peer; - int parse_addr = 0; - - peer = *args[0] == 'p'; - local_peer = strcmp(args[1], localpeer) == 0; - /* The local peer may have already partially been parsed on a "bind" line. */ - if (*args[0] == 'p') { - if (bind_line) { - ha_alert("parsing [%s:%d] : mixing \"peer\" and \"bind\" line is forbidden\n", file, linenum); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - peer_line = 1; - } - if (cfg_peers->local && !cfg_peers->local->id && local_peer) { - /* The local peer has already been initialized on a "bind" line. - * Let's use it and store its ID. - */ - newpeer = cfg_peers->local; - newpeer->id = strdup(localpeer); - } - else { - if (local_peer && cfg_peers->local) { - ha_alert("parsing [%s:%d] : '%s %s' : local peer name already referenced at %s:%d. %s\n", - file, linenum, args[0], args[1], - curpeers->peers_fe->conf.file, curpeers->peers_fe->conf.line, cfg_peers->local->id); - err_code |= ERR_FATAL; - goto out; - } - newpeer = cfg_peers_add_peer(curpeers, file, linenum, args[1], local_peer); - if (!newpeer) { - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - } - - /* Line number and peer ID are updated only if this peer is the local one. */ - if (init_peers_frontend(file, - newpeer->local ? linenum: -1, - newpeer->local ? newpeer->id : NULL, - curpeers) != 0) { - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - - /* This initializes curpeer->peers->peers_fe->srv. - * The server address is parsed only if we are parsing a "peer" line, - * or if we are parsing a "server" line and the current peer is not the local one. - */ - parse_addr = (peer || !local_peer) ? SRV_PARSE_PARSE_ADDR : 0; - prev_srv = curpeers->peers_fe->srv; - err_code |= parse_server(file, linenum, args, curpeers->peers_fe, NULL, - SRV_PARSE_IN_PEER_SECTION|parse_addr|SRV_PARSE_INITIAL_RESOLVE); - if (curpeers->peers_fe->srv == prev_srv) { - /* parse_server didn't add a server: - * Remove the newly allocated peer. - */ - struct peer *p; - - /* while it is tolerated to have a "server" line without address, it isn't - * the case for a "peer" line - */ - if (peer) { - ha_warning("parsing [%s:%d] : '%s %s' : ignoring invalid peer definition (missing address:port)\n", - file, linenum, args[0], args[1]); - err_code |= ERR_WARN; - } - else { - ha_diag_warning("parsing [%s:%d] : '%s %s' : ignoring server (not a local peer, valid address:port is expected)\n", - file, linenum, args[0], args[1]); - } - - p = curpeers->remote; - curpeers->remote = curpeers->remote->next; - free(p->id); - free(p); - if (local_peer) { - /* we only get there with incomplete "peer" - * line for local peer (missing address): - * - * reset curpeers and curpeers fields - * that are local peer related - */ - curpeers->local = NULL; - ha_free(&curpeers->peers_fe->id); - } - goto out; - } - - if (!parse_addr && bind_addr) { - /* local peer declared using "server": has name but no - * address: we use the known "bind" line addr settings - * as implicit server's addr and port. - */ - curpeers->peers_fe->srv->addr = *bind_addr; - curpeers->peers_fe->srv->svc_port = get_host_port(bind_addr); - } - - if (nb_shards && curpeers->peers_fe->srv->shard > nb_shards) { - ha_warning("parsing [%s:%d] : '%s %s' : %d peer shard greater value than %d shards value is ignored.\n", - file, linenum, args[0], args[1], curpeers->peers_fe->srv->shard, nb_shards); - curpeers->peers_fe->srv->shard = 0; - err_code |= ERR_WARN; - } - - if (curpeers->peers_fe->srv->init_addr_methods || curpeers->peers_fe->srv->resolvers_id || - curpeers->peers_fe->srv->do_check || curpeers->peers_fe->srv->do_agent) { - ha_warning("parsing [%s:%d] : '%s %s' : init_addr, resolvers, check and agent are ignored for peers.\n", file, linenum, args[0], args[1]); - err_code |= ERR_WARN; - } - - HA_SPIN_INIT(&newpeer->lock); - - newpeer->srv = curpeers->peers_fe->srv; - if (!newpeer->local) - goto out; - - /* The lines above are reserved to "peer" lines. */ - if (*args[0] == 's') - goto out; - - bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, args[2], xprt_get(XPRT_RAW)); - if (!bind_conf) { - ha_alert("parsing [%s:%d] : '%s %s' : Cannot allocate memory.\n", file, linenum, args[0], args[1]); - err_code |= ERR_FATAL; - goto out; - } - - bind_conf->maxaccept = 1; - bind_conf->accept = session_accept_fd; - bind_conf->options |= BC_O_UNLIMITED; /* don't make the peers subject to global limits */ - - if (!LIST_ISEMPTY(&bind_conf->listeners)) { - ha_alert("parsing [%s:%d] : One listener per \"peers\" section is authorized but another is already configured at [%s:%d].\n", file, linenum, bind_conf->file, bind_conf->line); - err_code |= ERR_FATAL; - } - - if (!str2listener(args[2], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { - if (errmsg && *errmsg) { - indent_msg(&errmsg, 2); - ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg); - } - else - ha_alert("parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s.\n", - file, linenum, args[0], args[1], args[2]); - err_code |= ERR_FATAL; - goto out; - } - - global.maxsock++; /* for the listening socket */ - } - else if (strcmp(args[0], "shards") == 0) { - char *endptr; - - if (!*args[1]) { - ha_alert("parsing [%s:%d] : '%s' : missing value\n", file, linenum, args[0]); - err_code |= ERR_FATAL; - goto out; - } - - curpeers->nb_shards = strtol(args[1], &endptr, 10); - if (*endptr != '\0') { - ha_alert("parsing [%s:%d] : '%s' : expects an integer argument, found '%s'\n", - file, linenum, args[0], args[1]); - err_code |= ERR_FATAL; - goto out; - } - - if (!curpeers->nb_shards) { - ha_alert("parsing [%s:%d] : '%s' : expects a strictly positive integer argument\n", - file, linenum, args[0]); - err_code |= ERR_FATAL; - goto out; - } - - nb_shards = curpeers->nb_shards; - } - else if (strcmp(args[0], "table") == 0) { - struct stktable *t, *other; - char *id; - size_t prefix_len; - - /* Line number and peer ID are updated only if this peer is the local one. */ - if (init_peers_frontend(file, -1, NULL, curpeers) != 0) { - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } - - /* Build the stick-table name, concatenating the "peers" section name - * followed by a '/' character and the table name argument. - */ - chunk_reset(&trash); - if (!chunk_strcpy(&trash, curpeers->id)) { - ha_alert("parsing [%s:%d]: '%s %s' : stick-table name too long.\n", - file, linenum, args[0], args[1]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - prefix_len = trash.data; - if (!chunk_memcat(&trash, "/", 1) || !chunk_strcat(&trash, args[1])) { - ha_alert("parsing [%s:%d]: '%s %s' : stick-table name too long.\n", - file, linenum, args[0], args[1]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - t = calloc(1, sizeof *t); - id = strdup(trash.area); - if (!t || !id) { - ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n", - file, linenum, args[0], args[1]); - free(t); - free(id); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - other = stktable_find_by_name(trash.area); - if (other) { - ha_alert("parsing [%s:%d] : stick-table name '%s' conflicts with table declared in %s '%s' at %s:%d.\n", - file, linenum, args[1], - other->proxy ? proxy_cap_str(other->proxy->cap) : "peers", - other->proxy ? other->id : other->peers.p->id, - other->conf.file, other->conf.line); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - - err_code |= parse_stick_table(file, linenum, args, t, id, id + prefix_len, curpeers); - if (err_code & ERR_FATAL) { - free(t); - free(id); - goto out; - } - - stktable_store_name(t); - t->next = stktables_list; - stktables_list = t; - } - else if (strcmp(args[0], "disabled") == 0) { /* disables this peers section */ - curpeers->disabled |= PR_FL_DISABLED; - } - else if (strcmp(args[0], "enabled") == 0) { /* enables this peers section (used to revert a disabled default) */ - curpeers->disabled = 0; - } - else if (*args[0] != 0) { - struct peers_kw_list *pkwl; - struct cfg_kw_list *kwl; - int index; - int cfg_index; - int rc = -1; - - list_for_each_entry(pkwl, &peers_keywords.list, list) { - for (index = 0; pkwl->kw[index].kw != NULL; index++) { - if (strcmp(pkwl->kw[index].kw, args[0]) == 0) { - if (rc < 0) { - ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - else if (rc > 0) { - ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg); - err_code |= ERR_WARN; - goto out; - } - } - } - } - - list_for_each_entry(kwl, &cfg_keywords.list, list) { - for (index = 0; kwl->kw[index].kw != NULL; index++) { - if ((kwl->kw[index].section & CFG_PEERS) && - (strcmp(kwl->kw[index].kw, args[0]) == 0)) { - err_code = kwl->kw[index].parse(args, CFG_PEERS, NULL, NULL, file, linenum, &errmsg); - if (errmsg) { - ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - } - } - } - - ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection); - err_code |= ERR_ALERT | ERR_FATAL; - } - -out: - ha_free(&errmsg); - return err_code; -} - /* * Parse a line in a <listen>, <frontend> or <backend> section. * Returns the error code, 0 if OK, or any combination of : @@ -5003,7 +4398,6 @@ REGISTER_CONFIG_SECTION("backend", cfg_parse_listen, NULL); REGISTER_CONFIG_SECTION("defaults", cfg_parse_listen, NULL); REGISTER_CONFIG_SECTION("global", cfg_parse_global, NULL); REGISTER_CONFIG_SECTION("userlist", cfg_parse_users, NULL); -REGISTER_CONFIG_SECTION("peers", cfg_parse_peers, NULL); REGISTER_CONFIG_SECTION("mailers", cfg_parse_mailers, NULL); REGISTER_CONFIG_SECTION("namespace_list", cfg_parse_netns, NULL); REGISTER_CONFIG_SECTION("traces", cfg_parse_traces, NULL); @@ -5012,8 +4406,6 @@ static struct cfg_kw_list cfg_kws = {{ }, { { CFG_GLOBAL, "default-path", cfg_parse_global_def_path }, { CFG_USERLIST, "group", cfg_parse_users_group }, { CFG_USERLIST, "user", cfg_parse_users_user }, - { CFG_PEERS, "bind", cfg_parse_peers_bind_default_bind }, - { CFG_PEERS, "default-bind", cfg_parse_peers_bind_default_bind }, { /* END */ } }}; -- 2.48.1

