From 4317c8ffa6675c9f91b710c7c75739706e1edfef Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 29 Jan 2024 22:50:26 +0200 Subject: [PATCH] mgmtd: add support for with-defaults parameter to get-data Signed-off-by: Igor Ryzhov --- lib/mgmt_fe_client.c | 8 +++++--- lib/mgmt_fe_client.h | 5 ++++- lib/mgmt_msg_native.h | 11 +++++++++++ lib/vty.c | 5 +++-- lib/vty.h | 3 ++- mgmtd/mgmt_fe_adapter.c | 33 +++++++++++++++++++++++++++------ mgmtd/mgmt_fe_adapter.h | 12 ++++++------ mgmtd/mgmt_main.c | 13 +++++++++++++ mgmtd/mgmt_txn.c | 7 +++++-- mgmtd/mgmt_txn.h | 5 +++-- mgmtd/mgmt_vty.c | 18 ++++++++++++++++-- mgmtd/subdir.am | 3 +++ 12 files changed, 98 insertions(+), 25 deletions(-) diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c index e94a6d291f..19fbdaf1bd 100644 --- a/lib/mgmt_fe_client.c +++ b/lib/mgmt_fe_client.c @@ -308,9 +308,10 @@ 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, - uint8_t flags, 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, + uint8_t defaults, const char *xpath) { struct mgmt_msg_get_data *msg; size_t xplen = strlen(xpath); @@ -323,6 +324,7 @@ int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, uint64_t session_id msg->code = MGMT_MSG_CODE_GET_DATA; msg->result_type = result_type; msg->flags = flags; + msg->defaults = defaults; 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 018f71ddf8..17ec354a1a 100644 --- a/lib/mgmt_fe_client.h +++ b/lib/mgmt_fe_client.h @@ -390,6 +390,9 @@ extern int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client, * flags * Flags to control the behavior of the request. * + * defaults + * Options to control the reporting of default values. + * * xpath * the xpath to get. * @@ -399,7 +402,7 @@ 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, uint8_t flags, - const char *xpath); + uint8_t defaults, const char *xpath); /* * Destroy library and cleanup everything. diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index 93a94fc15c..b26f07a643 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -240,17 +240,28 @@ _Static_assert(sizeof(struct mgmt_msg_tree_data) == #define GET_DATA_FLAG_CONFIG 0x02 /* get only "config true" data */ #define GET_DATA_FLAG_EXACT 0x04 /* get exact data node instead of the full tree */ +/* + * Modes of reporting default values. Non-default values are always reported. + * These options reflect "with-defaults" modes as defined in RFC 6243. + */ +#define GET_DATA_DEFAULTS_EXPLICIT 0 /* "explicit" */ +#define GET_DATA_DEFAULTS_TRIM 1 /* "trim" */ +#define GET_DATA_DEFAULTS_ALL 2 /* "report-all" */ +#define GET_DATA_DEFAULTS_ALL_ADD_TAG 3 /* "report-all-tagged" */ + /** * struct mgmt_msg_get_data - frontend get-data request. * * @result_type: ``LYD_FORMAT`` for the returned result. * @flags: combination of ``GET_DATA_FLAG_*`` flags. + * @defaults: one of ``GET_DATA_DEFAULTS_*`` values. * @xpath: the query for the data to return. */ struct mgmt_msg_get_data { struct mgmt_msg_header; uint8_t result_type; uint8_t flags; + uint8_t defaults; uint8_t resv2[6]; alignas(8) char xpath[]; diff --git a/lib/vty.c b/lib/vty.c index ea35c541ee..c082c8385c 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -4102,7 +4102,8 @@ 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, - uint8_t flags, const char *xpath) + uint8_t flags, uint8_t defaults, + const char *xpath) { LYD_FORMAT intern_format = result_type; @@ -4110,7 +4111,7 @@ int vty_mgmt_send_get_data_req(struct vty *vty, LYD_FORMAT result_type, if (mgmt_fe_send_get_data_req(mgmt_fe_client, vty->mgmt_session_id, vty->mgmt_req_id, intern_format, flags, - xpath)) { + 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); diff --git a/lib/vty.h b/lib/vty.h index 73e0d238ad..7244aeceed 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -421,7 +421,8 @@ 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, - uint8_t flags, const char *xpath); + uint8_t flags, uint8_t defaults, + 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 95f925d307..acf77f552b 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -1080,7 +1080,7 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, */ static int fe_adapter_send_tree_data(struct mgmt_fe_session_ctx *session, uint64_t req_id, bool short_circuit_ok, - uint8_t result_type, + uint8_t result_type, uint32_t wd_options, const struct lyd_node *tree, int partial_error) @@ -1105,8 +1105,7 @@ static int fe_adapter_send_tree_data(struct mgmt_fe_session_ctx *session, darrp = mgmt_msg_native_get_darrp(msg); ret = yang_print_tree_append(darrp, tree, result_type, - (LYD_PRINT_WD_EXPLICIT | - LYD_PRINT_WITHSIBLINGS)); + (wd_options | LYD_PRINT_WITHSIBLINGS)); if (ret != LY_SUCCESS) { MGMTD_FE_ADAPTER_ERR("Error building get-tree result for client %s session-id %" PRIu64 " req-id %" PRIu64 @@ -1147,6 +1146,7 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, char *xpath_resolved = NULL; uint64_t req_id = msg->req_id; uint64_t clients; + uint32_t wd_options; bool simple_xpath; LY_ERR err; int ret; @@ -1171,6 +1171,25 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, goto done; } + switch (msg->defaults) { + case GET_DATA_DEFAULTS_EXPLICIT: + wd_options = LYD_PRINT_WD_EXPLICIT; + break; + case GET_DATA_DEFAULTS_TRIM: + wd_options = LYD_PRINT_WD_TRIM; + break; + case GET_DATA_DEFAULTS_ALL: + wd_options = LYD_PRINT_WD_ALL; + break; + case GET_DATA_DEFAULTS_ALL_ADD_TAG: + wd_options = LYD_PRINT_WD_IMPL_TAG; + break; + default: + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid defaults value %u for session-id: %" PRIu64, + msg->defaults, session->session_id); + goto done; + } err = yang_resolve_snode_xpath(ly_native_ctx, msg->xpath, &snodes, &simple_xpath); @@ -1190,7 +1209,7 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, session->session_id); fe_adapter_send_tree_data(session, req_id, false, - msg->result_type, NULL, 0); + msg->result_type, wd_options, NULL, 0); goto done; } @@ -1210,7 +1229,7 @@ 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, msg->flags, - simple_xpath, msg->xpath); + wd_options, simple_xpath, msg->xpath); if (ret) { /* destroy the just created txn */ mgmt_destroy_txn(&session->txn_id); @@ -1469,6 +1488,7 @@ int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id, int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id, uint64_t req_id, LYD_FORMAT result_type, + uint32_t wd_options, const struct lyd_node *tree, int partial_error, bool short_circuit_ok) { @@ -1480,7 +1500,8 @@ int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id, return -1; ret = fe_adapter_send_tree_data(session, req_id, short_circuit_ok, - result_type, tree, partial_error); + result_type, wd_options, tree, + partial_error); mgmt_destroy_txn(&session->txn_id); diff --git a/mgmtd/mgmt_fe_adapter.h b/mgmtd/mgmt_fe_adapter.h index 09d64415bc..2150f864d9 100644 --- a/mgmtd/mgmt_fe_adapter.h +++ b/mgmtd/mgmt_fe_adapter.h @@ -148,6 +148,7 @@ extern int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id, * txn_id: the txn_id this data pertains to * req_id: the req id for the get_tree message * result_type: the format of the result data. + * wd_options: with-defaults options. * tree: the results. * partial_error: if there were errors while gather results. * short_circuit_ok: True if OK to short-circuit the call. @@ -156,12 +157,11 @@ extern int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id, * the return value from the underlying send function. * */ -extern int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id, - uint64_t req_id, - LYD_FORMAT result_type, - const struct lyd_node *tree, - int partial_error, - bool short_circuit_ok); +extern int +mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id, + uint64_t req_id, LYD_FORMAT result_type, + uint32_t wd_options, const struct lyd_node *tree, + int partial_error, bool short_circuit_ok); /** * Send an error back to the FE client using native messaging. diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c index 6dbd1f2e52..5be849b63c 100644 --- a/mgmtd/mgmt_main.c +++ b/mgmtd/mgmt_main.c @@ -144,6 +144,16 @@ static struct frr_signal_t mgmt_signals[] = { extern const struct frr_yang_module_info frr_staticd_cli_info; #endif +/* + * These are modules that are only needed by mgmtd and hence not included into + * the lib and backend daemons. + */ +const struct frr_yang_module_info ietf_netconf_with_defaults_info = { + .name = "ietf-netconf-with-defaults", + .ignore_cfg_cbs = true, + .nodes = { { .xpath = NULL } }, +}; + /* * These are stub info structs that are used to load the modules used by backend * clients into mgmtd. The modules are used by libyang in order to support @@ -167,6 +177,9 @@ static const struct frr_yang_module_info *const mgmt_yang_modules[] = { &frr_vrf_info, &frr_affinity_map_cli_info, + /* mgmtd-only modules */ + &ietf_netconf_with_defaults_info, + /* * YANG module info used by backend clients get added here. */ diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index 7f88524e85..926b1574a1 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -175,6 +175,7 @@ struct txn_req_get_tree { uint64_t recv_clients; /* Bitmask of clients recv reply from */ int32_t partial_error; /* an error while gather results */ uint8_t result_type; /* LYD_FORMAT for results */ + uint8_t wd_options; /* LYD_PRINT_WD_* flags for results */ uint8_t exact; /* if exact node is requested */ uint8_t simple_xpath; /* if xpath is simple */ struct lyd_node *client_results; /* result tree from clients */ @@ -1282,6 +1283,7 @@ static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn, txn->txn_id, txn_req->req_id, get_tree->result_type, + get_tree->wd_options, result, get_tree->partial_error, false); @@ -2340,8 +2342,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, - uint8_t flags, bool simple_xpath, - const char *xpath) + uint8_t flags, uint32_t wd_options, + bool simple_xpath, const char *xpath) { struct mgmt_msg_get_tree *msg; struct mgmt_txn_ctx *txn; @@ -2359,6 +2361,7 @@ int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id, txn_req = mgmt_txn_req_alloc(txn, req_id, MGMTD_TXN_PROC_GETTREE); get_tree = txn_req->req.get_tree; get_tree->result_type = result_type; + get_tree->wd_options = wd_options; get_tree->exact = CHECK_FLAG(flags, GET_DATA_FLAG_EXACT); get_tree->simple_xpath = simple_xpath; get_tree->xpath = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h index 02b2baa95f..ad2e38fb0f 100644 --- a/mgmtd/mgmt_txn.h +++ b/mgmtd/mgmt_txn.h @@ -204,6 +204,7 @@ extern int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id, * clients: Bitmask of clients to send get-tree to. * result_type: LYD_FORMAT result format. * flags: option flags for the request. + * wd_options: LYD_PRINT_WD_* flags for the result. * simple_xpath: true if xpath is simple (only key predicates). * xpath: The xpath to get the tree from. * @@ -212,8 +213,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, - uint8_t flags, bool simple_xpath, - const char *xpath); + uint8_t flags, uint32_t wd_options, + bool simple_xpath, const char *xpath); /* * Notifiy backend adapter on connection. diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index 7135bc5547..7c9c3c6fe0 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -258,7 +258,7 @@ 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 [with-config|only-config]$content [exact]$exact [json|xml]$fmt", + "show mgmt get-data WORD$path [with-config|only-config]$content [exact]$exact [with-defaults $wd] [json|xml]$fmt", SHOW_STR MGMTD_STR "Get a data from the operational datastore\n" @@ -266,6 +266,10 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd, "Include \"config true\" data\n" "Get only \"config true\" data\n" "Get exact node instead of the whole data tree\n" + "Configure 'with-defaults' mode per RFC 6243 (\"explicit\" mode by default)\n" + "Use \"trim\" mode\n" + "Use \"report-all-tagged\" mode\n" + "Use \"report-all\" mode\n" "JSON output format\n" "XML output format\n") { @@ -273,6 +277,7 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd, int plen = strlen(path); char *xpath = NULL; uint8_t flags = content ? GET_DATA_FLAG_CONFIG : GET_DATA_FLAG_STATE; + uint8_t defaults = GET_DATA_DEFAULTS_EXPLICIT; if (content && content[0] == 'w') flags |= GET_DATA_FLAG_STATE; @@ -280,6 +285,15 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd, if (exact) flags |= GET_DATA_FLAG_EXACT; + if (wd) { + if (wd[0] == 't') + defaults = GET_DATA_DEFAULTS_TRIM; + else if (wd[3] == '-') + defaults = GET_DATA_DEFAULTS_ALL_ADD_TAG; + else + defaults = GET_DATA_DEFAULTS_ALL; + } + /* 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] == '/'))) { @@ -289,7 +303,7 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd, path = xpath; } - vty_mgmt_send_get_data_req(vty, format, flags, path); + vty_mgmt_send_get_data_req(vty, format, flags, defaults, path); if (xpath) XFREE(MTYPE_TMP, xpath); diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am index fa8025c0e2..0af64dc0be 100644 --- a/mgmtd/subdir.am +++ b/mgmtd/subdir.am @@ -61,6 +61,9 @@ mgmtd_mgmtd_SOURCES = \ # end nodist_mgmtd_mgmtd_SOURCES = \ yang/frr-zebra.yang.c \ + yang/ietf/ietf-netconf-acm.yang.c \ + yang/ietf/ietf-netconf.yang.c \ + yang/ietf/ietf-netconf-with-defaults.yang.c \ # nothing mgmtd_mgmtd_CFLAGS = $(AM_CFLAGS) -I ./ mgmtd_mgmtd_LDADD = mgmtd/libmgmtd.a lib/libfrr.la $(LIBCAP) $(LIBM) $(LIBYANG_LIBS) $(UST_LIBS) -- 2.39.5