]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: add native RPC processing to mgmt frontend client
authorIgor Ryzhov <iryzhov@nfware.com>
Tue, 19 Mar 2024 22:46:07 +0000 (00:46 +0200)
committerIgor Ryzhov <iryzhov@nfware.com>
Mon, 22 Apr 2024 13:36:23 +0000 (16:36 +0300)
Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
lib/mgmt_fe_client.c
lib/mgmt_fe_client.h
lib/northbound_cli.c
lib/vty.c
lib/vty.h
mgmtd/mgmt_vty.c

index 3345505213ffba7b034f4277a74c95a082cb6125..8cfb025f7225ea5afdf0a7d5530f995fe40d5893 100644 (file)
@@ -360,6 +360,33 @@ int mgmt_fe_send_edit_req(struct mgmt_fe_client *client, uint64_t session_id,
        return ret;
 }
 
+int mgmt_fe_send_rpc_req(struct mgmt_fe_client *client, uint64_t session_id,
+                        uint64_t req_id, LYD_FORMAT request_type,
+                        const char *xpath, const char *data)
+{
+       struct mgmt_msg_rpc *msg;
+       int ret;
+
+       msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_rpc, 0,
+                                       MTYPE_MSG_NATIVE_RPC);
+       msg->refer_id = session_id;
+       msg->req_id = req_id;
+       msg->code = MGMT_MSG_CODE_RPC;
+       msg->request_type = request_type;
+
+       mgmt_msg_native_xpath_encode(msg, xpath);
+       if (data)
+               mgmt_msg_native_append(msg, data, strlen(data) + 1);
+
+       debug_fe_client("Sending RPC_REQ session-id %" PRIu64 " req-id %" PRIu64
+                       " xpath: %s",
+                       session_id, req_id, xpath);
+
+       ret = mgmt_msg_native_send_msg(&client->client.conn, msg, false);
+       mgmt_msg_native_free_msg(msg);
+       return ret;
+}
+
 static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
                                     Mgmtd__FeMessage *fe_msg)
 {
@@ -534,6 +561,7 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
        struct mgmt_msg_notify_data *notify_msg;
        struct mgmt_msg_tree_data *tree_msg;
        struct mgmt_msg_edit_reply *edit_msg;
+       struct mgmt_msg_rpc_reply *rpc_msg;
        struct mgmt_msg_error *err_msg;
        const char *xpath = NULL;
        const char *data = NULL;
@@ -608,6 +636,23 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
                                                 session->user_ctx, msg->req_id,
                                                 xpath);
                break;
+       case MGMT_MSG_CODE_RPC_REPLY:
+               if (!session->client->cbs.rpc_notify)
+                       return;
+
+               rpc_msg = (typeof(rpc_msg))msg;
+               if (msg_len < sizeof(*rpc_msg)) {
+                       log_err_fe_client("Corrupt rpc-reply msg recv");
+                       return;
+               }
+               dlen = msg_len - sizeof(*rpc_msg);
+
+               session->client->cbs.rpc_notify(client, client->user_data,
+                                               session->client_id,
+                                               msg->refer_id,
+                                               session->user_ctx, msg->req_id,
+                                               dlen ? rpc_msg->data : NULL);
+               break;
        case MGMT_MSG_CODE_NOTIFY:
                if (!session->client->cbs.async_notification)
                        return;
index 9d569348ae5832643773d71d2bdc9abf3e934d1d..20c87044a5e406518ba240c482669f3d953ad56f 100644 (file)
@@ -120,6 +120,12 @@ struct mgmt_fe_client_cbs {
                           uintptr_t session_ctx, uint64_t req_id,
                           const char *xpath);
 
+       /* Called when RPC result is returned */
+       int (*rpc_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,
+                         const char *result);
+
        /* Called with asynchronous notifications from backends */
        int (*async_notification)(struct mgmt_fe_client *client,
                                  uintptr_t user_data, uint64_t client_id,
@@ -454,6 +460,35 @@ extern int mgmt_fe_send_edit_req(struct mgmt_fe_client *client,
                                 uint8_t flags, uint8_t operation,
                                 const char *xpath, const char *data);
 
+/*
+ * Send RPC request 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 of the RPC.
+ *
+ * data
+ *    the data tree.
+ *
+ * Returns:
+ *    0 on success, otherwise msg_conn_send_msg() return values.
+ */
+extern int mgmt_fe_send_rpc_req(struct mgmt_fe_client *client,
+                               uint64_t session_id, uint64_t req_id,
+                               LYD_FORMAT request_type, const char *xpath,
+                               const char *data);
+
 /*
  * Destroy library and cleanup everything.
  */
index 5be64f01346f1ad3891ad94a81fdd5b3a97d1c94..4f962cda5c1d73a9668983558a14b08e6bc8cc02 100644 (file)
@@ -322,6 +322,22 @@ int nb_cli_rpc(struct vty *vty, const char *xpath, struct lyd_node **output_p)
                assert(err == LY_SUCCESS);
        }
 
