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); memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ);
ve->line_num = line_num; ve->line_num = line_num;
ve->cmd_ret = ret;
if (!vty->error) if (!vty->error)
vty->error = list_new(); vty->error = list_new();

View File

@ -19,14 +19,6 @@
#include "lib/mgmt_fe_client_clippy.c" #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; struct mgmt_fe_client_ctx;
PREDECL_LIST(mgmt_sessions); PREDECL_LIST(mgmt_sessions);

View File

@ -114,6 +114,17 @@ struct mgmt_fe_client_params {
Mgmtd__YangData **yang_data, size_t num_data); 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 * API prototypes
***************************************************************/ ***************************************************************/

206
lib/vty.c
View File

@ -21,6 +21,7 @@
#endif /* HAVE_LIBPCRE2_POSIX */ #endif /* HAVE_LIBPCRE2_POSIX */
#include <stdio.h> #include <stdio.h>
#include "debug.h"
#include "linklist.h" #include "linklist.h"
#include "frrevent.h" #include "frrevent.h"
#include "buffer.h" #include "buffer.h"
@ -128,6 +129,13 @@ static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
bool vty_log_commands; bool vty_log_commands;
static bool vty_log_commands_perm; 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) void vty_mgmt_resume_response(struct vty *vty, bool success)
{ {
uint8_t header[4] = {0, 0, 0, 0}; 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; ret = CMD_WARNING_CONFIG_FAILED;
vty->mgmt_req_pending = false; vty->mgmt_req_pending = false;
header[3] = ret;
buffer_put(vty->obuf, header, 4);
/* XXX this is crashing */ MGMTD_FE_CLIENT_DBG("resuming: %s:", success ? "succeeded" : "failed");
// if (!vty->t_write && (vtysh_flush(vty) < 0))
if (!vty->t_write) if (vty->type != VTY_FILE) {
/* Try to flush results; exit if a write header[3] = ret;
* error occurs. buffer_put(vty->obuf, header, 4);
*/ if (!vty->t_write && (vtysh_flush(vty) < 0)) {
return; zlog_err("failed to vtysh_flush");
/* Try to flush results; exit if a write error occurs */
return;
}
}
if (vty->status == VTY_CLOSE) if (vty->status == VTY_CLOSE)
vty_close(vty); vty_close(vty);
else else if (vty->type != VTY_FILE)
vty_event(VTYSH_READ, vty); 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, ...) 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; 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) static void vtysh_read(struct event *thread)
{ {
int ret; int ret;
@ -2323,6 +2409,8 @@ void vty_close(struct vty *vty)
int i; int i;
bool was_stdio = false; bool was_stdio = false;
vty->status = VTY_CLOSE;
if (mgmt_lib_hndl) { if (mgmt_lib_hndl) {
mgmt_fe_destroy_client_session(mgmt_lib_hndl, mgmt_fe_destroy_client_session(mgmt_lib_hndl,
vty->mgmt_client_id); vty->mgmt_client_id);
@ -2359,7 +2447,7 @@ void vty_close(struct vty *vty)
if (vty->fd != -1) { if (vty->fd != -1) {
if (vty->type == VTY_SHELL_SERV) if (vty->type == VTY_SHELL_SERV)
vtys_del(vtysh_sessions, vty); vtys_del(vtysh_sessions, vty);
else else if (vty->type == VTY_TERM)
vtys_del(vty_sessions, vty); vtys_del(vty_sessions, vty);
} }
@ -2413,10 +2501,7 @@ static void vty_timeout(struct event *thread)
/* Read up configuration file from file_name. */ /* Read up configuration file from file_name. */
void vty_read_file(struct nb_config *config, FILE *confp) void vty_read_file(struct nb_config *config, FILE *confp)
{ {
int ret;
struct vty *vty; struct vty *vty;
struct vty_error *ve;
struct listnode *node;
unsigned int line_num = 0; unsigned int line_num = 0;
vty = vty_new(); vty = vty_new();
@ -2439,16 +2524,30 @@ void vty_read_file(struct nb_config *config, FILE *confp)
} }
/* Execute configuration file */ /* 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 */ /* Flush any previous errors before printing messages below */
buffer_flush_all(vty->obuf, vty->wfd); 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; const char *message = NULL;
char *nl; 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: case CMD_ERR_AMBIGUOUS:
message = "Ambiguous command"; message = "Ambiguous command";
break; break;
@ -2473,13 +2572,11 @@ void vty_read_file(struct nb_config *config, FILE *confp)
break; break;
} }
for (ALL_LIST_ELEMENTS_RO(vty->error, node, ve)) { nl = strchr(ve->error_buf, '\n');
nl = strchr(ve->error_buf, '\n'); if (nl)
if (nl) *nl = '\0';
*nl = '\0'; flog_err(EC_LIB_VTY, "%s on config line %u: %s", message,
flog_err(EC_LIB_VTY, "%s on config line %u: %s", ve->line_num, ve->error_buf);
message, ve->line_num, ve->error_buf);
}
} }
/* /*
@ -2489,6 +2586,7 @@ void vty_read_file(struct nb_config *config, FILE *confp)
if (config == NULL) { if (config == NULL) {
struct nb_context context = {}; struct nb_context context = {};
char errmsg[BUFSIZ] = {0}; char errmsg[BUFSIZ] = {0};
int ret;
context.client = NB_CLIENT_CLI; context.client = NB_CLIENT_CLI;
context.user = vty; context.user = vty;
@ -2559,15 +2657,12 @@ static FILE *vty_use_backup_config(const char *fullpath)
return ret; return ret;
} }
/* Read up configuration file from file_name. */ FILE *vty_open_config(const char *config_file, char *config_default_dir)
bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir)
{ {
char cwd[MAXPATHLEN]; char cwd[MAXPATHLEN];
FILE *confp = NULL; FILE *confp = NULL;
const char *fullpath; const char *fullpath;
char *tmp = NULL; char *tmp = NULL;
bool read_success = false;
/* If -f flag specified. */ /* If -f flag specified. */
if (config_file != NULL) { 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) { if (strstr(config_default_dir, "vtysh") == NULL) {
ret = stat(integrate_default, &conf_stat); ret = stat(integrate_default, &conf_stat);
if (ret >= 0) { if (ret >= 0) {
read_success = true; // read_success = true;
goto tmp_free_and_out; 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; fullpath = config_default_dir;
} }
vty_read_file(config, confp);
read_success = true;
fclose(confp);
host_config_set(fullpath); host_config_set(fullpath);
tmp_free_and_out: tmp_free_and_out:
XFREE(MTYPE_TMP, tmp); 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++) { confp = vty_open_config(config_file, config_default_dir);
if (!frrstr_startswith(vty->xpath[i], oldpath)) if (!confp)
break; return false;
char *tmp = frrstr_replace(vty->xpath[i], oldpath, newpath); vty_read_file(config, confp);
strlcpy(vty->xpath[i], tmp, sizeof(vty->xpath[0]));
XFREE(MTYPE_TMP, tmp);
}
}
void vty_update_xpath(const char *oldpath, const char *newpath) fclose(confp);
{
struct vty *vty;
frr_each (vtys, vtysh_sessions, vty) return true;
update_xpath(vty, oldpath, newpath);
frr_each (vtys, vty_sessions, vty)
update_xpath(vty, oldpath, newpath);
} }
int vty_config_enter(struct vty *vty, bool private_config, bool exclusive) 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; 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) != if (vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE, false) !=
0) { 0) {
vty_out(vty, "Not able to unlock candidate DS\n"); 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; 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; return 1;
} }

