diff options
Diffstat (limited to 'lib/vty.c')
| -rw-r--r-- | lib/vty.c | 1123 |
1 files changed, 789 insertions, 334 deletions
@@ -6,6 +6,8 @@ #include <zebra.h> +#include <fcntl.h> +#include <sys/stat.h> #include <lib/version.h> #include <sys/types.h> #include <sys/types.h> @@ -21,6 +23,7 @@ #endif /* HAVE_LIBPCRE2_POSIX */ #include <stdio.h> +#include "debug.h" #include "linklist.h" #include "frrevent.h" #include "buffer.h" @@ -43,6 +46,8 @@ #include <arpa/telnet.h> #include <termios.h> +#include "lib/config_paths.h" + #include "lib/vty_clippy.c" DEFINE_MTYPE_STATIC(LIB, VTY, "VTY"); @@ -67,19 +72,11 @@ enum vty_event { struct nb_config *vty_mgmt_candidate_config; -static uintptr_t mgmt_lib_hndl; +static struct mgmt_fe_client *mgmt_fe_client; static bool mgmt_fe_connected; -static bool mgmt_candidate_ds_wr_locked; static uint64_t mgmt_client_id_next; static uint64_t mgmt_last_req_id = UINT64_MAX; -static bool vty_debug; -#define VTY_DBG(fmt, ...) \ - do { \ - if (vty_debug) \ - zlog_debug(fmt, ##__VA_ARGS__); \ - } while (0) - PREDECL_DLIST(vtyservs); struct vty_serv { @@ -125,37 +122,86 @@ static int no_password_check = 0; /* Integrated configuration file path */ static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; -static bool do_log_commands; -static bool do_log_commands_perm; +bool vty_log_commands; +static bool vty_log_commands_perm; + +char const *const mgmt_daemons[] = { + "zebra", +#ifdef HAVE_RIPD + "ripd", +#endif +#ifdef HAVE_RIPNGD + "ripngd", +#endif +#ifdef HAVE_STATICD + "staticd", +#endif +}; +uint mgmt_daemons_count = array_size(mgmt_daemons); + + +static int vty_mgmt_lock_candidate_inline(struct vty *vty) +{ + assert(!vty->mgmt_locked_candidate_ds); + (void)vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE, true, true); + return vty->mgmt_locked_candidate_ds ? 0 : -1; +} + +static int vty_mgmt_unlock_candidate_inline(struct vty *vty) +{ + assert(vty->mgmt_locked_candidate_ds); + (void)vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE, false, true); + return vty->mgmt_locked_candidate_ds ? -1 : 0; +} + +static int vty_mgmt_lock_running_inline(struct vty *vty) +{ + assert(!vty->mgmt_locked_running_ds); + (void)vty_mgmt_send_lockds_req(vty, MGMTD_DS_RUNNING, true, true); + return vty->mgmt_locked_running_ds ? 0 : -1; +} -void vty_mgmt_resume_response(struct vty *vty, bool success) +static int vty_mgmt_unlock_running_inline(struct vty *vty) +{ + assert(vty->mgmt_locked_running_ds); + (void)vty_mgmt_send_lockds_req(vty, MGMTD_DS_RUNNING, false, true); + return vty->mgmt_locked_running_ds ? -1 : 0; +} + +void vty_mgmt_resume_response(struct vty *vty, int ret) { uint8_t header[4] = {0, 0, 0, 0}; - int ret = CMD_SUCCESS; - if (!vty->mgmt_req_pending) { + if (!vty->mgmt_req_pending_cmd) { zlog_err( - "vty response called without setting mgmt_req_pending"); + "vty resume response called without mgmt_req_pending_cmd"); return; } - if (!success) - ret = CMD_WARNING_CONFIG_FAILED; + debug_fe_client("resuming CLI cmd after %s on vty session-id: %" PRIu64 + " with '%s'", + vty->mgmt_req_pending_cmd, vty->mgmt_session_id, + ret == CMD_SUCCESS ? "success" : "failed"); - vty->mgmt_req_pending = false; - header[3] = ret; - buffer_put(vty->obuf, header, 4); + vty->mgmt_req_pending_cmd = NULL; - if (!vty->t_write && (vtysh_flush(vty) < 0)) - /* Try to flush results; exit if a write - * error occurs. - */ - return; + 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, ...) @@ -343,11 +389,14 @@ int vty_json_no_pretty(struct vty *vty, struct json_object *json) return vty_json_helper(vty, json, JSON_C_TO_STRING_NOSLASHESCAPE); } -void vty_json_empty(struct vty *vty) +void vty_json_empty(struct vty *vty, struct json_object *json) { - json_object *json = json_object_new_object(); + json_object *jsonobj = json; + + if (!json) + jsonobj = json_object_new_object(); - vty_json(vty, json); + vty_json(vty, jsonobj); } /* Output current time to the vty. */ @@ -508,7 +557,7 @@ static int vty_command(struct vty *vty, char *buf) /* * Log non empty command lines */ - if (do_log_commands && + if (vty_log_commands && strncmp(buf, "echo PING", strlen("echo PING")) != 0) cp = buf; if (cp != NULL) { @@ -1525,7 +1574,7 @@ static void vty_read(struct event *thread) break; case '\r': vty->escape = VTY_CR; - /* fallthru */ + fallthrough; case '\n': vty_out(vty, "\n"); buffer_flush_available(vty->obuf, vty->wfd); @@ -1632,14 +1681,16 @@ struct vty *vty_new(void) new->max = VTY_BUFSIZ; new->pass_fd = -1; - if (mgmt_lib_hndl) { + if (mgmt_fe_client) { + if (!mgmt_client_id_next) + mgmt_client_id_next++; new->mgmt_client_id = mgmt_client_id_next++; - if (mgmt_fe_create_client_session( - mgmt_lib_hndl, new->mgmt_client_id, - (uintptr_t) new) != MGMTD_SUCCESS) - zlog_err( - "Failed to open a MGMTD Frontend session for VTY session %p!!", - new); + new->mgmt_session_id = 0; + mgmt_fe_create_client_session( + mgmt_fe_client, new->mgmt_client_id, (uintptr_t) new); + /* we short-circuit create the session so it must be set now */ + assertf(new->mgmt_session_id != 0, + "Failed to create client session for VTY"); } return new; @@ -2173,6 +2224,77 @@ 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; + uint index; + + vty = vty_new(); + vty->wfd = STDERR_FILENO; + vty->type = VTY_FILE; + vty->node = CONFIG_NODE; + vty->config = true; + vty->pending_allowed = true; + + vty->candidate_config = vty_shared_candidate_config; + + vty_mgmt_lock_candidate_inline(vty); + vty_mgmt_lock_running_inline(vty); + + for (index = 0; index < array_size(mgmt_daemons); index++) { + snprintf(path, sizeof(path), "%s/%s.conf", frr_sysconfdir, + mgmt_daemons[index]); + + confp = vty_open_config(path, config_default); + if (!confp) + continue; + + zlog_info("mgmtd: reading config file: %s", path); + + /* Execute configuration file */ + line_num = 0; + (void)config_from_file(vty, confp, &line_num); + count++; + + fclose(confp); + } + + snprintf(path, sizeof(path), "%s/mgmtd.conf", frr_sysconfdir); + confp = vty_open_config(path, config_default); + if (confp) { + zlog_info("mgmtd: reading config file: %s", path); + + line_num = 0; + (void)config_from_file(vty, confp, &line_num); + count++; + + fclose(confp); + } + + /* Conditionally unlock as the config file may have "exit"d early which + * would then have unlocked things. + */ + if (vty->mgmt_locked_running_ds) + vty_mgmt_unlock_running_inline(vty); + if (vty->mgmt_locked_candidate_ds) + vty_mgmt_unlock_candidate_inline(vty); + + vty->pending_allowed = false; + + if (!count) + vty_close(vty); + else + vty_read_file_finish(vty, NULL); + + zlog_info("mgmtd: finished reading config files"); + + return true; +} + static void vtysh_read(struct event *thread) { int ret; @@ -2186,6 +2308,19 @@ static void vtysh_read(struct event *thread) sock = EVENT_FD(thread); vty = EVENT_ARG(thread); + /* + * This code looks like it can read multiple commands from the `buf` + * value returned by read(); however, it cannot in some cases. + * + * There are multiple paths out of the "copying to vty->buf" loop, which + * lose any content not yet copied from the stack `buf`, `passfd`, + * `CMD_SUSPEND` and finally if a front-end for mgmtd (generally this + * would be mgmtd itself). So these code paths are counting on vtysh not + * sending us more than 1 command line before waiting on the reply to + * that command. + */ + assert(vty->type == VTY_SHELL_SERV); + if ((nbytes = read(sock, buf, VTY_READ_BUFSIZ)) <= 0) { if (nbytes < 0) { if (ERRNO_IO_RETRY(errno)) { @@ -2229,8 +2364,7 @@ static void vtysh_read(struct event *thread) printf("result: %d\n", ret); printf("vtysh node: %d\n", vty->node); #endif /* VTYSH_DEBUG */ - - if (vty->pass_fd != -1) { + if (vty->pass_fd >= 0) { memset(vty->pass_fd_status, 0, 4); vty->pass_fd_status[3] = ret; vty->status = VTY_PASSFD; @@ -2248,6 +2382,13 @@ static void vtysh_read(struct event *thread) * => skip vty_event(VTYSH_READ, vty)! */ return; + } else { + assertf(vty->status != VTY_PASSFD, + "%p address=%s passfd=%d", vty, + vty->address, vty->pass_fd); + + /* normalize other invalid values */ + vty->pass_fd = -1; } /* hack for asynchronous "write integrated" @@ -2260,8 +2401,12 @@ static void vtysh_read(struct event *thread) /* with new infra we need to stop response till * we get response through callback. */ - if (vty->mgmt_req_pending) + if (vty->mgmt_req_pending_cmd) { + debug_fe_client("postpone CLI response pending mgmtd %s on vty session-id %" PRIu64, + vty->mgmt_req_pending_cmd, + vty->mgmt_session_id); return; + } /* warning: watchfrr hardcodes this result write */ @@ -2292,7 +2437,7 @@ static void vtysh_write(struct event *thread) #endif /* VTYSH */ /* Determine address family to bind. */ -void vty_serv_sock(const char *addr, unsigned short port, const char *path) +void vty_serv_start(const char *addr, unsigned short port, const char *path) { /* If port is set to 0, do not listen on TCP/IP at all! */ if (port) @@ -2303,6 +2448,20 @@ void vty_serv_sock(const char *addr, unsigned short port, const char *path) #endif /* VTYSH */ } +void vty_serv_stop(void) +{ + struct vty_serv *vtyserv; + + while ((vtyserv = vtyservs_pop(vty_servs))) { + EVENT_OFF(vtyserv->t_accept); + close(vtyserv->sock); + XFREE(MTYPE_VTY_SERV, vtyserv); + } + + vtyservs_fini(vty_servs); + vtyservs_init(vty_servs); +} + static void vty_error_delete(void *arg) { struct vty_error *ve = arg; @@ -2319,15 +2478,26 @@ void vty_close(struct vty *vty) int i; bool was_stdio = false; - if (mgmt_lib_hndl) { - mgmt_fe_destroy_client_session(mgmt_lib_hndl, - vty->mgmt_client_id); - vty->mgmt_session_id = 0; - } + vty->status = VTY_CLOSE; + + /* + * If we reach here with pending config to commit we will be losing it + * so warn the user. + */ + if (vty->mgmt_num_pending_setcfg) + log_err_fe_client( + "vty closed, uncommitted config will be lost."); /* Drop out of configure / transaction if needed. */ vty_config_exit(vty); + if (mgmt_fe_client && vty->mgmt_session_id) { + debug_fe_client("closing vty session"); + mgmt_fe_destroy_client_session(mgmt_fe_client, + vty->mgmt_client_id); + vty->mgmt_session_id = 0; + } + /* Cancel threads.*/ EVENT_OFF(vty->t_read); EVENT_OFF(vty->t_write); @@ -2355,7 +2525,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); } @@ -2374,6 +2544,7 @@ void vty_close(struct vty *vty) if (vty->fd == STDIN_FILENO) was_stdio = true; + XFREE(MTYPE_TMP, vty->pending_cmds_buf); XFREE(MTYPE_VTY, vty->buf); if (vty->error) { @@ -2409,10 +2580,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(); @@ -2435,16 +2603,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; @@ -2469,13 +2651,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); } /* @@ -2485,6 +2665,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; @@ -2555,15 +2736,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) { @@ -2626,10 +2804,8 @@ 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; + if (ret >= 0) goto tmp_free_and_out; - } } #endif /* VTYSH */ confp = fopen(config_default_dir, "r"); @@ -2655,66 +2831,66 @@ 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) +int vty_config_enter(struct vty *vty, bool private_config, bool exclusive, + bool file_lock) { - if (exclusive && nb_running_lock(NB_CLIENT_CLI, vty)) { + if (exclusive && !vty_mgmt_fe_enabled() && + nb_running_lock(NB_CLIENT_CLI, vty)) { vty_out(vty, "%% Configuration is locked by other client\n"); return CMD_WARNING; } - if (vty_mgmt_fe_enabled()) { - if (!mgmt_candidate_ds_wr_locked) { - if (vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE, - true) != 0) { - vty_out(vty, "Not able to lock candidate DS\n"); - return CMD_WARNING; - } - } else { + /* + * We only need to do a lock when reading a config file as we will be + * sending a batch of setcfg changes followed by a single commit + * message. For user interactive mode we are doing implicit commits + * those will obtain the lock (or not) when they try and commit. + */ + if (file_lock && vty_mgmt_fe_enabled() && !private_config) { + if (vty_mgmt_lock_candidate_inline(vty)) { vty_out(vty, - "Candidate DS already locked by different session\n"); - return CMD_WARNING; + "%% Can't enter config; candidate datastore locked by another session\n"); + return CMD_WARNING_CONFIG_FAILED; } + if (vty_mgmt_lock_running_inline(vty)) { + vty_out(vty, + "%% Can't enter config; running datastore locked by another session\n"); + vty_mgmt_unlock_candidate_inline(vty); + return CMD_WARNING_CONFIG_FAILED; + } + assert(vty->mgmt_locked_candidate_ds); + assert(vty->mgmt_locked_running_ds); - vty->mgmt_locked_candidate_ds = true; - mgmt_candidate_ds_wr_locked = true; + /* + * As datastores are locked explicitly, we don't need implicit + * commits and should allow pending changes. + */ + vty->pending_allowed = true; } vty->node = CONFIG_NODE; @@ -2727,23 +2903,24 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive) vty->candidate_config_base = nb_config_dup(running_config); vty_out(vty, "Warning: uncommitted changes will be discarded on exit.\n\n"); - } else { - /* - * NOTE: On the MGMTD daemon we point the VTY candidate DS to - * the global MGMTD candidate DS. Else we point to the VTY - * Shared Candidate Config. - */ - vty->candidate_config = vty_mgmt_candidate_config - ? vty_mgmt_candidate_config - : vty_shared_candidate_config; - if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) - vty->candidate_config_base = - nb_config_dup(running_config); + return CMD_SUCCESS; } + /* + * NOTE: On the MGMTD daemon we point the VTY candidate DS to + * the global MGMTD candidate DS. Else we point to the VTY + * Shared Candidate Config. + */ + vty->candidate_config = vty_mgmt_candidate_config + ? vty_mgmt_candidate_config + : vty_shared_candidate_config; + if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) + vty->candidate_config_base = nb_config_dup(running_config); + return CMD_SUCCESS; } + void vty_config_exit(struct vty *vty) { enum node_type node = vty->node; @@ -2768,17 +2945,15 @@ 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 (vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE, false) != - 0) { - vty_out(vty, "Not able to unlock candidate DS\n"); - return CMD_WARNING; - } + /* TODO: could we check for un-commited changes here? */ - vty->mgmt_locked_candidate_ds = false; - mgmt_candidate_ds_wr_locked = false; - } + vty->pending_allowed = false; + + if (vty->mgmt_locked_running_ds) + vty_mgmt_unlock_running_inline(vty); + + if (vty->mgmt_locked_candidate_ds) + vty_mgmt_unlock_candidate_inline(vty); /* Perform any pending commits. */ (void)nb_cli_pending_commit_check(vty); @@ -2804,6 +2979,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; } @@ -3160,15 +3345,15 @@ DEFPY (log_commands, "Log all commands\n") { if (no) { - if (do_log_commands_perm) { + if (vty_log_commands_perm) { vty_out(vty, "Daemon started with permanent logging turned on for commands, ignoring\n"); return CMD_WARNING; } - do_log_commands = false; + vty_log_commands = false; } else - do_log_commands = true; + vty_log_commands = true; return CMD_SUCCESS; } @@ -3196,7 +3381,7 @@ static int vty_config_write(struct vty *vty) vty_endframe(vty, "exit\n"); - if (do_log_commands) + if (vty_log_commands) vty_out(vty, "log commands\n"); vty_out(vty, "!\n"); @@ -3277,25 +3462,42 @@ void vty_init_vtysh(void) /* currently nothing to do, but likely to have future use */ } -static void vty_mgmt_server_connected(uintptr_t lib_hndl, uintptr_t usr_data, - bool connected) -{ - VTY_DBG("%sGot %sconnected %s MGMTD Frontend Server", - !connected ? "ERROR: " : "", !connected ? "dis: " : "", - !connected ? "from" : "to"); - mgmt_fe_connected = connected; +/* + * These functions allow for CLI handling to be placed inside daemons; however, + * currently they are only used by mgmtd, with mgmtd having each daemons CLI + * functionality linked into it. This design choice was taken for efficiency. + */ + +static void vty_mgmt_server_connected(struct mgmt_fe_client *client, + uintptr_t usr_data, bool connected) +{ + debug_fe_client("Got %sconnected %s MGMTD Frontend Server", + !connected ? "dis: " : "", !connected ? "from" : "to"); /* - * TODO: Setup or teardown front-end sessions for existing - * VTY connections. + * We should not have any sessions for connecting or disconnecting case. + * The fe client library will delete all session on disconnect before + * calling us. */ + assert(mgmt_fe_client_session_count(client) == 0); + + mgmt_fe_connected = connected; + + /* Start or stop listening for vty connections */ + if (connected) + frr_vty_serv_start(); + else + frr_vty_serv_stop(); } -static void vty_mgmt_session_created(uintptr_t lib_hndl, uintptr_t usr_data, - uint64_t client_id, bool create, - bool success, uintptr_t session_id, - uintptr_t session_ctx) +/* + * A session has successfully been created for a vty. + */ +static void vty_mgmt_session_notify(struct mgmt_fe_client *client, + uintptr_t usr_data, uint64_t client_id, + bool create, bool success, + uintptr_t session_id, uintptr_t session_ctx) { struct vty *vty; @@ -3307,40 +3509,58 @@ static void vty_mgmt_session_created(uintptr_t lib_hndl, uintptr_t usr_data, return; } - VTY_DBG("%s session for client %" PRIu64 " successfully", - create ? "Created" : "Destroyed", client_id); - if (create) + debug_fe_client("%s session for client %" PRIu64 " successfully", + create ? "Created" : "Destroyed", client_id); + + if (create) { + assert(session_id != 0); vty->mgmt_session_id = session_id; + } else { + vty->mgmt_session_id = 0; + /* We may come here by way of vty_close() and short-circuits */ + if (vty->status != VTY_CLOSE) + vty_close(vty); + } } -static void vty_mgmt_ds_lock_notified(uintptr_t lib_hndl, uintptr_t usr_data, - uint64_t client_id, uintptr_t session_id, +static void vty_mgmt_ds_lock_notified(struct mgmt_fe_client *client, + uintptr_t usr_data, uint64_t client_id, + uintptr_t session_id, uintptr_t session_ctx, uint64_t req_id, bool lock_ds, bool success, Mgmtd__DatastoreId ds_id, char *errmsg_if_any) { struct vty *vty; + bool is_short_circuit = mgmt_fe_client_current_msg_short_circuit(client); vty = (struct vty *)session_ctx; - if (!success) { - zlog_err("%socking for DS %u failed, Err: '%s'", - lock_ds ? "L" : "Unl", ds_id, errmsg_if_any); - vty_out(vty, "ERROR: %socking for DS %u failed, Err: '%s'\n", - lock_ds ? "L" : "Unl", ds_id, errmsg_if_any); - } else { - VTY_DBG("%socked DS %u successfully", lock_ds ? "L" : "Unl", - ds_id); + assert(ds_id == MGMTD_DS_CANDIDATE || ds_id == MGMTD_DS_RUNNING); + if (!success) + zlog_err("%socking for DS %u failed, Err: '%s' vty %p", + lock_ds ? "L" : "Unl", ds_id, errmsg_if_any, vty); + else { + debug_fe_client("%socked DS %u successfully", + lock_ds ? "L" : "Unl", ds_id); + if (ds_id == MGMTD_DS_CANDIDATE) + vty->mgmt_locked_candidate_ds = lock_ds; + else + vty->mgmt_locked_running_ds = lock_ds; } - vty_mgmt_resume_response(vty, success); + if (!is_short_circuit && vty->mgmt_req_pending_cmd) { + assert(!strcmp(vty->mgmt_req_pending_cmd, "MESSAGE_LOCKDS_REQ")); + vty_mgmt_resume_response(vty, + success ? CMD_SUCCESS : CMD_WARNING); + } } static void vty_mgmt_set_config_result_notified( - uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id, + struct mgmt_fe_client *client, uintptr_t usr_data, uint64_t client_id, uintptr_t session_id, uintptr_t session_ctx, uint64_t req_id, - bool success, Mgmtd__DatastoreId ds_id, char *errmsg_if_any) + bool success, Mgmtd__DatastoreId ds_id, bool implicit_commit, + char *errmsg_if_any) { struct vty *vty; @@ -3350,19 +3570,27 @@ static void vty_mgmt_set_config_result_notified( zlog_err("SET_CONFIG request for client 0x%" PRIx64 " failed, Error: '%s'", client_id, errmsg_if_any ? errmsg_if_any : "Unknown"); - vty_out(vty, "ERROR: SET_CONFIG request failed, Error: %s\n", - errmsg_if_any ? errmsg_if_any : "Unknown"); + vty_out(vty, "%% Configuration failed.\n\n"); + if (errmsg_if_any) + vty_out(vty, "%s\n", errmsg_if_any); } else { - VTY_DBG("SET_CONFIG request for client 0x%" PRIx64 - " req-id %" PRIu64 " was successfull", - client_id, req_id); + debug_fe_client("SET_CONFIG request for client 0x%" PRIx64 + " req-id %" PRIu64 " was successfull", + client_id, req_id); + } + + if (implicit_commit) { + /* In this case the changes have been applied, we are done */ + vty_mgmt_unlock_candidate_inline(vty); + vty_mgmt_unlock_running_inline(vty); } - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, success ? CMD_SUCCESS + : CMD_WARNING_CONFIG_FAILED); } static void vty_mgmt_commit_config_result_notified( - uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id, + struct mgmt_fe_client *client, uintptr_t usr_data, uint64_t client_id, uintptr_t session_id, uintptr_t session_ctx, uint64_t req_id, bool success, Mgmtd__DatastoreId src_ds_id, Mgmtd__DatastoreId dst_ds_id, bool validate_only, char *errmsg_if_any) @@ -3375,21 +3603,23 @@ static void vty_mgmt_commit_config_result_notified( zlog_err("COMMIT_CONFIG request for client 0x%" PRIx64 " failed, Error: '%s'", client_id, errmsg_if_any ? errmsg_if_any : "Unknown"); - vty_out(vty, "ERROR: COMMIT_CONFIG request failed, Error: %s\n", - errmsg_if_any ? errmsg_if_any : "Unknown"); + vty_out(vty, "%% Configuration failed.\n\n"); + if (errmsg_if_any) + vty_out(vty, "%s\n", errmsg_if_any); } else { - VTY_DBG("COMMIT_CONFIG request for client 0x%" PRIx64 - " req-id %" PRIu64 " was successfull", - client_id, req_id); + debug_fe_client("COMMIT_CONFIG request for client 0x%" PRIx64 + " req-id %" PRIu64 " was successfull", + client_id, req_id); if (errmsg_if_any) vty_out(vty, "MGMTD: %s\n", errmsg_if_any); } - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, success ? CMD_SUCCESS + : CMD_WARNING_CONFIG_FAILED); } -static enum mgmt_result vty_mgmt_get_data_result_notified( - uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id, +static int vty_mgmt_get_data_result_notified( + struct mgmt_fe_client *client, uintptr_t usr_data, uint64_t client_id, uintptr_t session_id, uintptr_t session_ctx, uint64_t req_id, bool success, Mgmtd__DatastoreId ds_id, Mgmtd__YangData **yang_data, size_t num_data, int next_key, char *errmsg_if_any) @@ -3405,13 +3635,13 @@ static enum mgmt_result vty_mgmt_get_data_result_notified( client_id, errmsg_if_any ? errmsg_if_any : "Unknown"); vty_out(vty, "ERROR: GET_DATA request failed, Error: %s\n", errmsg_if_any ? errmsg_if_any : "Unknown"); - vty_mgmt_resume_response(vty, success); - return MGMTD_INTERNAL_ERROR; + vty_mgmt_resume_response(vty, CMD_WARNING); + return -1; } - VTY_DBG("GET_DATA request for client 0x%" PRIx64 " req-id %" PRIu64 - " was successfull!", - client_id, req_id); + debug_fe_client("GET_DATA request succeeded, client 0x%" PRIx64 + " req-id %" PRIu64, + client_id, req_id); if (req_id != mgmt_last_req_id) { mgmt_last_req_id = req_id; @@ -3424,171 +3654,420 @@ static enum mgmt_result vty_mgmt_get_data_result_notified( } if (next_key < 0) { vty_out(vty, "]\n"); - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, CMD_SUCCESS); + } + + return 0; +} + +static ssize_t vty_mgmt_libyang_print(void *user_data, const void *buf, + size_t count) +{ + struct vty *vty = user_data; + + vty_out(vty, "%.*s", (int)count, (const char *)buf); + return count; +} + +static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format, + struct ly_err_item *ei) +{ + bool have_apptag = ei->apptag && ei->apptag[0] != 0; + bool have_path = ei->path && ei->path[0] != 0; + bool have_msg = ei->msg && ei->msg[0] != 0; + const char *severity = NULL; + const char *evalid = NULL; + const char *ecode = NULL; + LY_ERR err = ei->no; + + if (ei->level == LY_LLERR) + severity = "error"; + else if (ei->level == LY_LLWRN) + severity = "warning"; + + ecode = yang_ly_strerrcode(err); + if (err == LY_EVALID && ei->vecode != LYVE_SUCCESS) + evalid = yang_ly_strvecode(ei->vecode); + + switch (format) { + case LYD_XML: + vty_out(vty, + "<rpc-error xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"); + vty_out(vty, "<error-type>application</error-type>"); + if (severity) + vty_out(vty, "<error-severity>%s</error-severity>", + severity); + if (ecode) + vty_out(vty, "<error-code>%s</error-code>", ecode); + if (evalid) + vty_out(vty, "<error-validation>%s</error-validation>\n", + evalid); + if (have_path) + vty_out(vty, "<error-path>%s</error-path>\n", ei->path); + if (have_apptag) + vty_out(vty, "<error-app-tag>%s</error-app-tag>\n", + ei->apptag); + if (have_msg) + vty_out(vty, "<error-message>%s</error-message>\n", + ei->msg); + + vty_out(vty, "</rpc-error>"); + break; + case LYD_JSON: + vty_out(vty, "{ \"error-type\": \"application\""); + if (severity) + vty_out(vty, ", \"error-severity\": \"%s\"", severity); + if (ecode) + vty_out(vty, ", \"error-code\": \"%s\"", ecode); + if (evalid) + vty_out(vty, ", \"error-validation\": \"%s\"", evalid); + if (have_path) + vty_out(vty, ", \"error-path\": \"%s\"", ei->path); + if (have_apptag) + vty_out(vty, ", \"error-app-tag\": \"%s\"", ei->apptag); + if (have_msg) + vty_out(vty, ", \"error-message\": \"%s\"", ei->msg); + + vty_out(vty, "}"); + break; + case LYD_UNKNOWN: + case LYD_LYB: + default: + vty_out(vty, "%% error"); + if (severity) + vty_out(vty, " severity: %s", severity); + if (evalid) + vty_out(vty, " invalid: %s", evalid); + if (have_path) + vty_out(vty, " path: %s", ei->path); + if (have_apptag) + vty_out(vty, " app-tag: %s", ei->apptag); + if (have_msg) + vty_out(vty, " msg: %s", ei->msg); + break; + } +} + +static uint vty_out_yang_errors(struct vty *vty, LYD_FORMAT format) +{ + struct ly_err_item *ei = ly_err_first(ly_native_ctx); + uint count; + + if (!ei) + return 0; + + if (format == LYD_JSON) + vty_out(vty, "\"ietf-restconf:errors\": [ "); + + for (count = 0; ei; count++, ei = ei->next) { + if (count) + vty_out(vty, ", "); + vty_out_yang_error(vty, format, ei); + } + + if (format == LYD_JSON) + vty_out(vty, " ]"); + + ly_err_clean(ly_native_ctx, NULL); + + return count; +} + + +static int vty_mgmt_get_tree_result_notified( + struct mgmt_fe_client *client, uintptr_t user_data, uint64_t client_id, + uint64_t session_id, uintptr_t session_ctx, uint64_t req_id, + Mgmtd__DatastoreId ds_id, LYD_FORMAT result_type, void *result, + size_t len, int partial_error) +{ + struct vty *vty; + struct lyd_node *dnode; + int ret = CMD_SUCCESS; + LY_ERR err; + + vty = (struct vty *)session_ctx; + + debug_fe_client("GET_TREE request %ssucceeded, client 0x%" PRIx64 + " req-id %" PRIu64, + partial_error ? "partially " : "", client_id, req_id); + + assert(result_type == LYD_LYB || + result_type == vty->mgmt_req_pending_data); + + if (vty->mgmt_req_pending_data == LYD_XML && partial_error) + vty_out(vty, + "<!-- some errors occurred gathering results -->\n"); + + if (result_type == LYD_LYB) { + /* + * parse binary into tree and print in the specified format + */ + result_type = vty->mgmt_req_pending_data; + + err = lyd_parse_data_mem(ly_native_ctx, result, LYD_LYB, 0, 0, + &dnode); + if (!err) + err = lyd_print_clb(vty_mgmt_libyang_print, vty, dnode, + result_type, LYD_PRINT_WITHSIBLINGS); + lyd_free_all(dnode); + + if (vty_out_yang_errors(vty, result_type) || err) + ret = CMD_WARNING; + } else { + /* + * Print the in-format result + */ + assert(result_type == LYD_XML || result_type == LYD_JSON); + vty_out(vty, "%.*s\n", (int)len - 1, (const char *)result); } - return MGMTD_SUCCESS; + vty_mgmt_resume_response(vty, ret); + + return 0; } -static struct mgmt_fe_client_params client_params = { +static int vty_mgmt_error_notified(struct mgmt_fe_client *client, + uintptr_t user_data, uint64_t client_id, + uint64_t session_id, uintptr_t session_ctx, + uint64_t req_id, int error, + const char *errstr) +{ + struct vty *vty = (struct vty *)session_ctx; + const char *cname = mgmt_fe_client_name(client); + + if (!vty->mgmt_req_pending_cmd) { + debug_fe_client("Erorr with no pending command: %d returned for client %s 0x%" PRIx64 + " session-id %" PRIu64 " req-id %" PRIu64 + "error-str %s", + error, cname, client_id, session_id, req_id, + errstr); + vty_out(vty, + "%% Error %d from MGMTD for %s with no pending command: %s\n", + error, cname, errstr); + return CMD_WARNING; + } + + debug_fe_client("Erorr %d returned for client %s 0x%" PRIx64 + " session-id %" PRIu64 " req-id %" PRIu64 "error-str %s", + error, cname, client_id, session_id, req_id, errstr); + + vty_out(vty, "%% %s (for %s, client %s)\n", errstr, + vty->mgmt_req_pending_cmd, cname); + + vty_mgmt_resume_response(vty, error ? CMD_WARNING : CMD_SUCCESS); + + return 0; +} + +static struct mgmt_fe_client_cbs mgmt_cbs = { .client_connect_notify = vty_mgmt_server_connected, - .client_session_notify = vty_mgmt_session_created, + .client_session_notify = vty_mgmt_session_notify, .lock_ds_notify = vty_mgmt_ds_lock_notified, .set_config_notify = vty_mgmt_set_config_result_notified, .commit_config_notify = vty_mgmt_commit_config_result_notified, .get_data_notify = vty_mgmt_get_data_result_notified, + .get_tree_notify = vty_mgmt_get_tree_result_notified, + .error_notify = vty_mgmt_error_notified, + }; void vty_init_mgmt_fe(void) { - if (!vty_master) { - zlog_err("Always call vty_mgmt_init_fe() after vty_init()!!"); - return; - } - - assert(!mgmt_lib_hndl); - snprintf(client_params.name, sizeof(client_params.name), "%s-%lld", - frr_get_progname(), (long long)getpid()); - mgmt_lib_hndl = mgmt_fe_client_lib_init(&client_params, vty_master); - assert(mgmt_lib_hndl); + char name[40]; + + assert(vty_master); + assert(!mgmt_fe_client); + snprintf(name, sizeof(name), "vty-%s-%ld", frr_get_progname(), + (long)getpid()); + mgmt_fe_client = mgmt_fe_client_create(name, &mgmt_cbs, 0, vty_master); + assert(mgmt_fe_client); } bool vty_mgmt_fe_enabled(void) { - return mgmt_lib_hndl && mgmt_fe_connected ? true : false; + return mgmt_fe_client && mgmt_fe_connected; } -int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id, - bool lock) +bool vty_mgmt_should_process_cli_apply_changes(struct vty *vty) { - enum mgmt_result ret; + return vty->type != VTY_FILE && vty_mgmt_fe_enabled(); +} - if (mgmt_lib_hndl && vty->mgmt_session_id) { - vty->mgmt_req_id++; - ret = mgmt_fe_lock_ds(mgmt_lib_hndl, vty->mgmt_session_id, - vty->mgmt_req_id, ds_id, lock); - if (ret != MGMTD_SUCCESS) { - zlog_err( - "Failed to send %sLOCK-DS-REQ to MGMTD for req-id %" - PRIu64 ".", - lock ? "" : "UN", vty->mgmt_req_id); - vty_out(vty, "Failed to send %sLOCK-DS-REQ to MGMTD!\n", - lock ? "" : "UN"); - return -1; - } +int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id, + bool lock, bool scok) +{ + assert(mgmt_fe_client); + assert(vty->mgmt_session_id); - vty->mgmt_req_pending = true; + vty->mgmt_req_id++; + if (mgmt_fe_send_lockds_req(mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, ds_id, lock, scok)) { + zlog_err("Failed sending %sLOCK-DS-REQ req-id %" PRIu64, + lock ? "" : "UN", vty->mgmt_req_id); + vty_out(vty, "Failed to send %sLOCK-DS-REQ to MGMTD!\n", + lock ? "" : "UN"); + return -1; } + if (!scok) + vty->mgmt_req_pending_cmd = "MESSAGE_LOCKDS_REQ"; + return 0; } -int vty_mgmt_send_config_data(struct vty *vty) +int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base, + bool implicit_commit) { Mgmtd__YangDataValue value[VTY_MAXCFGCHANGES]; Mgmtd__YangData cfg_data[VTY_MAXCFGCHANGES]; Mgmtd__YangCfgDataReq cfg_req[VTY_MAXCFGCHANGES]; Mgmtd__YangCfgDataReq *cfgreq[VTY_MAXCFGCHANGES] = {0}; + char xpath[VTY_MAXCFGCHANGES][XPATH_MAXLEN]; + char *change_xpath; size_t indx; - int cnt; - bool implicit_commit = false; - - if (mgmt_lib_hndl && vty->mgmt_session_id) { - cnt = 0; - for (indx = 0; indx < vty->num_cfg_changes; indx++) { - mgmt_yang_data_init(&cfg_data[cnt]); - - if (vty->cfg_changes[indx].value) { - mgmt_yang_data_value_init(&value[cnt]); - value[cnt].encoded_str_val = - (char *)vty->cfg_changes[indx].value; - value[cnt].value_case = - MGMTD__YANG_DATA_VALUE__VALUE_ENCODED_STR_VAL; - cfg_data[cnt].value = &value[cnt]; - } - cfg_data[cnt].xpath = vty->cfg_changes[indx].xpath; + if (vty->type == VTY_FILE) { + /* + * if this is a config file read we will not send any of the + * changes until we are done reading the file and have modified + * the local candidate DS. + */ + /* no-one else should be sending data right now */ + assert(!vty->mgmt_num_pending_setcfg); + return 0; + } - mgmt_yang_cfg_data_req_init(&cfg_req[cnt]); - cfg_req[cnt].data = &cfg_data[cnt]; - switch (vty->cfg_changes[indx].operation) { - case NB_OP_DESTROY: - cfg_req[cnt].req_type = - MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA; - break; + /* If we are FE client and we have a vty then we have a session */ + assert(mgmt_fe_client && vty->mgmt_client_id && vty->mgmt_session_id); - case NB_OP_CREATE: - case NB_OP_MODIFY: - case NB_OP_MOVE: - case NB_OP_PRE_VALIDATE: - case NB_OP_APPLY_FINISH: - cfg_req[cnt].req_type = - MGMTD__CFG_DATA_REQ_TYPE__SET_DATA; - break; - case NB_OP_GET_ELEM: - case NB_OP_GET_NEXT: - case NB_OP_GET_KEYS: - case NB_OP_LOOKUP_ENTRY: - case NB_OP_RPC: - assert(!"Invalid type of operation"); - break; - default: - assert(!"non-enum value, invalid"); - } + if (!vty->num_cfg_changes) + return 0; - cfgreq[cnt] = &cfg_req[cnt]; - cnt++; + /* grab the candidate and running lock prior to sending implicit commit + * command + */ + if (implicit_commit) { + if (vty_mgmt_lock_candidate_inline(vty)) { + vty_out(vty, + "%% command failed, could not lock candidate DS\n"); + return -1; + } else if (vty_mgmt_lock_running_inline(vty)) { + vty_out(vty, + "%% command failed, could not lock running DS\n"); + vty_mgmt_unlock_candidate_inline(vty); + return -1; } + } - vty->mgmt_req_id++; - implicit_commit = vty_needs_implicit_commit(vty); - if (cnt && mgmt_fe_set_config_data( - mgmt_lib_hndl, vty->mgmt_session_id, - vty->mgmt_req_id, MGMTD_DS_CANDIDATE, cfgreq, - cnt, implicit_commit, - MGMTD_DS_RUNNING) != MGMTD_SUCCESS) { - zlog_err("Failed to send %d Config Xpaths to MGMTD!!", - (int)indx); - vty_out(vty, "Failed to send SETCFG-REQ to MGMTD!\n"); - return -1; + if (xpath_base == NULL) + xpath_base = ""; + + for (indx = 0; indx < vty->num_cfg_changes; indx++) { + mgmt_yang_data_init(&cfg_data[indx]); + + if (vty->cfg_changes[indx].value) { + mgmt_yang_data_value_init(&value[indx]); + value[indx].encoded_str_val = + (char *)vty->cfg_changes[indx].value; + value[indx].value_case = + MGMTD__YANG_DATA_VALUE__VALUE_ENCODED_STR_VAL; + cfg_data[indx].value = &value[indx]; + } + + change_xpath = vty->cfg_changes[indx].xpath; + + memset(xpath[indx], 0, sizeof(xpath[indx])); + /* If change xpath is relative, prepend base xpath. */ + if (change_xpath[0] == '.') { + strlcpy(xpath[indx], xpath_base, sizeof(xpath[indx])); + change_xpath++; /* skip '.' */ + } + strlcat(xpath[indx], change_xpath, sizeof(xpath[indx])); + + cfg_data[indx].xpath = xpath[indx]; + + mgmt_yang_cfg_data_req_init(&cfg_req[indx]); + cfg_req[indx].data = &cfg_data[indx]; + switch (vty->cfg_changes[indx].operation) { + case NB_OP_DELETE: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA; + break; + + case NB_OP_DESTROY: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA; + break; + + case NB_OP_CREATE_EXCL: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA; + break; + + case NB_OP_REPLACE: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA; + break; + + case NB_OP_CREATE: + case NB_OP_MODIFY: + case NB_OP_MOVE: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__SET_DATA; + break; + default: + assertf(false, + "Invalid operation type for send config: %d", + vty->cfg_changes[indx].operation); + /*NOTREACHED*/ + abort(); } - vty->mgmt_req_pending = true; + cfgreq[indx] = &cfg_req[indx]; } + if (!indx) + return 0; + + vty->mgmt_req_id++; + if (mgmt_fe_send_setcfg_req(mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, MGMTD_DS_CANDIDATE, + cfgreq, indx, implicit_commit, + MGMTD_DS_RUNNING)) { + zlog_err("Failed to send %zu config xpaths to mgmtd", indx); + vty_out(vty, "%% Failed to send commands to mgmtd\n"); + return -1; + } + + vty->mgmt_req_pending_cmd = "MESSAGE_SETCFG_REQ"; return 0; } int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only, bool abort) { - enum mgmt_result ret; - - if (mgmt_lib_hndl && vty->mgmt_session_id) { + if (mgmt_fe_client && vty->mgmt_session_id) { vty->mgmt_req_id++; - ret = mgmt_fe_commit_config_data( - mgmt_lib_hndl, vty->mgmt_session_id, vty->mgmt_req_id, - MGMTD_DS_CANDIDATE, MGMTD_DS_RUNNING, validate_only, - abort); - if (ret != MGMTD_SUCCESS) { - zlog_err( - "Failed to send COMMIT-REQ to MGMTD for req-id %" - PRIu64 ".", - vty->mgmt_req_id); + if (mgmt_fe_send_commitcfg_req( + mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, MGMTD_DS_CANDIDATE, + MGMTD_DS_RUNNING, validate_only, abort)) { + zlog_err("Failed sending COMMIT-REQ req-id %" PRIu64, + vty->mgmt_req_id); vty_out(vty, "Failed to send COMMIT-REQ to MGMTD!\n"); return -1; } - vty->mgmt_req_pending = true; + vty->mgmt_req_pending_cmd = "MESSAGE_COMMCFG_REQ"; vty->mgmt_num_pending_setcfg = 0; } return 0; } -int vty_mgmt_send_get_config(struct vty *vty, Mgmtd__DatastoreId datastore, - const char **xpath_list, int num_req) +int vty_mgmt_send_get_req(struct vty *vty, bool is_config, + Mgmtd__DatastoreId datastore, const char **xpath_list, + int num_req) { - enum mgmt_result ret; Mgmtd__YangData yang_data[VTY_MAXCFGCHANGES]; Mgmtd__YangGetDataReq get_req[VTY_MAXCFGCHANGES]; Mgmtd__YangGetDataReq *getreq[VTY_MAXCFGCHANGES]; @@ -3605,56 +4084,40 @@ int vty_mgmt_send_get_config(struct vty *vty, Mgmtd__DatastoreId datastore, get_req[i].data = &yang_data[i]; getreq[i] = &get_req[i]; } - ret = mgmt_fe_get_config_data(mgmt_lib_hndl, vty->mgmt_session_id, - vty->mgmt_req_id, datastore, getreq, - num_req); - - if (ret != MGMTD_SUCCESS) { - zlog_err( - "Failed to send GET-CONFIG to MGMTD for req-id %" PRIu64 - ".", - vty->mgmt_req_id); + if (mgmt_fe_send_get_req(mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, is_config, datastore, getreq, + num_req)) { + zlog_err("Failed to send GET- to MGMTD for req-id %" PRIu64 ".", + vty->mgmt_req_id); vty_out(vty, "Failed to send GET-CONFIG to MGMTD!\n"); return -1; } - vty->mgmt_req_pending = true; + vty->mgmt_req_pending_cmd = "MESSAGE_GETCFG_REQ"; return 0; } -int vty_mgmt_send_get_data(struct vty *vty, Mgmtd__DatastoreId datastore, - const char **xpath_list, int num_req) +int vty_mgmt_send_get_data_req(struct vty *vty, uint8_t datastore, + LYD_FORMAT result_type, uint8_t flags, + uint8_t defaults, const char *xpath) { - enum mgmt_result ret; - Mgmtd__YangData yang_data[VTY_MAXCFGCHANGES]; - Mgmtd__YangGetDataReq get_req[VTY_MAXCFGCHANGES]; - Mgmtd__YangGetDataReq *getreq[VTY_MAXCFGCHANGES]; - int i; + LYD_FORMAT intern_format = result_type; vty->mgmt_req_id++; - for (i = 0; i < num_req; i++) { - mgmt_yang_get_data_req_init(&get_req[i]); - mgmt_yang_data_init(&yang_data[i]); - - yang_data->xpath = (char *)xpath_list[i]; - - get_req[i].data = &yang_data[i]; - getreq[i] = &get_req[i]; - } - ret = mgmt_fe_get_data(mgmt_lib_hndl, vty->mgmt_session_id, - vty->mgmt_req_id, datastore, getreq, num_req); - - if (ret != MGMTD_SUCCESS) { - zlog_err("Failed to send GET-DATA to MGMTD for req-id %" PRIu64 - ".", - vty->mgmt_req_id); + if (mgmt_fe_send_get_data_req(mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, datastore, + intern_format, flags, defaults, xpath)) { + zlog_err("Failed to send GET-DATA to MGMTD session-id: %" PRIu64 + " req-id %" PRIu64 ".", + vty->mgmt_session_id, vty->mgmt_req_id); vty_out(vty, "Failed to send GET-DATA to MGMTD!\n"); return -1; } - vty->mgmt_req_pending = true; + vty->mgmt_req_pending_cmd = "MESSAGE_GET_DATA_REQ"; + vty->mgmt_req_pending_data = result_type; return 0; } @@ -3681,8 +4144,8 @@ void vty_init(struct event_loop *master_thread, bool do_command_logging) install_element(CONFIG_NODE, &log_commands_cmd); if (do_command_logging) { - do_log_commands = true; - do_log_commands_perm = true; + vty_log_commands = true; + vty_log_commands_perm = true; } install_element(ENABLE_NODE, &terminal_monitor_cmd); @@ -3704,11 +4167,10 @@ void vty_init(struct event_loop *master_thread, bool do_command_logging) void vty_terminate(void) { struct vty *vty; - struct vty_serv *vtyserv; - if (mgmt_lib_hndl) { - mgmt_fe_client_lib_destroy(mgmt_lib_hndl); - mgmt_lib_hndl = 0; + if (mgmt_fe_client) { + mgmt_fe_client_destroy(mgmt_fe_client); + mgmt_fe_client = 0; } memset(vty_cwd, 0x00, sizeof(vty_cwd)); @@ -3730,12 +4192,5 @@ void vty_terminate(void) vtys_fini(vtysh_sessions); vtys_init(vtysh_sessions); - while ((vtyserv = vtyservs_pop(vty_servs))) { - EVENT_OFF(vtyserv->t_accept); - close(vtyserv->sock); - XFREE(MTYPE_VTY_SERV, vtyserv); - } - - vtyservs_fini(vty_servs); - vtyservs_init(vty_servs); + vty_serv_stop(); } |
