diff --git a/include/proto/cli.h b/include/proto/cli.h index da80af7d3..de1305b97 100644 --- a/include/proto/cli.h +++ b/include/proto/cli.h @@ -28,5 +28,7 @@ void cli_register_kw(struct cli_kw_list *kw_list); int cli_has_level(struct appctx *appctx, int level); +int mworker_cli_sockpair_new(struct mworker_proc *mworker_proc, int proc); + #endif /* _PROTO_CLI_H */ diff --git a/src/cli.c b/src/cli.c index 07dce53bf..2c17c6b8f 100644 --- a/src/cli.c +++ b/src/cli.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -1565,6 +1566,63 @@ static int cli_parse_simple(char **args, char *payload, struct appctx *appctx, v } +/* + * Create a new CLI socket using a socketpair for a worker process + * is the process structure, and is the process number + */ +int mworker_cli_sockpair_new(struct mworker_proc *mworker_proc, int proc) +{ + struct bind_conf *bind_conf; + struct listener *l; + char *path = NULL; + char *err = NULL; + + /* master pipe to ensure the master is still alive */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, mworker_proc->ipc_fd) < 0) { + ha_alert("Cannot create worker socketpair.\n"); + return -1; + } + + /* XXX: we might want to use a separate frontend at some point */ + if (!global.stats_fe) { + if ((global.stats_fe = alloc_stats_fe("GLOBAL", "master-socket", 0)) == NULL) { + ha_alert("out of memory trying to allocate the stats frontend"); + return -1; + } + } + + bind_conf = bind_conf_alloc(global.stats_fe, "master-socket", 0, "", xprt_get(XPRT_RAW)); + bind_conf->level &= ~ACCESS_LVL_MASK; + bind_conf->level |= ACCESS_LVL_ADMIN; /* TODO: need to lower the rights with a CLI keyword*/ + + bind_conf->bind_proc = 1UL << proc; + global.stats_fe->bind_proc = 0; /* XXX: we should be careful with that, it can be removed by configuration */ + + if (!memprintf(&path, "sockpair@%d", mworker_proc->ipc_fd[1])) { + ha_alert("Cannot allocate listener.\n"); + return -1; + } + + if (!str2listener(path, global.stats_fe, bind_conf, "master-socket", 0, &err)) { + ha_alert("Cannot create a CLI sockpair listener for process #%d\n", proc); + return -1; + } + + list_for_each_entry(l, &bind_conf->listeners, by_bind) { + l->maxconn = global.stats_fe->maxconn; + l->backlog = global.stats_fe->backlog; + l->accept = session_accept_fd; + l->default_target = global.stats_fe->default_target; + l->options |= LI_O_UNLIMITED; + /* it's a sockpair but we don't want to keep the fd in the master */ + l->options &= ~LI_O_INHERITED; + l->nice = -64; /* we want to boost priority for local stats */ + global.maxsock += l->maxconn; + } + + return 0; +} + static struct applet cli_applet = { .obj_type = OBJ_TYPE_APPLET, .name = "", /* used for logging */ diff --git a/src/haproxy.c b/src/haproxy.c index 539eaeea4..5cce57343 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -84,6 +84,7 @@ #include #include +#include #include #include #include @@ -94,6 +95,7 @@ #include #include #include +#include #include #include #include @@ -1709,6 +1711,30 @@ static void init(int argc, char **argv) exit(1); } + if (global.mode & MODE_MWORKER) { + int proc; + + for (proc = 0; proc < global.nbproc; proc++) { + struct mworker_proc *tmproc; + + tmproc = malloc(sizeof(*tmproc)); + if (!tmproc) { + ha_alert("Cannot allocate process structures.\n"); + exit(EXIT_FAILURE); + } + + tmproc->pid = -1; + tmproc->reloads = 0; + tmproc->relative_pid = 1 + proc; + + if (mworker_cli_sockpair_new(tmproc, proc) < 0) { + exit(EXIT_FAILURE); + } + + LIST_ADDQ(&proc_list, &tmproc->list); + } + } + pattern_finalize_config(); err_code |= check_config_validity(); @@ -2914,25 +2940,6 @@ int main(int argc, char **argv) /* the father launches the required number of processes */ for (proc = 0; proc < global.nbproc; proc++) { - if (global.mode & MODE_MWORKER) { - - proc_self = malloc(sizeof(*proc_self)); - if (!proc_self) { - ha_alert("[%s.main()] Cannot allocate process structures.\n", argv[0]); - exit(1); - } - - /* master pipe to ensure the master is still alive */ - ret = socketpair(AF_UNIX, SOCK_STREAM, 0, proc_self->ipc_fd); - if (ret < 0) { - ha_alert("[%s.main()] Cannot create master pipe.\n", argv[0]); - exit(EXIT_FAILURE); - } else { - proc_self->reloads = 0; - proc_self->relative_pid = relative_pid; - LIST_ADDQ(&proc_list, &proc_self->list); - } - } ret = fork(); if (ret < 0) { ha_alert("[%s.main()] Cannot fork.\n", argv[0]); @@ -2948,9 +2955,16 @@ int main(int argc, char **argv) shut_your_big_mouth_gcc(write(pidfd, pidstr, strlen(pidstr))); } if (global.mode & MODE_MWORKER) { - proc_self->pid = ret; - close(proc_self->ipc_fd[1]); /* close client side */ - proc_self->ipc_fd[1] = -1; + struct mworker_proc *child; + + /* find the right mworker_proc */ + list_for_each_entry(child, &proc_list, list) { + if (child->relative_pid == relative_pid && + child->reloads == 0) { + child->pid = ret; + break; + } + } } relative_pid++; /* each child will get a different one */ @@ -3020,13 +3034,17 @@ int main(int argc, char **argv) /* free proc struct of other processes */ list_for_each_entry_safe(child, it, &proc_list, list) { - if (child->ipc_fd[0] > -1) { - close(child->ipc_fd[0]); - child->ipc_fd[0] = -1; - } - if (child == proc_self) + /* close the FD of the master side for all + * workers, we don't need to close the worker + * side of other workers since it's done with + * the bind_proc */ + close(child->ipc_fd[0]); + if (child->relative_pid == relative_pid && + child->reloads == 0) { + /* keep this struct if this is our pid */ + proc_self = child; continue; - close(child->ipc_fd[1]); + } LIST_DEL(&child->list); free(child); }