From e1cdb38ee61bcd05b9648d4d60007336e5cffff4 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Sat, 13 Jan 2024 22:51:45 +0200 Subject: [PATCH] lib, mgmtd: add ability to set content type in get-data request Like in RESTCONF GET request and NETCONF get-data request, make it possible to request state-only, config-only, or all data. Signed-off-by: Igor Ryzhov --- lib/mgmt_fe_client.c | 7 +++--- lib/mgmt_fe_client.h | 7 +++++- lib/mgmt_msg_native.h | 8 +++++- lib/vty.c | 5 ++-- lib/vty.h | 2 +- mgmtd/mgmt_fe_adapter.c | 6 ++--- mgmtd/mgmt_txn.c | 54 ++++++++++++++++++++++++++++++++++++++++- mgmtd/mgmt_txn.h | 4 ++- mgmtd/mgmt_vty.c | 10 ++++++-- 9 files changed, 88 insertions(+), 15 deletions(-) diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c index 16559c6103..57ac071ecf 100644 --- a/lib/mgmt_fe_client.c +++ b/lib/mgmt_fe_client.c @@ -308,9 +308,9 @@ int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client, /* * Send get-data request. */ -int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, - uint64_t session_id, uint64_t req_id, - LYD_FORMAT result_type, const char *xpath) +int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, uint64_t session_id, + uint64_t req_id, LYD_FORMAT result_type, + uint8_t flags, const char *xpath) { struct mgmt_msg_get_data *msg; size_t xplen = strlen(xpath); @@ -322,6 +322,7 @@ int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, msg->req_id = req_id; msg->code = MGMT_MSG_CODE_GET_DATA; msg->result_type = result_type; + msg->flags = flags; strlcpy(msg->xpath, xpath, xplen + 1); MGMTD_FE_CLIENT_DBG("Sending GET_DATA_REQ session-id %" PRIu64 diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h index 95e73ca594..3abe29b1cf 100644 --- a/lib/mgmt_fe_client.h +++ b/lib/mgmt_fe_client.h @@ -15,6 +15,7 @@ extern "C" { #include "mgmt_pb.h" #include "frrevent.h" #include "mgmt_defines.h" +#include "mgmt_msg_native.h" /*************************************************************** * Macros @@ -381,6 +382,9 @@ extern int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client, * result_type * The LYD_FORMAT of the result. * + * flags + * Flags to control the behavior of the request. + * * xpath * the xpath to get. * @@ -389,7 +393,8 @@ extern int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client, */ extern int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, uint64_t session_id, uint64_t req_id, - LYD_FORMAT result_type, const char *xpath); + LYD_FORMAT result_type, uint8_t flags, + const char *xpath); /* * Destroy library and cleanup everything. diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index 93ff6f012c..88c1065fc8 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -233,16 +233,22 @@ _Static_assert(sizeof(struct mgmt_msg_tree_data) == offsetof(struct mgmt_msg_tree_data, result), "Size mismatch"); +/* Flags for get-data request */ +#define GET_DATA_FLAG_STATE 0x01 /* get only "config false" data */ +#define GET_DATA_FLAG_CONFIG 0x02 /* get only "config true" data */ + /** * struct mgmt_msg_get_data - frontend get-data request. * * @result_type: ``LYD_FORMAT`` for the returned result. + * @flags: combination of ``GET_DATA_FLAG_*`` flags. * @xpath: the query for the data to return. */ struct mgmt_msg_get_data { struct mgmt_msg_header; uint8_t result_type; - uint8_t resv2[7]; + uint8_t flags; + uint8_t resv2[6]; alignas(8) char xpath[]; }; diff --git a/lib/vty.c b/lib/vty.c index f1b7d621b7..3fc7c38083 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -4106,14 +4106,15 @@ int vty_mgmt_send_get_req(struct vty *vty, bool is_config, } int vty_mgmt_send_get_data_req(struct vty *vty, LYD_FORMAT result_type, - const char *xpath) + uint8_t flags, const char *xpath) { LYD_FORMAT intern_format = result_type; vty->mgmt_req_id++; if (mgmt_fe_send_get_data_req(mgmt_fe_client, vty->mgmt_session_id, - vty->mgmt_req_id, intern_format, xpath)) { + vty->mgmt_req_id, intern_format, flags, + xpath)) { zlog_err("Failed to send GET-DATA to MGMTD session-id: %" PRIu64 " req-id %" PRIu64 ".", vty->mgmt_session_id, vty->mgmt_req_id); diff --git a/lib/vty.h b/lib/vty.h index 044e6433d1..73e0d238ad 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -421,7 +421,7 @@ 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_data_req(struct vty *vty, LYD_FORMAT result_type, - const char *xpath); + uint8_t flags, 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, int ret); diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index 6527677d31..d91987d888 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -1181,7 +1181,7 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, darr_free(snodes); clients = mgmt_be_interested_clients(msg->xpath, false); - if (!clients) { + if (!clients && !CHECK_FLAG(msg->flags, GET_DATA_FLAG_CONFIG)) { MGMTD_FE_ADAPTER_DBG("No backends provide xpath: %s for txn-id: %" PRIu64 " session-id: %" PRIu64, msg->xpath, session->txn_id, @@ -1207,8 +1207,8 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, /* Create a GET-TREE request under the transaction */ ret = mgmt_txn_send_get_tree_oper(session->txn_id, req_id, clients, - msg->result_type, simple_xpath, - msg->xpath); + msg->result_type, msg->flags, + simple_xpath, msg->xpath); if (ret) { /* destroy the just created txn */ mgmt_destroy_txn(&session->txn_id); diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index 679eaa7d7f..3a2a23d9e9 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -2364,7 +2364,8 @@ int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id, */ int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id, uint64_t clients, LYD_FORMAT result_type, - bool simple_xpath, const char *xpath) + uint8_t flags, bool simple_xpath, + const char *xpath) { struct mgmt_msg_get_tree *msg; struct mgmt_txn_ctx *txn; @@ -2385,6 +2386,57 @@ int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id, get_tree->simple_xpath = simple_xpath; get_tree->xpath = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); + if (CHECK_FLAG(flags, GET_DATA_FLAG_CONFIG)) { + struct mgmt_ds_ctx *ds = + mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_RUNNING); + struct nb_config *config = mgmt_ds_get_nb_config(ds); + + if (config) { + struct ly_set *set = NULL; + LY_ERR err; + + err = lyd_find_xpath(config->dnode, xpath, &set); + if (err) { + get_tree->partial_error = err; + goto state; + } + + /* + * If there's a single result, duplicate the returned + * node. If there are multiple results, duplicate the + * whole config and mark simple_xpath as false so the + * result is trimmed later in txn_get_tree_data_done. + */ + if (set->count == 1) { + err = lyd_dup_single(set->dnodes[0], NULL, + LYD_DUP_WITH_PARENTS | + LYD_DUP_WITH_FLAGS | + LYD_DUP_RECURSIVE, + &get_tree->client_results); + if (!err) + while (get_tree->client_results->parent) + get_tree->client_results = lyd_parent( + get_tree->client_results); + } else if (set->count > 1) { + err = lyd_dup_siblings(config->dnode, NULL, + LYD_DUP_RECURSIVE | + LYD_DUP_WITH_FLAGS, + &get_tree->client_results); + if (!err) + get_tree->simple_xpath = false; + } + + if (err) + get_tree->partial_error = err; + + ly_set_free(set, NULL); + } + } +state: + /* If we are only getting config, we are done */ + if (!CHECK_FLAG(flags, GET_DATA_FLAG_STATE) || !clients) + return txn_get_tree_data_done(txn, txn_req); + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_get_tree, slen + 1, MTYPE_MSG_NATIVE_GET_TREE); msg->refer_id = txn_id; diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h index 39d8cde169..3f27f2f07b 100644 --- a/mgmtd/mgmt_txn.h +++ b/mgmtd/mgmt_txn.h @@ -203,6 +203,7 @@ extern int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id, * req_id: FE client request identifier. * clients: Bitmask of clients to send get-tree to. * result_type: LYD_FORMAT result format. + * flags: option flags for the request. * simple_xpath: true if xpath is simple (only key predicates). * xpath: The xpath to get the tree from. * @@ -211,7 +212,8 @@ extern int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id, */ extern int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id, uint64_t clients, LYD_FORMAT result_type, - bool simple_xpath, const char *xpath); + uint8_t flags, bool simple_xpath, + const char *xpath); /* * Notifiy backend adapter on connection. diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index 98e55788b4..e6f74c3129 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -251,17 +251,23 @@ DEFPY(show_mgmt_get_config, show_mgmt_get_config_cmd, } DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd, - "show mgmt get-data WORD$path [json|xml]$fmt", + "show mgmt get-data WORD$path [with-config|only-config]$content [json|xml]$fmt", SHOW_STR MGMTD_STR "Get a data from the operational datastore\n" "XPath expression specifying the YANG data root\n" + "Include \"config true\" data\n" + "Get only \"config true\" data\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; + uint8_t flags = content ? GET_DATA_FLAG_CONFIG : GET_DATA_FLAG_STATE; + + if (content && content[0] == 'w') + flags |= GET_DATA_FLAG_STATE; /* get rid of extraneous trailing slash-* or single '/' unless root */ if (plen > 2 && ((path[plen - 2] == '/' && path[plen - 1] == '*') || @@ -272,7 +278,7 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd, path = xpath; } - vty_mgmt_send_get_data_req(vty, format, path); + vty_mgmt_send_get_data_req(vty, format, flags, path); if (xpath) XFREE(MTYPE_TMP, xpath); -- 2.39.5