]> git.puffer.fish Git - matthieu/frr.git/commitdiff
mgmtd: add native session-req (create/delete) messages
authorChristian Hopps <chopps@labn.net>
Tue, 11 Jun 2024 09:08:49 +0000 (05:08 -0400)
committerChristian Hopps <chopps@labn.net>
Tue, 11 Jun 2024 14:37:31 +0000 (10:37 -0400)
This addition allows for a limited native-message-only front-end
interaction.

Signed-off-by: Christian Hopps <chopps@labn.net>
lib/mgmt_msg_native.c
lib/mgmt_msg_native.h
mgmtd/mgmt_fe_adapter.c

index d0a0b72189bab8b2927c678af1ffb78100c43614..b85c7d1b61822327fa1a1e0f5accf3a4ea2785c4 100644 (file)
@@ -19,6 +19,33 @@ DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT, "native edit msg");
 DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT_REPLY, "native edit reply msg");
 DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC, "native RPC msg");
 DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC_REPLY, "native RPC reply msg");
+DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REQ, "native session-req msg");
+DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REPLY, "native session-reply msg");
+
+
+size_t mgmt_msg_min_sizes[] = {
+       [MGMT_MSG_CODE_ERROR] = sizeof(struct mgmt_msg_error),
+       [MGMT_MSG_CODE_GET_TREE] = sizeof(struct mgmt_msg_get_tree),
+       [MGMT_MSG_CODE_TREE_DATA] = sizeof(struct mgmt_msg_tree_data),
+       [MGMT_MSG_CODE_GET_DATA] = sizeof(struct mgmt_msg_get_data),
+       [MGMT_MSG_CODE_NOTIFY] = sizeof(struct mgmt_msg_notify_data),
+       [MGMT_MSG_CODE_EDIT] = sizeof(struct mgmt_msg_edit),
+       [MGMT_MSG_CODE_EDIT_REPLY] = sizeof(struct mgmt_msg_edit_reply),
+       [MGMT_MSG_CODE_RPC] = sizeof(struct mgmt_msg_rpc),
+       [MGMT_MSG_CODE_RPC_REPLY] = sizeof(struct mgmt_msg_rpc_reply),
+       [MGMT_MSG_CODE_NOTIFY_SELECT] = sizeof(struct mgmt_msg_notify_select),
+       [MGMT_MSG_CODE_SESSION_REQ] = sizeof(struct mgmt_msg_session_req),
+       [MGMT_MSG_CODE_SESSION_REPLY] = sizeof(struct mgmt_msg_session_reply),
+};
+size_t nmgmt_msg_min_sizes = sizeof(mgmt_msg_min_sizes) /
+                            sizeof(*mgmt_msg_min_sizes);
+
+size_t mgmt_msg_get_min_size(uint code)
+{
+       if (code >= nmgmt_msg_min_sizes)
+               return 0;
+       return mgmt_msg_min_sizes[code];
+}
 
 int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id,
                                uint64_t req_id, bool short_circuit_ok,
index e61346e6e5d5196296be531307f317e0e87d13dd..76a52658cdee751859e0b29237a977ee99853b70 100644 (file)
@@ -163,6 +163,8 @@ DECLARE_MTYPE(MSG_NATIVE_EDIT);
 DECLARE_MTYPE(MSG_NATIVE_EDIT_REPLY);
 DECLARE_MTYPE(MSG_NATIVE_RPC);
 DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY);
+DECLARE_MTYPE(MSG_NATIVE_SESSION_REQ);
+DECLARE_MTYPE(MSG_NATIVE_SESSION_REPLY);
 
 /*
  * Native message codes
@@ -177,6 +179,8 @@ DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY);
 #define MGMT_MSG_CODE_RPC       7 /* Public API */
 #define MGMT_MSG_CODE_RPC_REPLY         8 /* Public API */
 #define MGMT_MSG_CODE_NOTIFY_SELECT 9 /* Public API */
