Skip to content

Commit

Permalink
lib: add simplified native msg support
Browse files Browse the repository at this point in the history
This is intended to replace protobuf use in mgmtd.

Signed-off-by: Christian Hopps <chopps@labn.net>
  • Loading branch information
choppsv1 committed Dec 26, 2023
1 parent 080299f commit 8790457
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 19 deletions.
49 changes: 48 additions & 1 deletion gdb/lib.txt
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,59 @@ 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:
1st: A (struct memgroup *) where to start the walk. If you are not
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
79 changes: 61 additions & 18 deletions lib/mgmt_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...) \
Expand Down Expand Up @@ -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");
Expand All @@ -99,16 +100,37 @@ 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.
*/
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);
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down
45 changes: 45 additions & 0 deletions lib/mgmt_msg_native.c
Original file line number Diff line number Diff line change
@@ -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;
}
121 changes: 121 additions & 0 deletions lib/mgmt_msg_native.h
Original file line number Diff line number Diff line change
@@ -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_ */
2 changes: 2 additions & 0 deletions lib/subdir.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down

0 comments on commit 8790457

Please sign in to comment.