mgmtd: fix reading of config file[s]

Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
Christian Hopps 2023-05-09 09:19:24 -04:00
parent edafa64c30
commit a1d8c7a36e
8 changed files with 210 additions and 85 deletions

View File

@ -1283,6 +1283,7 @@ int command_config_read_one_line(struct vty *vty,
memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ);
ve->line_num = line_num;
ve->cmd_ret = ret;
if (!vty->error)
vty->error = list_new();

View File

@ -19,14 +19,6 @@
#include "lib/mgmt_fe_client_clippy.c"
#define MGMTD_FE_CLIENT_DBG(fmt, ...) \
DEBUGD(&mgmt_dbg_fe_client, "FE-CLIENT: %s:" fmt, __func__, \
##__VA_ARGS__)
#define MGMTD_FE_CLIENT_ERR(fmt, ...) \
zlog_err("FE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_DBG_FE_CLIENT_CHECK() \
DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_ALL)
struct mgmt_fe_client_ctx;
PREDECL_LIST(mgmt_sessions);

View File

@ -114,6 +114,17 @@ struct mgmt_fe_client_params {
Mgmtd__YangData **yang_data, size_t num_data);
};
extern struct debug mgmt_dbg_fe_client;
#define MGMTD_FE_CLIENT_DBG(fmt, ...) \
DEBUGD(&mgmt_dbg_fe_client, "FE-CLIENT: %s:" fmt, __func__, \
##__VA_ARGS__)
#define MGMTD_FE_CLIENT_ERR(fmt, ...) \
zlog_err("FE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_DBG_FE_CLIENT_CHECK() \
DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_ALL)
/***************************************************************
* API prototypes
***************************************************************/

206
lib/vty.c
View File

@ -21,6 +21,7 @@
#endif /* HAVE_LIBPCRE2_POSIX */
#include <stdio.h>
#include "debug.h"
#include "linklist.h"
#include "frrevent.h"
#include "buffer.h"
@ -128,6 +129,13 @@ static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
bool vty_log_commands;
static bool vty_log_commands_perm;
char const *const mgmt_daemons[] = {
#ifdef HAVE_STATICD
"staticd",
#endif
};
uint mgmt_daemons_count = array_size(mgmt_daemons);
void vty_mgmt_resume_response(struct vty *vty, bool success)
{
uint8_t header[4] = {0, 0, 0, 0};
@ -143,21 +151,26 @@ void vty_mgmt_resume_response(struct vty *vty, bool success)
ret = CMD_WARNING_CONFIG_FAILED;
vty->mgmt_req_pending = false;
header[3] = ret;
buffer_put(vty->obuf, header, 4);
/* XXX this is crashing */
// if (!vty->t_write && (vtysh_flush(vty) < 0))
if (!vty->t_write)
/* Try to flush results; exit if a write
* error occurs.
*/
return;
MGMTD_FE_CLIENT_DBG("resuming: %s:", success ? "succeeded" : "failed");
if (vty->type != VTY_FILE) {
header[3] = ret;
buffer_put(vty->obuf, header, 4);
if (!vty->t_write && (vtysh_flush(vty) < 0)) {
zlog_err("failed to vtysh_flush");
/* Try to flush results; exit if a write error occurs */
return;
}
}
if (vty->status == VTY_CLOSE)
vty_close(vty);
else
else if (vty->type != VTY_FILE)
vty_event(VTYSH_READ, vty);
else
/* should we assert here? */
zlog_err("mgmtd: unexpected resume while reading config file");
}
void vty_frame(struct vty *vty, const char *format, ...)
@ -2177,6 +2190,79 @@ void vty_pass_fd(struct vty *vty, int fd)
vty->pass_fd = fd;
}
bool mgmt_vty_read_configs(void)
{
char path[PATH_MAX];
struct vty *vty;
FILE *confp;
uint line_num = 0;
uint count = 0;
vty = vty_new();
vty->wfd = STDERR_FILENO;
vty->type = VTY_FILE;
vty->node = CONFIG_NODE;
vty->config = true;
vty->candidate_config = vty_shared_candidate_config;
vty->mgmt_locked_candidate_ds = true;
mgmt_candidate_ds_wr_locked = true;
for (uint index = 0; index < mgmt_daemons_count; index++) {
snprintf(path, sizeof(path), "%s/%s.conf", frr_sysconfdir,
mgmt_daemons[index]);
confp = vty_open_config(path, config_default);
if (!confp)
continue;
MGMTD_FE_CLIENT_DBG("mgmtd: reading config file %s", path);
/* Execute configuration file */
line_num = 0;
(void)config_from_file(vty, confp, &line_num);
count++;
}
MGMTD_FE_CLIENT_DBG(
"mgmtd: done with daemon configs, checking mgmtd config");
snprintf(path, sizeof(path), "%s/mgmtd.conf", frr_sysconfdir);
confp = vty_open_config(path, config_default);
if (!confp) {
char *orig;
MGMTD_FE_CLIENT_DBG("mgmtd: no mgmtd config file %s", path);
snprintf(path, sizeof(path), "%s/zebra.conf", frr_sysconfdir);
orig = XSTRDUP(MTYPE_TMP, host_config_get());
zlog_info("mgmtd: trying backup config file: %s", path);
confp = vty_open_config(path, config_default);
host_config_set(path);
XFREE(MTYPE_TMP, orig);
}
if (confp) {
line_num = 0;
(void)config_from_file(vty, confp, &line_num);
count++;
}
if (!count) {
MGMTD_FE_CLIENT_DBG("mgmtd: read no config files");
vty_close(vty);
} else {
MGMTD_FE_CLIENT_DBG("mgmtd: done reading all config files");
vty_read_file_finish(vty, vty->candidate_config);
}
vty->mgmt_locked_candidate_ds = false;
mgmt_candidate_ds_wr_locked = false;
return true;
}
static void vtysh_read(struct event *thread)
{
int ret;
@ -2323,6 +2409,8 @@ void vty_close(struct vty *vty)
int i;
bool was_stdio = false;
vty->status = VTY_CLOSE;
if (mgmt_lib_hndl) {
mgmt_fe_destroy_client_session(mgmt_lib_hndl,
vty->mgmt_client_id);
@ -2359,7 +2447,7 @@ void vty_close(struct vty *vty)
if (vty->fd != -1) {
if (vty->type == VTY_SHELL_SERV)
vtys_del(vtysh_sessions, vty);
else
else if (vty->type == VTY_TERM)
vtys_del(vty_sessions, vty);
}
@ -2413,10 +2501,7 @@ static void vty_timeout(struct event *thread)
/* Read up configuration file from file_name. */
void vty_read_file(struct nb_config *config, FILE *confp)
{
int ret;
struct vty *vty;
struct vty_error *ve;
struct listnode *node;
unsigned int line_num = 0;
vty = vty_new();
@ -2439,16 +2524,30 @@ void vty_read_file(struct nb_config *config, FILE *confp)
}
/* Execute configuration file */
ret = config_from_file(vty, confp, &line_num);
(void)config_from_file(vty, confp, &line_num);
vty_read_file_finish(vty, config);
}
void vty_read_file_finish(struct vty *vty, struct nb_config *config)
{
struct vty_error *ve;
struct listnode *node;
/* Flush any previous errors before printing messages below */
buffer_flush_all(vty->obuf, vty->wfd);
if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) {
for (ALL_LIST_ELEMENTS_RO(vty->error, node, ve)) {
const char *message = NULL;
char *nl;
switch (ret) {
switch (ve->cmd_ret) {
case CMD_SUCCESS:
message = "Command succeeded";
break;
case CMD_ERR_NOTHING_TODO:
message = "Nothing to do";
break;
case CMD_ERR_AMBIGUOUS:
message = "Ambiguous command";
break;
@ -2473,13 +2572,11 @@ void vty_read_file(struct nb_config *config, FILE *confp)
break;
}
for (ALL_LIST_ELEMENTS_RO(vty->error, node, ve)) {
nl = strchr(ve->error_buf, '\n');
if (nl)
*nl = '\0';
flog_err(EC_LIB_VTY, "%s on config line %u: %s",
message, ve->line_num, ve->error_buf);
}
nl = strchr(ve->error_buf, '\n');
if (nl)
*nl = '\0';
flog_err(EC_LIB_VTY, "%s on config line %u: %s", message,
ve->line_num, ve->error_buf);
}
/*
@ -2489,6 +2586,7 @@ void vty_read_file(struct nb_config *config, FILE *confp)
if (config == NULL) {
struct nb_context context = {};
char errmsg[BUFSIZ] = {0};
int ret;
context.client = NB_CLIENT_CLI;
context.user = vty;
@ -2559,15 +2657,12 @@ static FILE *vty_use_backup_config(const char *fullpath)
return ret;
}
/* Read up configuration file from file_name. */
bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir)
FILE *vty_open_config(const char *config_file, char *config_default_dir)
{
char cwd[MAXPATHLEN];
FILE *confp = NULL;
const char *fullpath;
char *tmp = NULL;
bool read_success = false;
/* If -f flag specified. */
if (config_file != NULL) {
@ -2631,7 +2726,7 @@ bool vty_read_config(struct nb_config *config, const char *config_file,
if (strstr(config_default_dir, "vtysh") == NULL) {
ret = stat(integrate_default, &conf_stat);
if (ret >= 0) {
read_success = true;
// read_success = true;
goto tmp_free_and_out;
}
}
@ -2659,42 +2754,29 @@ bool vty_read_config(struct nb_config *config, const char *config_file,
fullpath = config_default_dir;
}
vty_read_file(config, confp);
read_success = true;
fclose(confp);
host_config_set(fullpath);
tmp_free_and_out:
XFREE(MTYPE_TMP, tmp);
return read_success;
return confp;
}
static void update_xpath(struct vty *vty, const char *oldpath,
const char *newpath)
bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir)
{
int i;
FILE *confp;
for (i = 0; i < vty->xpath_index; i++) {
if (!frrstr_startswith(vty->xpath[i], oldpath))
break;
confp = vty_open_config(config_file, config_default_dir);
if (!confp)
return false;
char *tmp = frrstr_replace(vty->xpath[i], oldpath, newpath);
strlcpy(vty->xpath[i], tmp, sizeof(vty->xpath[0]));
XFREE(MTYPE_TMP, tmp);
}
}
vty_read_file(config, confp);
void vty_update_xpath(const char *oldpath, const char *newpath)
{
struct vty *vty;
fclose(confp);
frr_each (vtys, vtysh_sessions, vty)
update_xpath(vty, oldpath, newpath);
frr_each (vtys, vty_sessions, vty)
update_xpath(vty, oldpath, newpath);
return true;
}
int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
@ -2772,8 +2854,12 @@ int vty_config_node_exit(struct vty *vty)
{
vty->xpath_index = 0;
if (vty_mgmt_fe_enabled() && mgmt_candidate_ds_wr_locked &&
vty->mgmt_locked_candidate_ds) {
/*
* If we are not reading config file and we are mgmtd FE and we are
* locked then unlock.
*/
if (vty->type != VTY_FILE && vty_mgmt_fe_enabled() &&
mgmt_candidate_ds_wr_locked && vty->mgmt_locked_candidate_ds) {
if (vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE, false) !=
0) {
vty_out(vty, "Not able to unlock candidate DS\n");
@ -2808,6 +2894,16 @@ int vty_config_node_exit(struct vty *vty)
}
vty->config = false;
/*
* If this is a config file and we are dropping out of config end
* parsing.
*/
if (vty->type == VTY_FILE && vty->status != VTY_CLOSE) {
vty_out(vty, "exit from config node while reading config file");
vty->status = VTY_CLOSE;
}
return 1;
}

View File

@ -43,6 +43,7 @@ struct json_object;
struct vty_error {
char error_buf[VTY_BUFSIZ];
uint32_t line_num;
int cmd_ret;
};
struct vty_cfg_change {
@ -71,7 +72,11 @@ struct vty {
bool is_paged;
/* Is this vty connect to file or not */
enum { VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV } type;
enum { VTY_TERM, /* telnet conn or stdin/stdout UI */
VTY_FILE, /* reading and writing config files */
VTY_SHELL, /* vtysh client side UI */
VTY_SHELL_SERV, /* server-side vtysh connection */
} type;
/* Node status of this vty */
int node;
@ -298,10 +303,10 @@ static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
#define VTY_CHECK_XPATH \
do { \
if (vty->type != VTY_FILE && !vty->private_config \
&& vty->xpath_index > 0 \
&& !yang_dnode_exists(vty->candidate_config->dnode, \
VTY_CURR_XPATH)) { \
if (vty->type != VTY_FILE && !vty->private_config && \
vty->xpath_index > 0 && \
!yang_dnode_exists(vty->candidate_config->dnode, \
VTY_CURR_XPATH)) { \
vty_out(vty, \
"Current configuration object was deleted " \
"by another process.\n\n"); \
@ -337,6 +342,9 @@ struct vty_arg {
extern struct nb_config *vty_mgmt_candidate_config;
extern bool vty_log_commands;
extern char const *const mgmt_daemons[];
extern uint mgmt_daemons_count;
/* Prototypes. */
extern void vty_init(struct event_loop *m, bool do_command_logging);
extern void vty_init_vtysh(void);
@ -368,9 +376,11 @@ extern void vty_json_empty(struct vty *vty);
*/
extern void vty_pass_fd(struct vty *vty, int fd);
extern FILE *vty_open_config(const char *config_file, char *config_default_dir);
extern bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir);
extern void vty_read_file(struct nb_config *config, FILE *confp);
extern void vty_read_file_finish(struct vty *vty, struct nb_config *config);
extern void vty_time_print(struct vty *, int);
extern void vty_serv_sock(const char *, unsigned short, const char *);
extern void vty_close(struct vty *);
@ -391,6 +401,9 @@ extern void vty_stdio_close(void);
extern void vty_init_mgmt_fe(void);
extern bool vty_mgmt_fe_enabled(void);
extern bool vty_mgmt_should_process_cli_changes(struct vty *vty);
extern bool mgmt_vty_read_configs(void);
extern int vty_mgmt_send_config_data(struct vty *vty);
extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only,
bool abort);

View File

@ -68,8 +68,6 @@ struct mgmt_master {
};
extern struct mgmt_master *mm;
extern char const *const mgmt_daemons[];
extern uint mgmt_daemons_count;
/* Inline functions */
static inline unsigned long timeval_elapsed(struct timeval a, struct timeval b)
@ -102,7 +100,8 @@ extern void mgmt_reset(void);
extern time_t mgmt_clock(void);
extern int mgmt_config_write(struct vty *vty);
extern struct vty *mgmt_vty_read_config(const char *config_file,
char *config_default_dir);
extern void mgmt_master_init(struct event_loop *master, const int buffer_size);
extern void mgmt_init(void);

View File

@ -17,20 +17,12 @@
#include "routing_nb.h"
char const *const mgmt_daemons[] = {
#ifdef HAVE_STATICD
"staticd",
#endif
};
uint mgmt_daemons_count = array_size(mgmt_daemons);
/* mgmt options, we use GNU getopt library. */
static const struct option longopts[] = {
{"skip_runas", no_argument, NULL, 'S'},
{"no_zebra", no_argument, NULL, 'Z'},
{"socket_size", required_argument, NULL, 's'},
{0}
};
{0}};
static void mgmt_exit(int);
static void mgmt_vrf_terminate(void);
@ -201,8 +193,11 @@ static void mgmt_vrf_terminate(void)
* all individual Backend clients.
*/
static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
&frr_filter_info, &frr_interface_info, &frr_route_map_info,
&frr_routing_info, &frr_vrf_info,
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_routing_info,
&frr_vrf_info,
/*
* YANG module info supported by backend clients get added here.
* NOTE: Always set .ignore_cbs true for to avoid validating
@ -221,11 +216,12 @@ FRR_DAEMON_INFO(mgmtd, MGMTD, .vty_port = MGMTD_VTY_PORT,
.signals = mgmt_signals, .n_signals = array_size(mgmt_signals),
.privs = &mgmt_privs, .yang_modules = mgmt_yang_modules,
.n_yang_modules = array_size(mgmt_yang_modules),
);
.n_yang_modules = array_size(mgmt_yang_modules));
#define DEPRECATED_OPTIONS ""
struct frr_daemon_info *mgmt_daemon_info = &mgmtd_di;
/* Main routine of mgmt. Treatment of argument and start mgmt finite
* state machine is handled at here.
*/

View File

@ -10,6 +10,7 @@
#include "command.h"
#include "json.h"
#include "network.h"
#include "northbound_cli.h"
#include "mgmtd/mgmt.h"
@ -20,6 +21,8 @@
#include "mgmtd/mgmt_vty_clippy.c"
extern struct frr_daemon_info *mgmt_daemon_info;
DEFPY(show_mgmt_be_adapter,
show_mgmt_be_adapter_cmd,
"show mgmt backend-adapter all",
@ -451,6 +454,16 @@ DEFPY(debug_mgmt, debug_mgmt_cmd,
return CMD_SUCCESS;
}
/*
* We need an event driven file reader for reading in config files.
*/
static void mgmt_config_read_in(struct event *event)
{
mgmt_vty_read_configs();
}
#if 0
/*
* Analog of `frr_config_read_in()`, instead of our config file though we loop
* over all daemons that have transitioned to mgmtd, loading their configs
@ -477,6 +490,7 @@ static int mgmt_config_pre_hook(struct event_loop *loop)
}
return 0;
}
#endif
void mgmt_vty_init(void)
{
@ -491,7 +505,10 @@ void mgmt_vty_init(void)
static_vty_init();
#endif
hook_register(frr_config_pre, mgmt_config_pre_hook);
// hook_register(frr_config_pre, mgmt_config_pre_hook);
event_add_event(mm->master, mgmt_config_read_in, NULL, 0,
&mgmt_daemon_info->read_in);
install_node(&debug_node);