View File

@ -43,6 +43,7 @@ struct json_object;
struct vty_error { struct vty_error {
char error_buf[VTY_BUFSIZ]; char error_buf[VTY_BUFSIZ];
uint32_t line_num; uint32_t line_num;
int cmd_ret;
}; };
struct vty_cfg_change { struct vty_cfg_change {
@ -71,7 +72,11 @@ struct vty {
bool is_paged; bool is_paged;
/* Is this vty connect to file or not */ /* 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 */ /* Node status of this vty */
int node; int node;
@ -298,10 +303,10 @@ static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
#define VTY_CHECK_XPATH \ #define VTY_CHECK_XPATH \
do { \ do { \
if (vty->type != VTY_FILE && !vty->private_config \ if (vty->type != VTY_FILE && !vty->private_config && \
&& vty->xpath_index > 0 \ vty->xpath_index > 0 && \
&& !yang_dnode_exists(vty->candidate_config->dnode, \ !yang_dnode_exists(vty->candidate_config->dnode, \
VTY_CURR_XPATH)) { \ VTY_CURR_XPATH)) { \
vty_out(vty, \ vty_out(vty, \
"Current configuration object was deleted " \ "Current configuration object was deleted " \
"by another process.\n\n"); \ "by another process.\n\n"); \
@ -337,6 +342,9 @@ struct vty_arg {
extern struct nb_config *vty_mgmt_candidate_config; extern struct nb_config *vty_mgmt_candidate_config;
extern bool vty_log_commands; extern bool vty_log_commands;
extern char const *const mgmt_daemons[];
extern uint mgmt_daemons_count;
/* Prototypes. */ /* Prototypes. */
extern void vty_init(struct event_loop *m, bool do_command_logging); extern void vty_init(struct event_loop *m, bool do_command_logging);
extern void vty_init_vtysh(void); 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 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, extern bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir); char *config_default_dir);
extern void vty_read_file(struct nb_config *config, FILE *confp); 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_time_print(struct vty *, int);
extern void vty_serv_sock(const char *, unsigned short, const char *); extern void vty_serv_sock(const char *, unsigned short, const char *);
extern void vty_close(struct vty *); extern void vty_close(struct vty *);
@ -391,6 +401,9 @@ extern void vty_stdio_close(void);
extern void vty_init_mgmt_fe(void); extern void vty_init_mgmt_fe(void);
extern bool vty_mgmt_fe_enabled(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_config_data(struct vty *vty);
extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only, extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only,
bool abort); bool abort);

View File

@ -68,8 +68,6 @@ struct mgmt_master {
}; };
extern struct mgmt_master *mm; extern struct mgmt_master *mm;
extern char const *const mgmt_daemons[];
extern uint mgmt_daemons_count;
/* Inline functions */ /* Inline functions */
static inline unsigned long timeval_elapsed(struct timeval a, struct timeval b) 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 time_t mgmt_clock(void);
extern int mgmt_config_write(struct vty *vty); 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_master_init(struct event_loop *master, const int buffer_size);
extern void mgmt_init(void); extern void mgmt_init(void);

View File

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

View File

@ -10,6 +10,7 @@
#include "command.h" #include "command.h"
#include "json.h" #include "json.h"
#include "network.h"
#include "northbound_cli.h" #include "northbound_cli.h"
#include "mgmtd/mgmt.h" #include "mgmtd/mgmt.h"
@ -20,6 +21,8 @@
#include "mgmtd/mgmt_vty_clippy.c" #include "mgmtd/mgmt_vty_clippy.c"
extern struct frr_daemon_info *mgmt_daemon_info;
DEFPY(show_mgmt_be_adapter, DEFPY(show_mgmt_be_adapter,
show_mgmt_be_adapter_cmd, show_mgmt_be_adapter_cmd,
"show mgmt backend-adapter all", "show mgmt backend-adapter all",
@ -451,6 +454,16 @@ DEFPY(debug_mgmt, debug_mgmt_cmd,
return CMD_SUCCESS; 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 * 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 * 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; return 0;
} }
#endif
void mgmt_vty_init(void) void mgmt_vty_init(void)
{ {
@ -491,7 +505,10 @@ void mgmt_vty_init(void)
static_vty_init(); static_vty_init();
#endif #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); install_node(&debug_node);