diff --git a/lib/command.c b/lib/command.c index 7a7ce3f5dc..e92251160f 100644 --- a/lib/command.c +++ b/lib/command.c @@ -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(); diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c index a7f86201de..56b0cb52e1 100644 --- a/lib/mgmt_fe_client.c +++ b/lib/mgmt_fe_client.c @@ -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); diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h index 511a5a94fe..aa9a74e27f 100644 --- a/lib/mgmt_fe_client.h +++ b/lib/mgmt_fe_client.h @@ -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 ***************************************************************/ diff --git a/lib/vty.c b/lib/vty.c index 52d2f2ff68..0a0b043195 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -21,6 +21,7 @@ #endif /* HAVE_LIBPCRE2_POSIX */ #include +#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; } diff --git a/lib/vty.h b/lib/vty.h index 9d2fd3bfc0..7a591ad172 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -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); diff --git a/mgmtd/mgmt.h b/mgmtd/mgmt.h index 603296bb38..f52d478bc2 100644 --- a/mgmtd/mgmt.h +++ b/mgmtd/mgmt.h @@ -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); diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c index ad9f40e2a5..a705990cac 100644 --- a/mgmtd/mgmt_main.c +++ b/mgmtd/mgmt_main.c @@ -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. */ diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index 7d6c8f206c..5cb172f3c9 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -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);