summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/mgmt_fe_client.c121
-rw-r--r--lib/mgmt_fe_client.h50
-rw-r--r--lib/vty.c334
-rw-r--r--lib/vty.h5
-rw-r--r--mgmtd/mgmt_history.c4
-rw-r--r--mgmtd/mgmt_vty.c30
6 files changed, 527 insertions, 17 deletions
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index 4c6f86b194..f6ae485c5c 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -12,6 +12,7 @@
#include "libfrr.h"
#include "mgmt_fe_client.h"
#include "mgmt_msg.h"
+#include "mgmt_msg_native.h"
#include "mgmt_pb.h"
#include "network.h"
#include "stream.h"
@@ -34,6 +35,7 @@ DECLARE_LIST(mgmt_sessions, struct mgmt_fe_client_session, list_linkage);
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_CLIENT, "frontend client");
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_CLIENT_NAME, "frontend client name");
+DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_GET_DATA_MSG, "FE get data msg");
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_SESSION, "frontend session");
struct mgmt_fe_client {
@@ -109,6 +111,13 @@ mgmt_fe_find_session_by_session_id(struct mgmt_fe_client *client,
return NULL;
}
+static int fe_client_send_native_msg(struct mgmt_fe_client *client, void *msg,
+ size_t len, bool short_circuit_ok)
+{
+ return msg_conn_send_msg(&client->client.conn, MGMT_MSG_VERSION_NATIVE,
+ msg, len, NULL, short_circuit_ok);
+}
+
static int mgmt_fe_client_send_msg(struct mgmt_fe_client *client,
Mgmtd__FeMessage *fe_msg,
bool short_circuit_ok)
@@ -304,6 +313,35 @@ int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client,
return mgmt_fe_client_send_msg(client, &fe_msg, false);
}
+/*
+ * Send get-tree request.
+ */
+int mgmt_fe_send_get_tree_req(struct mgmt_fe_client *client,
+ uint64_t session_id, uint64_t req_id,
+ LYD_FORMAT result_type, const char *xpath)
+{
+ struct mgmt_msg_get_tree *msg;
+ size_t xplen = strlen(xpath);
+ size_t mlen = sizeof(*msg) + xplen + 1;
+ int ret;
+
+ msg = XCALLOC(MTYPE_MGMTD_FE_GET_DATA_MSG, mlen);
+ msg->session_id = session_id;
+ msg->req_id = req_id;
+ msg->code = MGMT_MSG_CODE_GET_TREE;
+ msg->result_type = result_type;
+ strlcpy(msg->xpath, xpath, xplen + 1);
+
+ MGMTD_FE_CLIENT_DBG("Sending GET_TREE_REQ session-id %" PRIu64
+ " req-id %" PRIu64 " xpath: %s",
+ session_id, req_id, xpath);
+
+ ret = fe_client_send_native_msg(client, msg, mlen, false);
+ XFREE(MTYPE_MGMTD_FE_GET_DATA_MSG, msg);
+ return ret;
+}
+
+
static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
Mgmtd__FeMessage *fe_msg)
{
@@ -469,6 +507,73 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
return 0;
}
+/*
+ * Handle a native encoded message
+ */
+static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
+ struct mgmt_msg_header *msg,
+ size_t msg_len)
+{
+ struct mgmt_fe_client_session *session;
+ struct mgmt_msg_tree_data *tree_msg;
+ struct mgmt_msg_error *err_msg;
+
+ MGMTD_FE_CLIENT_DBG("Got GET_TREE reply for session-id %" PRIu64,
+ msg->session_id);
+
+ session = mgmt_fe_find_session_by_session_id(client, msg->session_id);
+
+ if (!session || !session->client) {
+ MGMTD_FE_CLIENT_ERR("No session for received native msg session-id %" PRIu64,
+ msg->session_id);
+ return;
+ }
+
+ switch (msg->code) {
+ case MGMT_MSG_CODE_ERROR:
+ if (!session->client->cbs.error_notify)
+ return;
+
+ err_msg = (typeof(err_msg))msg;
+ if (!MGMT_MSG_VALIDATE_NUL_TERM(err_msg, msg_len)) {
+ MGMTD_FE_CLIENT_ERR("Corrupt error msg recv");
+ return;
+ }
+ session->client->cbs.error_notify(client, client->user_data,
+ session->client_id,
+ msg->session_id,
+ session->user_ctx,
+ msg->req_id, err_msg->error,
+ err_msg->errstr);
+ break;
+ case MGMT_MSG_CODE_TREE_DATA:
+ if (!session->client->cbs.get_tree_notify)
+ return;
+
+ tree_msg = (typeof(tree_msg))msg;
+ if (msg_len < sizeof(*tree_msg)) {
+ MGMTD_FE_CLIENT_ERR("Corrupt tree-data msg recv");
+ return;
+ }
+ session->client->cbs.get_tree_notify(client, client->user_data,
+ session->client_id,
+ msg->session_id,
+ session->user_ctx,
+ msg->req_id,
+ MGMTD_DS_OPERATIONAL,
+ tree_msg->result_type,
+ tree_msg->result,
+ msg_len - sizeof(*tree_msg),
+ tree_msg->partial_error);
+ break;
+ default:
+ MGMTD_FE_CLIENT_ERR("unknown native message session-id %" PRIu64
+ " req-id %" PRIu64 " code %u",
+ msg->session_id, msg->req_id, msg->code);
+ break;
+ }
+}
+
static void mgmt_fe_client_process_msg(uint8_t version, uint8_t *data,
size_t len, struct msg_conn *conn)
{
@@ -479,6 +584,17 @@ static void mgmt_fe_client_process_msg(uint8_t version, uint8_t *data,
msg_client = container_of(conn, struct msg_client, conn);
client = container_of(msg_client, struct mgmt_fe_client, client);
+ if (version == MGMT_MSG_VERSION_NATIVE) {
+ struct mgmt_msg_header *msg = (typeof(msg))data;
+
+ if (len >= sizeof(*msg))
+ fe_client_handle_native_msg(client, msg, len);
+ else
+ MGMTD_FE_CLIENT_ERR("native message to FE client %s too short %zu",
+ client->name, len);
+ return;
+ }
+
fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
if (!fe_msg) {
MGMTD_FE_CLIENT_DBG("Failed to decode %zu bytes from server.",
@@ -647,6 +763,11 @@ bool mgmt_fe_client_current_msg_short_circuit(struct mgmt_fe_client *client)
return client->client.conn.is_short_circuit;
}
+const char *mgmt_fe_client_name(struct mgmt_fe_client *client)
+{
+ return client->name;
+}
+
/*
* Create a new Session for a Frontend Client connection.
*/
diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
index d770748f23..32d2920ff9 100644
--- a/lib/mgmt_fe_client.h
+++ b/lib/mgmt_fe_client.h
@@ -115,6 +115,20 @@ struct mgmt_fe_client_cbs {
uintptr_t user_data, uint64_t req_id,
Mgmtd__DatastoreId ds_id,
Mgmtd__YangData **yang_data, size_t num_data);
+
+ /* Called when get-tree result is returned */
+ int (*get_tree_notify)(struct mgmt_fe_client *client,
+ uintptr_t user_data, uint64_t client_id,
+ uint64_t session_id, uint64_t session_ctx,
+ uint64_t req_id, Mgmtd__DatastoreId ds_id,
+ LYD_FORMAT result_type, void *result, size_t len,
+ int partial_error);
+
+ /* Called when new native error is returned */
+ int (*error_notify)(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);
};
extern struct debug mgmt_dbg_fe_client;
@@ -364,6 +378,31 @@ extern int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client,
int num_reqs);
/*
+ * Send GET-TREE to MGMTD daemon.
+ *
+ * client
+ * Client object.
+ *
+ * session_id
+ * Client session ID.
+ *
+ * req_id
+ * Client request ID.
+ *
+ * result_type
+ * The LYD_FORMAT of the result.
+ *
+ * xpath
+ * the xpath to get.
+ *
+ * Returns:
+ * 0 on success, otherwise msg_conn_send_msg() return values.
+ */
+extern int mgmt_fe_send_get_tree_req(struct mgmt_fe_client *client,
+ uint64_t session_id, uint64_t req_id,
+ LYD_FORMAT result_type, const char *xpath);
+
+/*
* Destroy library and cleanup everything.
*/
extern void mgmt_fe_client_destroy(struct mgmt_fe_client *client);
@@ -379,6 +418,17 @@ extern uint mgmt_fe_client_session_count(struct mgmt_fe_client *client);
extern bool
mgmt_fe_client_current_msg_short_circuit(struct mgmt_fe_client *client);
+/**
+ * Get the name of the client
+ *
+ * Args:
+ * The client object.
+ *
+ * Return:
+ * The name of the client.
+ */
+extern const char *mgmt_fe_client_name(struct mgmt_fe_client *client);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/vty.c b/lib/vty.c
index 2cfe34f211..afd00d1da5 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -157,10 +157,9 @@ static int vty_mgmt_unlock_running_inline(struct vty *vty)
return vty->mgmt_locked_running_ds ? -1 : 0;
}
-void vty_mgmt_resume_response(struct vty *vty, bool success)
+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_cmd) {
zlog_err(
@@ -168,14 +167,10 @@ void vty_mgmt_resume_response(struct vty *vty, bool success)
return;
}
- if (!success)
- ret = CMD_WARNING_CONFIG_FAILED;
-
- MGMTD_FE_CLIENT_DBG(
- "resuming CLI cmd after %s on vty session-id: %" PRIu64
- " with '%s'",
- vty->mgmt_req_pending_cmd, vty->mgmt_session_id,
- success ? "succeeded" : "failed");
+ MGMTD_FE_CLIENT_DBG("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_cmd = NULL;
@@ -3560,7 +3555,8 @@ static void vty_mgmt_ds_lock_notified(struct mgmt_fe_client *client,
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);
+ vty_mgmt_resume_response(vty,
+ success ? CMD_SUCCESS : CMD_WARNING);
}
}
@@ -3592,7 +3588,8 @@ static void vty_mgmt_set_config_result_notified(
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(
@@ -3620,7 +3617,8 @@ static void vty_mgmt_commit_config_result_notified(
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 int vty_mgmt_get_data_result_notified(
@@ -3640,7 +3638,7 @@ static int 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);
+ vty_mgmt_resume_response(vty, CMD_WARNING);
return -1;
}
@@ -3659,9 +3657,290 @@ static int 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,
+ success ? CMD_SUCCESS : CMD_WARNING);
+ }
+
+ 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";
+
+ switch (ei->no) {
+ case LY_SUCCESS:
+ ecode = "ok";
+ break;
+ case LY_EMEM:
+ ecode = "out of memory";
+ break;
+ case LY_ESYS:
+ ecode = "system error";
+ break;
+ case LY_EINVAL:
+ ecode = "invalid value given";
+ break;
+ case LY_EEXIST:
+ ecode = "item exists";
+ break;
+ case LY_ENOTFOUND:
+ ecode = "item not found";
+ break;
+ case LY_EINT:
+ ecode = "operation interrupted";
+ break;
+ case LY_EVALID:
+ ecode = "validation failed";
+ break;
+ case LY_EDENIED:
+ ecode = "access denied";
+ break;
+ case LY_EINCOMPLETE:
+ ecode = "incomplete";
+ break;
+ case LY_ERECOMPILE:
+ ecode = "compile error";
+ break;
+ case LY_ENOT:
+ ecode = "not";
+ break;
+ default:
+ case LY_EPLUGIN:
+ case LY_EOTHER:
+ ecode = "other";
+ break;
+ }
+
+ if (err == LY_EVALID) {
+ switch (ei->vecode) {
+ case LYVE_SUCCESS:
+ evalid = NULL;
+ break;
+ case LYVE_SYNTAX:
+ evalid = "syntax";
+ break;
+ case LYVE_SYNTAX_YANG:
+ evalid = "yang-syntax";
+ break;
+ case LYVE_SYNTAX_YIN:
+ evalid = "yin-syntax";
+ break;
+ case LYVE_REFERENCE:
+ evalid = "reference";
+ break;
+ case LYVE_XPATH:
+ evalid = "xpath";
+ break;
+ case LYVE_SEMANTICS:
+ evalid = "semantics";
+ break;
+ case LYVE_SYNTAX_XML:
+ evalid = "xml-syntax";
+ break;
+ case LYVE_SYNTAX_JSON:
+ evalid = "json-syntax";
+ break;
+ case LYVE_DATA:
+ evalid = "data";
+ break;
+ default:
+ case LYVE_OTHER:
+ evalid = "other";
+ break;
+ }
+ }
+
+ 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, uint64_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;
+
+ MGMTD_FE_CLIENT_DBG("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);
+ }
+
+ vty_mgmt_resume_response(vty, ret);
+
+ return 0;
+}
+
+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) {
+ MGMTD_FE_CLIENT_DBG("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;
+ }
+
+ MGMTD_FE_CLIENT_DBG("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;
}
@@ -3672,6 +3951,9 @@ static struct mgmt_fe_client_cbs mgmt_cbs = {
.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)
@@ -3893,6 +4175,28 @@ int vty_mgmt_send_get_req(struct vty *vty, bool is_config,
return 0;
}
+int vty_mgmt_send_get_tree_req(struct vty *vty, LYD_FORMAT result_type,
+ const char *xpath)
+{
+ LYD_FORMAT intern_format = result_type;
+
+ vty->mgmt_req_id++;
+
+ if (mgmt_fe_send_get_tree_req(mgmt_fe_client, vty->mgmt_session_id,
+ vty->mgmt_req_id, intern_format, xpath)) {
+ zlog_err("Failed to send GET-TREE to MGMTD session-id: %" PRIu64
+ " req-id %" PRIu64 ".",
+ vty->mgmt_session_id, vty->mgmt_req_id);
+ vty_out(vty, "Failed to send GET-TREE to MGMTD!\n");
+ return -1;
+ }
+
+ vty->mgmt_req_pending_cmd = "MESSAGE_GET_TREE_REQ";
+ vty->mgmt_req_pending_data = result_type;
+
+ return 0;
+}
+
/* Install vty's own commands like `who' command. */
void vty_init(struct event_loop *master_thread, bool do_command_logging)
{
diff --git a/lib/vty.h b/lib/vty.h
index 1a431fa16a..5866eccde0 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -229,6 +229,7 @@ struct vty {
* CLI command and we are waiting on the reply so we can respond to the
* vty user. */
const char *mgmt_req_pending_cmd;
+ uintptr_t mgmt_req_pending_data;
bool mgmt_locked_candidate_ds;
bool mgmt_locked_running_ds;
/* Need to track when we file-lock in vtysh to re-lock on end/conf t
@@ -419,9 +420,11 @@ extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only,
extern int vty_mgmt_send_get_req(struct vty *vty, bool is_config,
Mgmtd__DatastoreId datastore,
const char **xpath_list, int num_req);
+extern int vty_mgmt_send_get_tree_req(struct vty *vty, LYD_FORMAT result_type,
+ const char *xpath);
extern int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id,
bool lock, bool scok);
-extern void vty_mgmt_resume_response(struct vty *vty, bool success);
+extern void vty_mgmt_resume_response(struct vty *vty, int ret);
static inline bool vty_needs_implicit_commit(struct vty *vty)
{
diff --git a/mgmtd/mgmt_history.c b/mgmtd/mgmt_history.c
index d4069325ca..ddc5a1844e 100644
--- a/mgmtd/mgmt_history.c
+++ b/mgmtd/mgmt_history.c
@@ -261,7 +261,9 @@ failed_unlock:
void mgmt_history_rollback_complete(bool success)
{
- vty_mgmt_resume_response(rollback_vty, success);
+ vty_mgmt_resume_response(rollback_vty,
+ success ? CMD_SUCCESS
+ : CMD_WARNING_CONFIG_FAILED);
rollback_vty = NULL;
}
diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c
index 3116ccbaf7..68203b8a70 100644
--- a/mgmtd/mgmt_vty.c
+++ b/mgmtd/mgmt_vty.c
@@ -218,6 +218,35 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
return CMD_SUCCESS;
}
+DEFPY(show_mgmt_get_data_tree, show_mgmt_get_data_tree_cmd,
+ "show mgmt get-data-tree WORD$path [json|xml]$fmt",
+ SHOW_STR MGMTD_STR
+ "Get a data tree from the operational datastore\n"
+ "XPath expression specifying the YANG data root\n"
+ "JSON output format\n"
+ "XML output format\n")
+{
+ LYD_FORMAT format = (fmt && fmt[0] == 'x') ? LYD_XML : LYD_JSON;
+ int plen = strlen(path);
+ char *xpath = NULL;
+
+ /* get rid of extraneous trailing slash-* or single '/' unless root */
+ if (plen > 2 && ((path[plen - 2] == '/' && path[plen - 1] == '*') ||
+ (path[plen - 2] != '/' && path[plen - 1] == '/'))) {
+ plen = path[plen - 1] == '/' ? plen - 1 : plen - 2;
+ xpath = XSTRDUP(MTYPE_TMP, path);
+ xpath[plen] = 0;
+ path = xpath;
+ }
+
+ vty_mgmt_send_get_tree_req(vty, format, path);
+
+ if (xpath)
+ XFREE(MTYPE_TMP, xpath);
+
+ return CMD_SUCCESS;
+}
+
DEFPY(show_mgmt_dump_data,
show_mgmt_dump_data_cmd,
"show mgmt datastore-contents [candidate|operational|running]$dsname [xpath WORD$path] [file WORD$filepath] <json|xml>$fmt",
@@ -512,6 +541,7 @@ void mgmt_vty_init(void)
install_element(VIEW_NODE, &show_mgmt_ds_cmd);
install_element(VIEW_NODE, &show_mgmt_get_config_cmd);
install_element(VIEW_NODE, &show_mgmt_get_data_cmd);
+ install_element(VIEW_NODE, &show_mgmt_get_data_tree_cmd);
install_element(VIEW_NODE, &show_mgmt_dump_data_cmd);
install_element(VIEW_NODE, &show_mgmt_map_xpath_cmd);
install_element(VIEW_NODE, &show_mgmt_cmt_hist_cmd);