+       if (vty_mgmt_fe_enabled()) {
+               char *data = NULL;
+
+               err = lyd_print_mem(&data, input, LYD_JSON, LYD_PRINT_SHRINK);
+               assert(err == LY_SUCCESS);
+
+               ret = vty_mgmt_send_rpc_req(vty, LYD_JSON, xpath, data);
+
+               free(data);
+               lyd_free_all(input);
+
+               if (ret < 0)
+                       return CMD_WARNING;
+               return CMD_SUCCESS;
+       }
+
        /* validate input tree to create implicit defaults */
        err = lyd_validate_op(input, NULL, LYD_TYPE_RPC_YANG, NULL);
        assert(err == LY_SUCCESS);
index d69b5eebd270b3db9ef0d2cab6a5c7c796128f8a..0a2a7552f8e4b8593fdf16965259520e4be2656c 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -3843,6 +3843,26 @@ static int vty_mgmt_edit_result_notified(struct mgmt_fe_client *client,
        return 0;
 }
 
+static int vty_mgmt_rpc_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,
+                                       const char *result)
+{
+       struct vty *vty = (struct vty *)session_ctx;
+
+       debug_fe_client("RPC request for client 0x%" PRIx64 " req-id %" PRIu64
+                       " was successful",
+                       client_id, req_id);
+
+       if (result)
+               vty_out(vty, "%s\n", result);
+
+       vty_mgmt_resume_response(vty, CMD_SUCCESS);
+
+       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,
@@ -3885,6 +3905,7 @@ static struct mgmt_fe_client_cbs mgmt_cbs = {
        .get_data_notify = vty_mgmt_get_data_result_notified,
        .get_tree_notify = vty_mgmt_get_tree_result_notified,
        .edit_notify = vty_mgmt_edit_result_notified,
+       .rpc_notify = vty_mgmt_rpc_result_notified,
        .error_notify = vty_mgmt_error_notified,
 
 };
@@ -4162,6 +4183,25 @@ int vty_mgmt_send_edit_req(struct vty *vty, uint8_t datastore,
        return 0;
 }
 
+int vty_mgmt_send_rpc_req(struct vty *vty, LYD_FORMAT request_type,
+                         const char *xpath, const char *data)
+{
+       vty->mgmt_req_id++;
+
+       if (mgmt_fe_send_rpc_req(mgmt_fe_client, vty->mgmt_session_id,
+                                vty->mgmt_req_id, request_type, xpath, data)) {
+               zlog_err("Failed to send RPC to MGMTD session-id: %" PRIu64
+                        " req-id %" PRIu64 ".",
+                        vty->mgmt_session_id, vty->mgmt_req_id);
+               vty_out(vty, "Failed to send RPC to MGMTD!\n");
+               return -1;
+       }
+
+       vty->mgmt_req_pending_cmd = "MESSAGE_RPC_REQ";
+
+       return 0;
+}
+
 /* Install vty's own commands like `who' command. */
 void vty_init(struct event_loop *master_thread, bool do_command_logging)
 {
index a51cee76fb5d1279e8b8c8960e9f7eecf0082085..a9570ef048d5caed2c926a6017046c8c0ab4fa92 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -427,6 +427,8 @@ extern int vty_mgmt_send_edit_req(struct vty *vty, uint8_t datastore,
                                  LYD_FORMAT request_type, uint8_t flags,
                                  uint8_t operation, const char *xpath,
                                  const char *data);
+extern int vty_mgmt_send_rpc_req(struct vty *vty, LYD_FORMAT request_type,
+                                const char *xpath, const char *data);
 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);
index 61d0760e05d626b24c4d882773004d492322197c..8ccb463577d412f94b4d493f51a01550945cb4e9 100644 (file)
@@ -296,6 +296,21 @@ DEFPY(mgmt_edit, mgmt_edit_cmd,
        return CMD_SUCCESS;
 }
 
+DEFPY(mgmt_rpc, mgmt_rpc_cmd,
+      "mgmt rpc XPATH [json|xml]$fmt [DATA]",
+      MGMTD_STR
+      "Invoke RPC\n"
+      "XPath expression specifying the YANG data path\n"
+      "JSON input format (default)\n"
+      "XML input format\n"
+      "Input data tree\n")
+{
+       LYD_FORMAT format = (fmt && fmt[0] == 'x') ? LYD_XML : LYD_JSON;
+
+       vty_mgmt_send_rpc_req(vty, format, xpath, data);
+       return CMD_SUCCESS;
+}
+
 DEFPY(show_mgmt_get_config, show_mgmt_get_config_cmd,
       "show mgmt get-config [candidate|operational|running]$dsname WORD$path",
       SHOW_STR MGMTD_STR
@@ -702,6 +717,7 @@ void mgmt_vty_init(void)
        install_element(CONFIG_NODE, &mgmt_remove_config_data_cmd);
        install_element(CONFIG_NODE, &mgmt_replace_config_data_cmd);
        install_element(CONFIG_NODE, &mgmt_edit_cmd);
+       install_element(CONFIG_NODE, &mgmt_rpc_cmd);
        install_element(CONFIG_NODE, &mgmt_load_config_cmd);
        install_element(CONFIG_NODE, &mgmt_save_config_cmd);
        install_element(CONFIG_NODE, &mgmt_rollback_cmd);