]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: add simplified native msg support
authorChristian Hopps <chopps@labn.net>
Thu, 6 Jul 2023 22:24:48 +0000 (18:24 -0400)
committerChristian Hopps <chopps@labn.net>
Tue, 26 Dec 2023 13:34:56 +0000 (08:34 -0500)
This is intended to replace protobuf use in mgmtd.

Signed-off-by: Christian Hopps <chopps@labn.net>
gdb/lib.txt
lib/mgmt_msg.c
lib/mgmt_msg_native.c [new file with mode: 0644]
lib/mgmt_msg_native.h [new file with mode: 0644]
lib/subdir.am

index 5d22321b6291bf2c730fced71a98011b5fbc020c..435ec7eda7bcac73d78d50f767adce578c964144 100644 (file)
@@ -306,8 +306,9 @@ define mq_walk
      end
      set $mg = $mg->next
   end
+end
 
-document mg_walk
+document mq_walk
 Walk the memory data structures to show what is holding memory.
 
 Arguments:
@@ -315,3 +316,49 @@ Arguments:
      sure where to start pass it mg_first, which is a global DS for
      all memory allocated in FRR
 end
+
+define __darr_meta
+  set $_ = ((struct darr_metadata *)$arg0) - 1
+end
+document __darr_meta
+Store a pointer to the struct darr_metadata in $_ for the given dynamic array.
+
+Argument: a pointer to a darr dynamic array.
+Returns: pointer to the struct darr_metadata in $_.
+end
+
+define darr_meta
+  __darr_meta $arg0
+  p *$_
+end
+document darr_meta
+Print the struct darr_metadata for the given dynamic array. Store the value
+in $_ as well.
+
+Argument: a pointer to a darr dynamic array.
+Returns: pointer to the struct darr_metadata in $_.
+end
+
+define darr_len
+  __darr_meta $arg0
+  set $_ = $_->len
+  p $_
+end
+document darr_len
+Print the length of the given dynamic array, and store in $_.
+
+Argument: a pointer to a darr dynamic array.
+Returns: length of the array.
+end
+
+define darr_cap
+  __darr_meta $arg0
+  set $_ = $_->cap
+  p $_
+end
+document darr_len
+Print the capacity of the given dynamic array, and store in $_.
+
+Argument: a pointer to a darr dynamic array.
+Returns: capacity of the array.
+end
index 12432a06e2cad6cf4dabd086005dd0dc0a45a011..d8a7fde435f9a7c540884e7fbd17d99d5cbd57e6 100644 (file)
@@ -13,6 +13,7 @@
 #include "stream.h"
 #include "frrevent.h"
 #include "mgmt_msg.h"
+#include "mgmt_msg_native.h"
 
 
 #define MGMT_MSG_DBG(dbgtag, fmt, ...)                                         \