+#define MGMT_MSG_CODE_SESSION_REQ   10 /* Public API */
+#define MGMT_MSG_CODE_SESSION_REPLY 11 /* Public API */
 
 /*
  * Datastores
@@ -434,7 +438,7 @@ _Static_assert(sizeof(struct mgmt_msg_rpc_reply) ==
  * to the front-end client.
  *
  * @selectors: the xpath prefixes to selectors notifications through.
- * @repalce: if true replace existing selectors with `selectors`.
+ * @replace: if true replace existing selectors with `selectors`.
  */
 struct mgmt_msg_notify_select {
        struct mgmt_msg_header;
@@ -448,12 +452,51 @@ _Static_assert(sizeof(struct mgmt_msg_notify_select) ==
                       offsetof(struct mgmt_msg_notify_select, selectors),
               "Size mismatch");
 
+/**
+ * struct mgmt_msg_session_req - Create or delete a front-end session.
+ *
+ * @refer_id: Zero for create, otherwise the session-id to delete.
+ * @req_id: For create will use as client-id.
+ * @client_name: For first session request the client name, otherwise empty.
+ */
+struct mgmt_msg_session_req {
+       struct mgmt_msg_header;
+       uint8_t resv2[8]; /* bug in compiler produces error w/o this */
+
+       alignas(8) char client_name[];
+};
+
+_Static_assert(sizeof(struct mgmt_msg_session_req) ==
+                      offsetof(struct mgmt_msg_session_req, client_name),
+              "Size mismatch");
+
+/**
+ * struct mgmt_msg_session_reply - Reply to session request message.
+ *
+ * @created: true if this is a reply to a create request, otherwise 0.
+ * @refer_id: The session-id for the action (create or delete) just taken.
+ */
+struct mgmt_msg_session_reply {
+       struct mgmt_msg_header;
+       uint8_t created;
+       uint8_t resv2[7];
+};
+
 /*
  * Validate that the message ends in a NUL terminating byte
  */
 #define MGMT_MSG_VALIDATE_NUL_TERM(msgp, len)                                  \
        ((len) >= sizeof(*msgp) + 1 && ((char *)msgp)[(len)-1] == 0)
 
+/**
+ * mgmt_msg_get_min_size() - Get minimum message size given the type
+ * @code: The type of the message (MGMT_MSG_CODE_*)
+ *
+ * Return:
+ *     The minimum size of a message of the given type or 0 if the message
+ *     code is unknown.
+ */
+size_t mgmt_msg_get_min_size(uint code);
 
 /**
  * Send a native message error to the other end of the connection.
index a076dc72f96b88c306abaf0f911b8a5b4d97b0ab..5f53c928a47e07929851111742ca305f8a5b5484 100644 (file)
@@ -490,6 +490,26 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session,
        return fe_adapter_send_msg(session->adapter, &fe_msg, false);
 }
 
+static int fe_adapter_conn_send_error(struct msg_conn *conn,
+                                     uint64_t session_id, uint64_t req_id,
+                                     bool short_circuit_ok, int16_t error,
+                                     const char *errfmt, ...) PRINTFRR(6, 7);
+static int fe_adapter_conn_send_error(struct msg_conn *conn, uint64_t session_id,
+                                     uint64_t req_id, bool short_circuit_ok,
+                                     int16_t error, const char *errfmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, errfmt);
+
+       ret = vmgmt_msg_native_send_error(conn, session_id, req_id,
+                                         short_circuit_ok, error, errfmt, ap);
+       va_end(ap);
+
+       return ret;
+}
+
 static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session,
                                 uint64_t req_id, bool short_circuit_ok,
                                 int16_t error, const char *errfmt, ...)
@@ -1170,6 +1190,88 @@ static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session,
        return ret;
 }
 
+static int
+fe_adapter_native_send_session_reply(struct mgmt_fe_client_adapter *adapter,
+                                    uint64_t req_id, uint64_t session_id,
+                                    bool created)
+{
+       struct mgmt_msg_session_reply *msg;
+       int ret;
+
+       msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_session_reply, 0,
+                                       MTYPE_MSG_NATIVE_SESSION_REPLY);
+       msg->refer_id = session_id;
+       msg->req_id = req_id;
+       msg->code = MGMT_MSG_CODE_SESSION_REPLY;
+       msg->created = created;
+
+       __dbg("Sending session-reply from adapter %s to session-id %" PRIu64
+             " req-id %" PRIu64 " len %u",
+             adapter->name, session_id, req_id,
+             mgmt_msg_native_get_msg_len(msg));
+
+       ret = fe_adapter_send_native_msg(adapter, msg,
+                                        mgmt_msg_native_get_msg_len(msg),
+                                        false);
+       mgmt_msg_native_free_msg(msg);
+
+       return ret;
+}
+
+/**
+ * fe_adapter_handle_session_req() - Handle a session-req message from a FE client.
+ * @msg_raw: the message data.
+ * @msg_len: the length of the message data.
+ */
+static void fe_adapter_handle_session_req(struct mgmt_fe_client_adapter *adapter,
+                                         void *__msg, size_t msg_len)
+{
+       struct mgmt_msg_session_req *msg = __msg;
+       struct mgmt_fe_session_ctx *session;
+       uint64_t client_id;
+
+       __dbg("Got session-req creating: %u for refer-id %" PRIu64 " from '%s'",
+             msg->refer_id == 0, msg->refer_id, adapter->name);
+
+       if (msg->refer_id) {
+               uint64_t session_id = msg->refer_id;
+
+               session = mgmt_session_id2ctx(session_id);
+               if (!session) {
+                       fe_adapter_conn_send_error(
+                               adapter->conn, session_id, msg->req_id, false,
+                               -EINVAL,
+                               "No session to delete for session-id: %" PRIu64,
+                               session_id);
+                       return;
+               }
+               fe_adapter_native_send_session_reply(adapter, msg->req_id,
+                                                    session_id, false);
+               mgmt_fe_cleanup_session(&session);
+               return;
+       }
+
+       client_id = msg->req_id;
+
+       /* See if we have a client name to register */
+       if (msg_len > sizeof(*msg)) {
+               if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) {
+                       fe_adapter_conn_send_error(
+                               adapter->conn, client_id, msg->req_id, false,
+                               -EINVAL,
+                               "Corrupt session-req message rcvd from client-id: %" PRIu64,
+                               client_id);
+                       return;
+               }
+               __dbg("Set client-name to '%s'", msg->client_name);
+               strlcpy(adapter->name, msg->client_name, sizeof(adapter->name));
+       }
+
+       session = mgmt_fe_create_session(adapter, client_id);
+       fe_adapter_native_send_session_reply(adapter, client_id,
+                                            session->session_id, true);
+}
+
 /**
  * fe_adapter_handle_get_data() - Handle a get-tree message from a FE client.
  * @session: the client session.
@@ -1529,6 +1631,28 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter,
                                         size_t msg_len)
 {
        struct mgmt_fe_session_ctx *session;
+       size_t min_size = mgmt_msg_get_min_size(msg->code);
+
+       if (msg_len < min_size) {
+               if (!min_size)
+                       __log_err("adapter %s: recv msg refer-id %" PRIu64
+                                 " unknown message type %u",
+                                 adapter->name, msg->refer_id, msg->code);
+               else
+                       __log_err("adapter %s: recv msg refer-id %" PRIu64
+                                 " short (%zu<%zu) msg for type %u",
+                                 adapter->name, msg->refer_id, msg_len,
+                                 min_size, msg->code);
+               return;
+       }
+
+       if (msg->code == MGMT_MSG_CODE_SESSION_REQ) {
+               __dbg("adapter %s: session-id %" PRIu64
+                     " received SESSION_REQ message",
+                     adapter->name, msg->refer_id);
+               fe_adapter_handle_session_req(adapter, msg, msg_len);
+               return;
+       }
 
        session = mgmt_session_id2ctx(msg->refer_id);
        if (!session) {