summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gdb/lib.txt49
-rw-r--r--lib/mgmt_msg.c79
-rw-r--r--lib/mgmt_msg_native.c45
-rw-r--r--lib/mgmt_msg_native.h121
-rw-r--r--lib/subdir.am2
5 files changed, 277 insertions, 19 deletions
diff --git a/gdb/lib.txt b/gdb/lib.txt
index 5d22321b6..435ec7eda 100644
--- a/gdb/lib.txt
+++ b/gdb/lib.txt
@@ -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
diff --git a/lib/mgmt_msg.c b/lib/mgmt_msg.c
index 12432a06e..d8a7fde43 100644
--- a/lib/mgmt_msg.c
+++ b/lib/mgmt_msg.c
@@ -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
index 000000000..a9e8a1711
--- /dev/null
+++ b/lib/mgmt_msg_native.c
@@ -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
index 000000000..3a2bf104a
--- /dev/null
+++ b/lib/mgmt_msg_native.h
@@ -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_ */
diff --git a/lib/subdir.am b/lib/subdir.am
index c4ddb87c1..1dde70646 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -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 \