@@ -84,7 +85,7 @@ enum mgmt_msg_rsched mgmt_msg_read(struct mgmt_msg_state *ms, int fd,
         */
        assert(stream_get_getp(ms->ins) == 0);
        left = stream_get_endp(ms->ins);
-       while (left > (long)sizeof(struct mgmt_msg_hdr)) {
+       while (left > (ssize_t)sizeof(struct mgmt_msg_hdr)) {
                mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(ms->ins) + total);
                if (!MGMT_MSG_IS_MARKER(mhdr->marker)) {
                        MGMT_MSG_DBG(dbgtag, "recv corrupt buffer, disconnect");
@@ -99,8 +100,25 @@ enum mgmt_msg_rsched mgmt_msg_read(struct mgmt_msg_state *ms, int fd,
                mcount++;
        }
 
-       if (!mcount)
+       if (!mcount) {
+               /* Didn't manage to read a full message */
+               if (mhdr && avail == 0) {
+                       struct stream *news;
+                       /*
+                        * Message was longer than what was left and we have no
+                        * available space to read more in. B/c mcount == 0 the
+                        * message starts at the beginning of the stream so
+                        * therefor the stream is too small to fit the message..
+                        * Resize the stream to fit.
+                        */
+                       news = stream_new(mhdr->len);
+                       stream_put(news, mhdr, left);
+                       stream_set_endp(news, left);
+                       stream_free(ms->ins);
+                       ms->ins = news;
+               }
                return MSR_SCHED_STREAM;
+       }
 
        /*
         * We have read at least one message into the stream, queue it up.
@@ -108,7 +126,11 @@ enum mgmt_msg_rsched mgmt_msg_read(struct mgmt_msg_state *ms, int fd,
        mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(ms->ins) + total);
        stream_set_endp(ms->ins, total);
        stream_fifo_push(&ms->inq, ms->ins);
-       ms->ins = stream_new(ms->max_msg_sz);
+       if (left < (ssize_t)sizeof(struct mgmt_msg_hdr))
+               ms->ins = stream_new(ms->max_msg_sz);
+       else
+               /* handle case where message is greater than max */
+               ms->ins = stream_new(MAX(ms->max_msg_sz, mhdr->len));
        if (left) {
                stream_put(ms->ins, mhdr, left);
                stream_set_endp(ms->ins, left);
@@ -292,23 +314,26 @@ int mgmt_msg_send_msg(struct mgmt_msg_state *ms, uint8_t version, void *msg,
        size_t endp, n;
        size_t mlen = len + sizeof(*mhdr);
 
-       if (mlen > ms->max_msg_sz) {
-               MGMT_MSG_ERR(ms, "Message %zu > max size %zu, dropping", mlen,
-                            ms->max_msg_sz);
-               return -1;
-       }
+       if (mlen > ms->max_msg_sz)
+               MGMT_MSG_DBG(dbgtag, "Sending large msg size %zu > max size %zu",
+                            mlen, ms->max_msg_sz);
 
        if (!ms->outs) {
-               MGMT_MSG_DBG(dbgtag, "creating new stream for msg len %zu",
-                            len);
-               ms->outs = stream_new(ms->max_msg_sz);
+               MGMT_MSG_DBG(dbgtag, "creating new stream for msg len %zu", mlen);
+               ms->outs = stream_new(MAX(ms->max_msg_sz, mlen));
+       } else if (mlen > ms->max_msg_sz && ms->outs->endp == 0) {
+               /* msg is larger than stream max size get a fit-to-size stream */
+               MGMT_MSG_DBG(dbgtag,
+                            "replacing old stream with fit-to-size for msg len %zu",
+                            mlen);
+               stream_free(ms->outs);
+               ms->outs = stream_new(mlen);
        } else if (STREAM_WRITEABLE(ms->outs) < mlen) {
-               MGMT_MSG_DBG(
-                       dbgtag,
-                       "enq existing stream len %zu and creating new stream for msg len %zu",
-                       STREAM_WRITEABLE(ms->outs), mlen);
+               MGMT_MSG_DBG(dbgtag,
+                            "enq existing stream len %zu and creating new stream for msg len %zu",
+                            STREAM_WRITEABLE(ms->outs), mlen);
                stream_fifo_push(&ms->outq, ms->outs);
-               ms->outs = stream_new(ms->max_msg_sz);
+               ms->outs = stream_new(MAX(ms->max_msg_sz, mlen));
        } else {
                MGMT_MSG_DBG(
                        dbgtag,
@@ -317,6 +342,16 @@ int mgmt_msg_send_msg(struct mgmt_msg_state *ms, uint8_t version, void *msg,
        }
        s = ms->outs;
 
+       if (dbgtag && version == MGMT_MSG_VERSION_NATIVE) {
+               struct mgmt_msg_header *native_msg = msg;
+
+               MGMT_MSG_DBG(
+                       dbgtag,
+                       "Sending native msg sess/txn-id %"PRIu64" req-id %"PRIu64" code %u",
+                       native_msg->session_id, native_msg->req_id, native_msg->code);
+
+       }
+
        /* We have a stream with space, pack the message into it. */
        mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(s) + s->endp);
        mhdr->marker = MGMT_MSG_MARKER(version);
@@ -672,6 +707,9 @@ static int msg_client_connect_short_circuit(struct msg_client *client)
        /* server side */
        memset(&su, 0, sizeof(union sockunion));
        server_conn = server->create(sockets[1], &su);
+       server_conn->debug = DEBUG_MODE_CHECK(server->debug, DEBUG_MODE_ALL)
+                                    ? true
+                                    : false;
 
        client->conn.remote_conn = server_conn;
        server_conn->remote_conn = &client->conn;
@@ -765,8 +803,9 @@ void msg_client_cleanup(struct msg_client *client)
 static void msg_server_accept(struct event *event)
 {
        struct msg_server *server = EVENT_ARG(event);
-       int fd;
+       struct msg_conn *conn;
        union sockunion su;
+       int fd;
 
        if (server->fd < 0)
                return;
@@ -789,7 +828,11 @@ static void msg_server_accept(struct event *event)
 
        DEBUGD(server->debug, "Accepted new %s connection", server->idtag);
 
-       server->create(fd, &su);
+       conn = server->create(fd, &su);
+       if (conn)
+               conn->debug = DEBUG_MODE_CHECK(server->debug, DEBUG_MODE_ALL)
+                                     ? true
+                                     : false;
 }
 
 int msg_server_init(struct msg_server *server, const char *sopath,
diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c
new file mode 100644 (file)
index 0000000..a9e8a17
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * June 29 2023, Christian Hopps <chopps@labn.net>
+ *
+ * Copyright (c) 2023, LabN Consulting, L.L.C.
+ *
+ */
+#include <zebra.h>
+#include "mgmt_msg_native.h"
+
+DEFINE_MGROUP(MSG_NATIVE, "Native message allocations");
+DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_MSG, "native mgmt msg");
+DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_ERROR, "native mgmt error msg");
+
+int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id,
+                               uint64_t req_id, bool short_circuit_ok,
+                               int16_t error, const char *errfmt, va_list ap)
+{
+       struct mgmt_msg_error *msg;
+       ssize_t slen;
+       size_t mlen;
+       int ret;
+
+       msg = XCALLOC(MTYPE_MSG_NATIVE_ERROR, 1024);
+       msg->session_id = sess_or_txn_id;
+       msg->req_id = req_id;
+       msg->code = MGMT_MSG_CODE_ERROR;
+       msg->error = error;
+
+       slen = vsnprintfrr(msg->errstr, 1024 - sizeof(*msg), errfmt, ap);
+       mlen = MIN(slen + sizeof(*msg) + 1, 1024);
+
+       if (conn->debug)
+               zlog_debug("Sending error %d session-id %" PRIu64
+                          " req-id %" PRIu64 " scok %d errstr: %s",
+                          error, sess_or_txn_id, req_id, short_circuit_ok,
+                          msg->errstr);
+
+       ret = msg_conn_send_msg(conn, MGMT_MSG_VERSION_NATIVE, msg, mlen, NULL,
+                               short_circuit_ok);
+
+       XFREE(MTYPE_MSG_NATIVE_ERROR, msg);
+
+       return ret;
+}
diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h
new file mode 100644 (file)
index 0000000..3a2bf10
--- /dev/null
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * June 29 2023, Christian Hopps <chopps@labn.net>
+ *
+ * Copyright (c) 2023, LabN Consulting, L.L.C.
+ *
+ */
+
+#ifndef _FRR_MGMT_MSG_NATIVE_H_
+#define _FRR_MGMT_MSG_NATIVE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#elif 0
+}
+#endif
+
+#include <zebra.h>
+#include "compiler.h"
+#include "memory.h"
+#include "mgmt_msg.h"
+#include "mgmt_defines.h"
+
+#include <stdalign.h>
+
+DECLARE_MTYPE(MSG_NATIVE_MSG);
+DECLARE_MTYPE(MSG_NATIVE_ERROR);
+
+/*
+ * Native message codes
+ */
+#define MGMT_MSG_CODE_ERROR    0
+#define MGMT_MSG_CODE_GET_TREE 1
+#define MGMT_MSG_CODE_TREE_DATA 2
+
+/*
+ * A note on alignments: The zero length arrays fields are aligned such that
+ * this is so:
+ *
+ *    sizeof(struct mgmt_msg_foo) == offsetof(struct mgmt_msg_foo, field)
+ *
+ * This allows things like `ptr = darr_append_n(A, sizeof(*ptr))`
+ * to work
+ */
+
+
+struct mgmt_msg_header {
+       union {
+               uint64_t session_id;
+               uint64_t txn_id;
+       };
+       uint64_t req_id;
+       uint16_t code;
+};
+
+struct mgmt_msg_error {
+       struct mgmt_msg_header;
+       int16_t error;
+
+       alignas(8) char errstr[];
+};
+_Static_assert(sizeof(struct mgmt_msg_error) ==
+                      offsetof(struct mgmt_msg_error, errstr),
+              "Size mismatch");
+
+struct mgmt_msg_get_tree {
+       struct mgmt_msg_header;
+       uint8_t result_type;
+
+       alignas(8) char xpath[];
+};
+_Static_assert(sizeof(struct mgmt_msg_get_tree) ==
+                      offsetof(struct mgmt_msg_get_tree, xpath),
+              "Size mismatch");
+
+struct mgmt_msg_tree_data {
+       struct mgmt_msg_header;
+       int8_t partial_error;
+       uint8_t result_type;
+
+       alignas(8) uint8_t result[];
+};
+_Static_assert(sizeof(struct mgmt_msg_tree_data) ==
+                      offsetof(struct mgmt_msg_tree_data, result),
+              "Size mismatch");
+
+#define MGMT_MSG_VALIDATE_NUL_TERM(msgp, len)                                  \
+       ((len) >= sizeof(*msg) + 1 && ((char *)msgp)[(len)-1] == 0)
+
+
+/**
+ * Send a native message error to the other end of the connection.
+ *
+ * This function is normally used by the server-side to indicate a failure to
+ * process a client request. For this server side handling of client messages
+ * which expect a reply, either that reply or this error should be returned, as
+ * closing the connection is not allowed during message handling.
+ *
+ * Args:
+ *     conn: the connection.
+ *     sess_or_txn_id: Session ID (to FE client) or Txn ID (from BE client)
+ *     req_id: which req_id this error is associated with.
+ *     short_circuit_ok: if short circuit sending is OK.
+ *     error: the error value
+ *     errfmt: vprintfrr style format string
+ *     ap: the variable args for errfmt.
+ *
+ * Return:
+ *     The return value of ``msg_conn_send_msg``.
+ */
+extern int vmgmt_msg_native_send_error(struct msg_conn *conn,
+                                      uint64_t sess_or_txn_id, uint64_t req_id,
+                                      bool short_circuit_ok, int16_t error,
+                                      const char *errfmt, va_list ap)
+       PRINTFRR(6, 0);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_MGMT_MSG_NATIVE_H_ */
index c4ddb87c1f423115437c9bf1abafa9810e38e206..1dde70646620e6798dce27a02299829c77c64ca0 100644 (file)
@@ -68,6 +68,7 @@ lib_libfrr_la_SOURCES = \
        lib/mgmt_be_client.c \
        lib/mgmt_fe_client.c \
        lib/mgmt_msg.c \
+       lib/mgmt_msg_native.c \
        lib/mlag.c \
        lib/module.c \
        lib/mpls.c \
@@ -256,6 +257,7 @@ pkginclude_HEADERS += \
        lib/mgmt_defines.h \
        lib/mgmt_fe_client.h \
        lib/mgmt_msg.h \
+       lib/mgmt_msg_native.h \
        lib/mgmt_pb.h \
        lib/module.h \
        lib/monotime.h \