From: Frédéric Lécaille <flecai...@haproxy.com>

Make "bind" line also parse the local peer bind address.
Add "default-bind" option to parse the binding options excepted the bind 
address.
Prevent "bind" lines to be mixed with "peer" line to help in handling the 
migration.
---
 src/cfgparse.c | 153 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 122 insertions(+), 31 deletions(-)

diff --git a/src/cfgparse.c b/src/cfgparse.c
index ef69b37d..2a6a4839 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -516,7 +516,8 @@ static int init_peers_frontend(const char *file, int 
linenum,
                p->id = strdup(id);
        free(p->conf.file);
        p->conf.args.file = p->conf.file = strdup(file);
-       p->conf.args.line = p->conf.line = linenum;
+       if (linenum != -1)
+               p->conf.args.line = p->conf.line = linenum;
 
        return 0;
 }
@@ -546,6 +547,44 @@ static struct bind_conf *bind_conf_uniq_alloc(struct proxy 
*p,
 
        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->next = peers->remote;
+       peers->remote = p;
+       p->conf.file = strdup(file);
+       p->conf.line = linenum;
+       p->last_change = now.tv_sec;
+       p->xprt  = xprt_get(XPRT_RAW);
+       p->sock_init_arg = NULL;
+       HA_SPIN_INIT(&p->lock);
+       if (id)
+               p->id = strdup(id);
+       if (local) {
+               p->local = 1;
+               peers->local = p;
+       }
+
+       return p;
+}
+
 /*
  * Parse a line in a <listen>, <frontend> or <backend> section.
  * Returns the error code, 0 if OK, or any combination of :
@@ -565,8 +604,9 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
        struct listener *l;
        int err_code = 0;
        char *errmsg = NULL;
+       static int bind_line, peer_line;
 
-       if (strcmp(args[0], "bind") == 0) {
+       if (strcmp(args[0], "bind") == 0 || strcmp(args[0], "default-bind") == 
0) {
                int cur_arg;
                static int kws_dumped;
                struct bind_conf *bind_conf;
@@ -582,6 +622,44 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
 
                bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, 
linenum,
                                                 NULL, xprt_get(XPRT_RAW));
+               if (*args[0] == 'b') {
+                       struct sockaddr_storage *sk;
+                       int port, port1, port2;
+
+                       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;
+                       }
+
+                       sk = str2sa_range(args[1], &port, &port1, &port2, 
&errmsg, NULL, NULL, 0);
+                       if (!sk) {
+                               ha_alert("parsing [%s:%d]: '%s %s': %s\n",
+                                                file, linenum, args[0], 
args[1], errmsg);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+
+                       bind_line = 1;
+                       if (cfg_peers->local) {
+                               newpeer = cfg_peers->local;
+                       }
+                       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;
+                               }
+                       }
+                       newpeer->addr = *sk;
+                       newpeer->proto = 
protocol_by_family(newpeer->addr.ss_family);
+                       cur_arg++;
+               }
+
                while (*args[cur_arg] && (kw = bind_find_kw(args[cur_arg]))) {
                        int ret;
 
@@ -616,13 +694,15 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
                }
        }
        else if (strcmp(args[0], "default-server") == 0) {
-               if (init_peers_frontend(file, linenum, NULL, curpeers) != 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);
        }
        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;
                if (!*args[1]) {
                        ha_alert("parsing [%s:%d] : missing name for peers 
section.\n", file, linenum);
                        err_code |= ERR_ALERT | ERR_ABORT;
@@ -668,27 +748,50 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
        }
        else if (strcmp(args[0], "peer") == 0 ||
                 strcmp(args[0], "server") == 0) { /* peer or server definition 
*/
-               if ((newpeer = calloc(1, sizeof(*newpeer))) == NULL) {
-                       ha_alert("parsing [%s:%d] : out of memory.\n", file, 
linenum);
-                       err_code |= ERR_ALERT | ERR_ABORT;
-                       goto out;
-               }
+               int local_peer;
 
-               /* the peers are linked backwards first */
-               curpeers->count++;
-               newpeer->next = curpeers->remote;
-               curpeers->remote = newpeer;
-               newpeer->conf.file = strdup(file);
-               newpeer->conf.line = linenum;
-
-               newpeer->last_change = now.tv_sec;
-               newpeer->id = strdup(args[1]);
+               local_peer = !strcmp(args[1], localpeer);
+               /* 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;
+                       }
+               }
 
-               if (init_peers_frontend(file, linenum, newpeer->id, curpeers) 
!= 0) {
+               /* 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. */
                err_code |= parse_server(file, linenum, args, 
curpeers->peers_fe, NULL);
                if (!curpeers->peers_fe->srv)
                        goto out;
@@ -699,22 +802,11 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
                newpeer->sock_init_arg = NULL;
                HA_SPIN_INIT(&newpeer->lock);
 
-               if (strcmp(newpeer->id, localpeer) != 0) {
+               if (!newpeer->local) {
                        newpeer->srv = curpeers->peers_fe->srv;
                        goto out;
                }
 
-               if (cfg_peers->local) {
-                       ha_alert("parsing [%s:%d] : '%s %s' : local peer name 
already referenced at %s:%d.\n",
-                                file, linenum, args[0], args[1],
-                                curpeers->peers_fe->conf.file, 
curpeers->peers_fe->conf.line);
-                       err_code |= ERR_FATAL;
-                       goto out;
-               }
-
-               /* Current is local peer, it define a frontend */
-               newpeer->local = 1;
-
                bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, 
linenum, args[2], xprt_get(XPRT_RAW));
 
                if (!str2listener(args[2], curpeers->peers_fe, bind_conf, file, 
linenum, &errmsg)) {
@@ -738,7 +830,6 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
                        l->options |= LI_O_UNLIMITED; /* don't make the peers 
subject to global limits */
                        global.maxsock += l->maxconn;
                }
-               cfg_peers->local = newpeer;
        } /* neither "peer" nor "peers" */
        else if (!strcmp(args[0], "disabled")) {  /* disables this peers 
section */
                curpeers->state = PR_STSTOPPED;
-- 
2.11.0

Reply via email to