summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorIgor Ryzhov <iryzhov@nfware.com>2024-03-18 18:08:23 +0100
committerIgor Ryzhov <iryzhov@nfware.com>2024-04-22 15:36:22 +0200
commit58a8ebc1fca07ba963faf60d54d77336f36e5ded (patch)
tree861d58a483ac4907ff4e4c43d3dbdb9cce840cd9 /lib
parentMerge pull request #15468 from idryzhov/mgmt-native-edit (diff)
downloadfrr-58a8ebc1fca07ba963faf60d54d77336f36e5ded.tar.xz
frr-58a8ebc1fca07ba963faf60d54d77336f36e5ded.zip
lib: rework northbound RPC callback
Change input/output arguments of the RPC callback from lists of (xpath/value) tuples to YANG data trees. Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/northbound.c7
-rw-r--r--lib/northbound.h10
-rw-r--r--lib/northbound_cli.c59
-rw-r--r--lib/northbound_cli.h34
-rw-r--r--lib/northbound_grpc.cpp61
-rw-r--r--lib/northbound_sysrepo.c65
-rw-r--r--lib/vty.h4
7 files changed, 140 insertions, 100 deletions
diff --git a/lib/northbound.c b/lib/northbound.c
index 9a5d67cd1..57068cc4e 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -1820,14 +1820,11 @@ const void *nb_callback_lookup_next(const struct nb_node *nb_node,
}
int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath,
- const struct list *input, struct list *output, char *errmsg,
- size_t errmsg_len)
+ const struct lyd_node *input, struct lyd_node *output,
+ char *errmsg, size_t errmsg_len)
{
struct nb_cb_rpc_args args = {};
- if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS))
- return 0;
-
DEBUGD(&nb_dbg_cbs_rpc, "northbound RPC: %s", xpath);
args.xpath = xpath;
diff --git a/lib/northbound.h b/lib/northbound.h
index 3bf1eacd6..34d17a587 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -274,11 +274,11 @@ struct nb_cb_rpc_args {
/* XPath of the YANG RPC or action. */
const char *xpath;
- /* Read-only list of input parameters. */
- const struct list *input;
+ /* Read-only "input" tree of the RPC/action. */
+ const struct lyd_node *input;
- /* List of output parameters to be populated by the callback. */
- struct list *output;
+ /* The "output" tree of the RPC/action to be populated by the callback. */
+ struct lyd_node *output;
/* Buffer to store human-readable error message in case of error. */
char *errmsg;
@@ -833,7 +833,7 @@ extern const void *nb_callback_lookup_next(const struct nb_node *nb_node,
const void *parent_list_entry,
const struct yang_list_keys *keys);
extern int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath,
- const struct list *input, struct list *output,
+ const struct lyd_node *input, struct lyd_node *output,
char *errmsg, size_t errmsg_len);
extern void nb_callback_notify(const struct nb_node *nb_node, const char *xpath,
struct lyd_node *dnode);
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 8809ec2ad..5be64f013 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -275,10 +275,31 @@ int nb_cli_apply_changes_clear_pending(struct vty *vty,
return nb_cli_apply_changes_internal(vty, xpath_base_abs, true);
}
-int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input,
- struct list *output)
+int nb_cli_rpc_enqueue(struct vty *vty, const char *xpath, const char *value)
+{
+ struct nb_cfg_change *param;
+
+ if (vty->num_rpc_params == VTY_MAXCFGCHANGES) {
+ /* Not expected to happen. */
+ vty_out(vty,
+ "%% Exceeded the maximum number of params (%u) for a single command\n\n",
+ VTY_MAXCFGCHANGES);
+ return CMD_WARNING;
+ }
+
+ param = &vty->rpc_params[vty->num_rpc_params++];
+ strlcpy(param->xpath, xpath, sizeof(param->xpath));
+ param->value = value;
+
+ return CMD_SUCCESS;
+}
+
+int nb_cli_rpc(struct vty *vty, const char *xpath, struct lyd_node **output_p)
{
struct nb_node *nb_node;
+ struct lyd_node *input = NULL;
+ struct lyd_node *output = NULL;
+ LY_ERR err;
int ret;
char errmsg[BUFSIZ] = {0};
@@ -289,12 +310,46 @@ int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input,
return CMD_WARNING;
}
+ /* create input tree */
+ err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, 0, NULL,
+ &input);
+ assert(err == LY_SUCCESS);
+
+ for (size_t i = 0; i < vty->num_rpc_params; i++) {
+ err = lyd_new_path(input, ly_native_ctx,
+ vty->rpc_params[i].xpath,
+ vty->rpc_params[i].value, 0, NULL);
+ assert(err == LY_SUCCESS);
+ }
+
+ /* validate input tree to create implicit defaults */
+ err = lyd_validate_op(input, NULL, LYD_TYPE_RPC_YANG, NULL);
+ assert(err == LY_SUCCESS);
+
+ /* create output tree root for population in the callback */
+ err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, 0, NULL,
+ &output);
+ assert(err == LY_SUCCESS);
+
ret = nb_callback_rpc(nb_node, xpath, input, output, errmsg,
sizeof(errmsg));
+
+ /* validate output tree to create implicit defaults */
+ err = lyd_validate_op(output, NULL, LYD_TYPE_REPLY_YANG, NULL);
+ assert(err == LY_SUCCESS);
+
+ lyd_free_all(input);
+ vty->num_rpc_params = 0;
+
switch (ret) {
case NB_OK:
+ if (output_p)
+ *output_p = output;
+ else
+ lyd_free_all(output);
return CMD_SUCCESS;
default:
+ lyd_free_all(output);
if (strlen(errmsg))
vty_show_nb_errors(vty, ret, errmsg);
return CMD_WARNING;
diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h
index 1a45794d4..4c8dc50bd 100644
--- a/lib/northbound_cli.h
+++ b/lib/northbound_cli.h
@@ -80,7 +80,23 @@ extern int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt,
...) PRINTFRR(2, 3);
/*
- * Execute a YANG RPC or Action.
+ * Add an input child node for an RPC or an action.
+ *
+ * vty
+ * The vty context.
+ *
+ * xpath
+ * XPath of the child being added, relative to the input container.
+ *
+ * value
+ * Value of the child being added. Can be NULL for containers and leafs of
+ * type 'empty'.
+ */
+extern int nb_cli_rpc_enqueue(struct vty *vty, const char *xpath,
+ const char *value);
+
+/*
+ * Execute a YANG RPC or Action using the enqueued input parameters.
*
* vty
* The vty terminal to dump any error.
@@ -88,20 +104,16 @@ extern int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt,
* xpath
* XPath of the YANG RPC or Action node.
*
- * input
- * List of 'yang_data' structures containing the RPC input parameters. It
- * can be set to NULL when there are no input parameters.
- *
- * output
- * List of 'yang_data' structures used to retrieve the RPC output parameters.
- * It can be set to NULL when it's known that the given YANG RPC or Action
- * doesn't have any output parameters.
+ * output_p
+ * A pointer to the libyang data node that will hold the output data tree.
+ * It can be set to NULL if the caller is not interested in processing the
+ * output. The caller is responsible for freeing the output data tree.
*
* Returns:
* CMD_SUCCESS on success, CMD_WARNING otherwise.
*/
-extern int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input,
- struct list *output);
+extern int nb_cli_rpc(struct vty *vty, const char *xpath,
+ struct lyd_node **output_p);
/*
* Show CLI commands associated to the given YANG data node.
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 795775258..612ec3981 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -1011,12 +1011,11 @@ grpc::Status HandleUnaryExecute(
grpc_debug("%s: entered", __func__);
struct nb_node *nb_node;
- struct list *input_list;
- struct list *output_list;
- struct listnode *node;
- struct yang_data *data;
+ struct lyd_node *input_tree, *output_tree, *child;
const char *xpath;
char errmsg[BUFSIZ] = {0};
+ char path[XPATH_MAXLEN];
+ LY_ERR err;
// Request: string path = 1;
xpath = tag->request.path().c_str();
@@ -1032,40 +1031,66 @@ grpc::Status HandleUnaryExecute(
return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
"Unknown data path");
- input_list = yang_data_list_new();
- output_list = yang_data_list_new();
+ // Create input data tree.
+ err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0,
+ (LYD_ANYDATA_VALUETYPE)0, 0, NULL, &input_tree);
+ if (err != LY_SUCCESS) {
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Invalid data path");
+ }
// Read input parameters.
auto input = tag->request.input();
for (const frr::PathValue &pv : input) {
// Request: repeated PathValue input = 2;
- data = yang_data_new(pv.path().c_str(), pv.value().c_str());
- listnode_add(input_list, data);
+ err = lyd_new_path(input_tree, ly_native_ctx, pv.path().c_str(),
+ pv.value().c_str(), 0, NULL);
+ if (err != LY_SUCCESS) {
+ lyd_free_tree(input_tree);
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Invalid input data");
+ }
+ }
+
+ // Validate input data.
+ err = lyd_validate_op(input_tree, NULL, LYD_TYPE_RPC_YANG, NULL);
+ if (err != LY_SUCCESS) {
+ lyd_free_tree(input_tree);
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Invalid input data");
+ }
+
+ // Create output data tree.
+ err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0,
+ (LYD_ANYDATA_VALUETYPE)0, 0, NULL, &output_tree);
+ if (err != LY_SUCCESS) {
+ lyd_free_tree(input_tree);
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ "Invalid data path");
}
// Execute callback registered for this XPath.
- if (nb_callback_rpc(nb_node, xpath, input_list, output_list, errmsg,
- sizeof(errmsg))
- != NB_OK) {
+ if (nb_callback_rpc(nb_node, xpath, input_tree, output_tree, errmsg,
+ sizeof(errmsg)) != NB_OK) {
flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s",
__func__, xpath);
- list_delete(&input_list);
- list_delete(&output_list);
+ lyd_free_tree(input_tree);
+ lyd_free_tree(output_tree);
return grpc::Status(grpc::StatusCode::INTERNAL, "RPC failed");
}
// Process output parameters.
- for (ALL_LIST_ELEMENTS_RO(output_list, node, data)) {
+ LY_LIST_FOR (lyd_child(output_tree), child) {
// Response: repeated PathValue output = 1;
frr::PathValue *pv = tag->response.add_output();
- pv->set_path(data->xpath);
- pv->set_value(data->value);
+ pv->set_path(lyd_path(child, LYD_PATH_STD, path, sizeof(path)));
+ pv->set_value(yang_dnode_get_string(child, NULL));
}
// Release memory.
- list_delete(&input_list);
- list_delete(&output_list);
+ lyd_free_tree(input_tree);
+ lyd_free_tree(output_tree);
return grpc::Status::OK;
}
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 640334926..0ec7610a9 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -377,16 +377,11 @@ static int frr_sr_state_cb(sr_session_ctx_t *session, uint32_t sub_id,
return SR_ERR_OK;
}
static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, uint32_t sub_id,
- const char *xpath, const sr_val_t *sr_input,
- const size_t input_cnt, sr_event_t sr_ev,
- uint32_t request_id, sr_val_t **sr_output,
- size_t *sr_output_cnt, void *private_ctx)
+ const char *xpath, const struct lyd_node *input,
+ sr_event_t sr_ev, uint32_t request_id,
+ struct lyd_node *output, void *private_ctx)
{
struct nb_node *nb_node;
- struct list *input;
- struct list *output;
- struct yang_data *data;
- size_t cb_output_cnt;
int ret = SR_ERR_OK;
char errmsg[BUFSIZ] = {0};
@@ -397,19 +392,6 @@ static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, uint32_t sub_id,
return SR_ERR_INTERNAL;
}
- input = yang_data_list_new();
- output = yang_data_list_new();
-
- /* Process input. */
- for (size_t i = 0; i < input_cnt; i++) {
- char value_str[YANG_VALUE_MAXLEN];
-
- sr_val_to_buff(&sr_input[i], value_str, sizeof(value_str));
-
- data = yang_data_new(xpath, value_str);
- listnode_add(input, data);
- }
-
/* Execute callback registered for this XPath. */
if (nb_callback_rpc(nb_node, xpath, input, output, errmsg,
sizeof(errmsg))
@@ -417,44 +399,8 @@ static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, uint32_t sub_id,
flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s",
__func__, xpath);
ret = SR_ERR_OPERATION_FAILED;
- goto exit;
}
- /* Process output. */
- if (listcount(output) > 0) {
- sr_val_t *values = NULL;
- struct listnode *node;
- int i = 0;
-
- cb_output_cnt = listcount(output);
- ret = sr_new_values(cb_output_cnt, &values);
- if (ret != SR_ERR_OK) {
- flog_err(EC_LIB_LIBSYSREPO, "%s: sr_new_values(): %s",
- __func__, sr_strerror(ret));
- goto exit;
- }
-
- for (ALL_LIST_ELEMENTS_RO(output, node, data)) {
- if (yang_data_frr2sr(data, &values[i++]) != 0) {
- flog_err(
- EC_LIB_SYSREPO_DATA_CONVERT,
- "%s: failed to convert data to Sysrepo format",
- __func__);
- ret = SR_ERR_INTERNAL;
- sr_free_values(values, cb_output_cnt);
- goto exit;
- }
- }
-
- *sr_output = values;
- *sr_output_cnt = cb_output_cnt;
- }
-
-exit:
- /* Release memory. */
- list_delete(&input);
- list_delete(&output);
-
return ret;
}
@@ -579,8 +525,9 @@ static int frr_sr_subscribe_rpc(const struct lysc_node *snode, void *arg)
DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: providing RPC to '%s'",
nb_node->xpath);
- ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
- NULL, 0, 0, &module->sr_subscription);
+ ret = sr_rpc_subscribe_tree(session, nb_node->xpath,
+ frr_sr_config_rpc_cb, NULL, 0, 0,
+ &module->sr_subscription);
if (ret != SR_ERR_OK)
flog_err(EC_LIB_LIBSYSREPO, "sr_rpc_subscribe(): %s",
sr_strerror(ret));
diff --git a/lib/vty.h b/lib/vty.h
index 0e0c92c33..a51cee76f 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -122,6 +122,10 @@ struct vty {
size_t num_cfg_changes;
struct nb_cfg_change cfg_changes[VTY_MAXCFGCHANGES];
+ /* Input parameters */
+ size_t num_rpc_params;
+ struct nb_cfg_change rpc_params[VTY_MAXCFGCHANGES];
+
/* XPath of the current node */
int xpath_index;
char xpath[VTY_MAXDEPTH][XPATH_MAXLEN];