mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-29 09:44:26 +00:00
vtysh: use fork() workflow for -f too
It was being used for -b only; we should be able to use it for -f as well. This also merges the codepaths for -b and -f since they have no real functional difference. Signed-off-by: Quentin Young <qlyoung@nvidia.com>
This commit is contained in:
parent
449f66552f
commit
ac76809027
@ -3536,7 +3536,7 @@ DEFUN (vtysh_copy_to_running,
|
|||||||
int ret;
|
int ret;
|
||||||
const char *fname = argv[1]->arg;
|
const char *fname = argv[1]->arg;
|
||||||
|
|
||||||
ret = vtysh_read_config(fname, true);
|
ret = vtysh_apply_config(fname, true, false);
|
||||||
|
|
||||||
/* Return to enable mode - the 'read_config' api leaves us up a level */
|
/* Return to enable mode - the 'read_config' api leaves us up a level */
|
||||||
vtysh_execute_no_pager("enable");
|
vtysh_execute_no_pager("enable");
|
||||||
|
@ -98,7 +98,7 @@ void config_add_line(struct list *, const char *);
|
|||||||
|
|
||||||
int vtysh_mark_file(const char *filename);
|
int vtysh_mark_file(const char *filename);
|
||||||
|
|
||||||
int vtysh_read_config(const char *filename, bool dry_run);
|
int vtysh_apply_config(const char *config_file_path, bool dry_run, bool fork);
|
||||||
int vtysh_write_config_integrated(void);
|
int vtysh_write_config_integrated(void);
|
||||||
|
|
||||||
void vtysh_config_parse_line(void *, const char *);
|
void vtysh_config_parse_line(void *, const char *);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "linklist.h"
|
#include "linklist.h"
|
||||||
@ -625,18 +626,20 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read up configuration file from config_default_dir. */
|
/*
|
||||||
int vtysh_read_config(const char *config_default_dir, bool dry_run)
|
* Read configuration file and send it to all connected daemons
|
||||||
|
*/
|
||||||
|
static int vtysh_read_config(const char *config_file_path, bool dry_run)
|
||||||
{
|
{
|
||||||
FILE *confp = NULL;
|
FILE *confp = NULL;
|
||||||
bool save;
|
bool save;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
confp = fopen(config_default_dir, "r");
|
confp = fopen(config_file_path, "r");
|
||||||
if (confp == NULL) {
|
if (confp == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%% Can't open configuration file %s due to '%s'.\n",
|
"%% Can't open configuration file %s due to '%s'.\n",
|
||||||
config_default_dir, safe_strerror(errno));
|
config_file_path, safe_strerror(errno));
|
||||||
return CMD_ERR_NO_FILE;
|
return CMD_ERR_NO_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +651,93 @@ int vtysh_read_config(const char *config_default_dir, bool dry_run)
|
|||||||
|
|
||||||
vtysh_add_timestamp = save;
|
vtysh_add_timestamp = save;
|
||||||
|
|
||||||
return (ret);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vtysh_apply_config(const char *config_file_path, bool dry_run, bool do_fork)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We need to apply the whole config file to all daemons. Instead of
|
||||||
|
* having one client talk to N daemons, we fork N times and let each
|
||||||
|
* child handle one daemon.
|
||||||
|
*/
|
||||||
|
pid_t fork_pid = getpid();
|
||||||
|
int status = 0;
|
||||||
|
int ret;
|
||||||
|
int my_client_type;
|
||||||
|
char my_client[64];
|
||||||
|
|
||||||
|
if (do_fork) {
|
||||||
|
for (unsigned int i = 0; i < array_size(vtysh_client); i++) {
|
||||||
|
/* Store name of client this fork will handle */
|
||||||
|
strlcpy(my_client, vtysh_client[i].name,
|
||||||
|
sizeof(my_client));
|
||||||
|
my_client_type = vtysh_client[i].flag;
|
||||||
|
fork_pid = fork();
|
||||||
|
|
||||||
|
/* If child, break */
|
||||||
|
if (fork_pid == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parent, wait for children */
|
||||||
|
if (fork_pid != 0) {
|
||||||
|
fprintf(stdout,
|
||||||
|
"Waiting for children to finish applying config...\n");
|
||||||
|
while (wait(&status) > 0)
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* children, grow up to be cowboys
|
||||||
|
*/
|
||||||
|
for (unsigned int i = 0; i < array_size(vtysh_client); i++) {
|
||||||
|
if (my_client_type != vtysh_client[i].flag) {
|
||||||
|
struct vtysh_client *cl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is a client we aren't responsible
|
||||||
|
* for, disconnect
|
||||||
|
*/
|
||||||
|
for (cl = &vtysh_client[i]; cl; cl = cl->next) {
|
||||||
|
if (cl->fd >= 0)
|
||||||
|
close(cl->fd);
|
||||||
|
cl->fd = -1;
|
||||||
|
}
|
||||||
|
} else if (vtysh_client[i].fd == -1 &&
|
||||||
|
vtysh_client[i].next == NULL) {
|
||||||
|
/*
|
||||||
|
* If this is the client we are responsible
|
||||||
|
* for, but we aren't already connected to that
|
||||||
|
* client, that means the client isn't up in
|
||||||
|
* the first place and we can exit early
|
||||||
|
*/
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "[%d|%s] sending configuration\n", getpid(),
|
||||||
|
my_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = vtysh_read_config(config_file_path, dry_run);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
if (do_fork)
|
||||||
|
fprintf(stderr,
|
||||||
|
"[%d|%s] Configuration file[%s] processing failure: %d\n",
|
||||||
|
getpid(), my_client, frr_config, ret);
|
||||||
|
else
|
||||||
|
fprintf(stderr,
|
||||||
|
"Configuration file[%s] processing failure: %d\n",
|
||||||
|
frr_config, ret);
|
||||||
|
} else if (do_fork) {
|
||||||
|
fprintf(stderr, "[%d|%s] done\n", getpid(), my_client);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't write vtysh specific into file from vtysh. vtysh.conf should
|
/* We don't write vtysh specific into file from vtysh. vtysh.conf should
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -345,8 +344,6 @@ int main(int argc, char **argv, char **env)
|
|||||||
char pathspace[MAXPATHLEN] = "";
|
char pathspace[MAXPATHLEN] = "";
|
||||||
const char *histfile = NULL;
|
const char *histfile = NULL;
|
||||||
const char *histfile_env = getenv("VTYSH_HISTFILE");
|
const char *histfile_env = getenv("VTYSH_HISTFILE");
|
||||||
char my_client[64];
|
|
||||||
int my_client_type;
|
|
||||||
|
|
||||||
/* SUID: drop down to calling user & go back up when needed */
|
/* SUID: drop down to calling user & go back up when needed */
|
||||||
elevuid = geteuid();
|
elevuid = geteuid();
|
||||||
@ -497,7 +494,7 @@ int main(int argc, char **argv, char **env)
|
|||||||
/* Read vtysh configuration file before connecting to daemons.
|
/* Read vtysh configuration file before connecting to daemons.
|
||||||
* (file may not be readable to calling user in SUID mode) */
|
* (file may not be readable to calling user in SUID mode) */
|
||||||
suid_on();
|
suid_on();
|
||||||
vtysh_read_config(vtysh_config, dryrun);
|
vtysh_apply_config(vtysh_config, dryrun, false);
|
||||||
suid_off();
|
suid_off();
|
||||||
}
|
}
|
||||||
/* Error code library system */
|
/* Error code library system */
|
||||||
@ -516,9 +513,9 @@ int main(int argc, char **argv, char **env)
|
|||||||
/* Start execution only if not in dry-run mode */
|
/* Start execution only if not in dry-run mode */
|
||||||
if (dryrun && !cmd) {
|
if (dryrun && !cmd) {
|
||||||
if (inputfile) {
|
if (inputfile) {
|
||||||
ret = vtysh_read_config(inputfile, dryrun);
|
ret = vtysh_apply_config(inputfile, dryrun, false);
|
||||||
} else {
|
} else {
|
||||||
ret = vtysh_read_config(frr_config, dryrun);
|
ret = vtysh_apply_config(frr_config, dryrun, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(ret);
|
exit(ret);
|
||||||
@ -597,10 +594,17 @@ int main(int argc, char **argv, char **env)
|
|||||||
return vtysh_write_config_integrated();
|
return vtysh_write_config_integrated();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputfile) {
|
if (boot_flag)
|
||||||
|
inputfile = frr_config;
|
||||||
|
|
||||||
|
if (inputfile || boot_flag) {
|
||||||
vtysh_flock_config(inputfile);
|
vtysh_flock_config(inputfile);
|
||||||
ret = vtysh_read_config(inputfile, dryrun);
|
ret = vtysh_apply_config(inputfile, dryrun, !no_fork);
|
||||||
vtysh_unflock_config();
|
vtysh_unflock_config();
|
||||||
|
|
||||||
|
if (no_error)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,106 +721,6 @@ int main(int argc, char **argv, char **env)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Boot startup configuration file. */
|
|
||||||
if (boot_flag) {
|
|
||||||
/*
|
|
||||||
* flock config file before fork. After fork, each child will
|
|
||||||
* hold the same lock. The lock can be released by any one of
|
|
||||||
* them but they will exit without releasing the lock - the
|
|
||||||
* parent (us) will release it when they are done
|
|
||||||
*/
|
|
||||||
vtysh_flock_config(frr_config);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In boot mode, we need to apply the whole config file to all
|
|
||||||
* daemons. Instead of having one client talk to N daemons, we
|
|
||||||
* fork N times and let each child handle one daemon.
|
|
||||||
*/
|
|
||||||
pid_t fork_pid = getpid();
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
if (!no_fork) {
|
|
||||||
for (unsigned int i = 0; i < array_size(vtysh_client);
|
|
||||||
i++) {
|
|
||||||
/* Store name of client this fork will handle */
|
|
||||||
strlcpy(my_client, vtysh_client[i].name,
|
|
||||||
sizeof(my_client));
|
|
||||||
my_client_type = vtysh_client[i].flag;
|
|
||||||
fork_pid = fork();
|
|
||||||
|
|
||||||
/* If child, break */
|
|
||||||
if (fork_pid == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parent, wait for children */
|
|
||||||
if (fork_pid != 0) {
|
|
||||||
fprintf(stdout,
|
|
||||||
"Waiting for children to finish applying config...\n");
|
|
||||||
while (wait(&status) > 0)
|
|
||||||
;
|
|
||||||
ret = 0;
|
|
||||||
goto boot_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* children, grow up to be cowboys
|
|
||||||
*/
|
|
||||||
for (unsigned int i = 0; i < array_size(vtysh_client);
|
|
||||||
i++) {
|
|
||||||
if (my_client_type != vtysh_client[i].flag) {
|
|
||||||
struct vtysh_client *cl;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If this is a client we aren't
|
|
||||||
* responsible for, disconnect
|
|
||||||
*/
|
|
||||||
for (cl = &vtysh_client[i]; cl;
|
|
||||||
cl = cl->next) {
|
|
||||||
if (cl->fd >= 0)
|
|
||||||
close(cl->fd);
|
|
||||||
cl->fd = -1;
|
|
||||||
}
|
|
||||||
} else if (vtysh_client[i].fd == -1 &&
|
|
||||||
vtysh_client[i].next == NULL) {
|
|
||||||
/*
|
|
||||||
* If this is the client we are
|
|
||||||
* responsible for, but we aren't
|
|
||||||
* already connected to that client,
|
|
||||||
* that means the client isn't up in the
|
|
||||||
* first place and we can exit early
|
|
||||||
*/
|
|
||||||
ret = 0;
|
|
||||||
goto boot_done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "[%d|%s] sending configuration\n",
|
|
||||||
getpid(), my_client);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = vtysh_read_config(frr_config, dryrun);
|
|
||||||
if (ret) {
|
|
||||||
if (!no_fork)
|
|
||||||
fprintf(stderr,
|
|
||||||
"[%d|%s] Configuration file[%s] processing failure: %d\n",
|
|
||||||
getpid(), my_client, frr_config, ret);
|
|
||||||
else
|
|
||||||
fprintf(stderr,
|
|
||||||
"Configuration file[%s] processing failure: %d\n",
|
|
||||||
frr_config, ret);
|
|
||||||
if (no_error)
|
|
||||||
ret = 0;
|
|
||||||
} else if (!no_fork) {
|
|
||||||
fprintf(stderr, "[%d|%s] done\n", getpid(), my_client);
|
|
||||||
}
|
|
||||||
|
|
||||||
boot_done:
|
|
||||||
if (fork_pid != 0)
|
|
||||||
vtysh_unflock_config();
|
|
||||||
exit(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
vtysh_readline_init();
|
vtysh_readline_init();
|
||||||
|
|
||||||
vty_hello(vty);
|
vty_hello(vty);
|
||||||
|
Loading…
Reference in New Issue
Block a user