Skip to content

Commit

Permalink
lib: add dedicated API functions for appendable msgs
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Hopps <[email protected]>
  • Loading branch information
choppsv1 committed Dec 15, 2023
1 parent 92a68b1 commit b369923
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 27 deletions.
18 changes: 9 additions & 9 deletions lib/mgmt_be_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,8 +787,8 @@ static enum nb_error be_client_send_tree_data_batch(const struct lyd_node *tree,
struct be_client_tree_data_batch_args *args = arg;
struct mgmt_be_client *client = args->client;
struct mgmt_msg_tree_data *tree_msg = NULL;
uint8_t *buf = NULL;
bool more = false;
uint8_t **darrp;
LY_ERR err;

if (ret == NB_YIELD) {
Expand All @@ -798,26 +798,26 @@ static enum nb_error be_client_send_tree_data_batch(const struct lyd_node *tree,
if (ret != NB_OK)
goto done;

darr_append_nz(buf, offsetof(typeof(*tree_msg), result));
tree_msg = (typeof(tree_msg))buf;
tree_msg = mgmt_msg_appendable_alloc_msg(struct mgmt_msg_tree_data);
tree_msg->refer_id = args->txn_id;
tree_msg->req_id = args->req_id;
tree_msg->code = MGMT_MSG_CODE_TREE_DATA;
tree_msg->result_type = args->result_type;
tree_msg->more = more;
err = yang_print_tree_append(&buf, tree, args->result_type,

darrp = mgmt_msg_appendable_get_darrp(tree_msg);
err = yang_print_tree_append(darrp, tree, args->result_type,
(LYD_PRINT_WD_EXPLICIT |
LYD_PRINT_WITHSIBLINGS));
/* buf may have been reallocated and moved */
tree_msg = (typeof(tree_msg))buf;

if (err) {
ret = NB_ERR;
goto done;
}
(void)be_client_send_native_msg(client, buf, darr_len(buf), false);
(void)be_client_send_native_msg(client, tree_msg,
mgmt_msg_appendable_get_msg_len(tree_msg),
false);
done:
darr_free(buf);
mgmt_msg_appendable_free_msg(tree_msg);
if (ret)
be_client_send_error(client, args->txn_id, args->req_id, false,
-EINVAL,
Expand Down
5 changes: 2 additions & 3 deletions lib/mgmt_fe_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ DECLARE_LIST(mgmt_sessions, struct mgmt_fe_client_session, list_linkage);

DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_CLIENT, "frontend client");
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_CLIENT_NAME, "frontend client name");
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_GET_DATA_MSG, "FE get data msg");
DEFINE_MTYPE_STATIC(LIB, MGMTD_FE_SESSION, "frontend session");

struct mgmt_fe_client {
Expand Down Expand Up @@ -325,7 +324,7 @@ int mgmt_fe_send_get_tree_req(struct mgmt_fe_client *client,
size_t mlen = sizeof(*msg) + xplen + 1;
int ret;

msg = XCALLOC(MTYPE_MGMTD_FE_GET_DATA_MSG, mlen);
msg = XCALLOC(MTYPE_MSG_NATIVE_GET_TREE, mlen);
msg->refer_id = session_id;
msg->req_id = req_id;
msg->code = MGMT_MSG_CODE_GET_TREE;
Expand All @@ -337,7 +336,7 @@ int mgmt_fe_send_get_tree_req(struct mgmt_fe_client *client,
session_id, req_id, xpath);

ret = fe_client_send_native_msg(client, msg, mlen, false);
XFREE(MTYPE_MGMTD_FE_GET_DATA_MSG, msg);
XFREE(MTYPE_MSG_NATIVE_GET_TREE, msg);
return ret;
}

Expand Down
1 change: 1 addition & 0 deletions lib/mgmt_msg_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
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");
DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_GET_TREE, "native get tree 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,
Expand Down
212 changes: 197 additions & 15 deletions lib/mgmt_msg_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,112 @@ extern "C" {

#include <stdalign.h>

DECLARE_MTYPE(MSG_NATIVE_MSG);
DECLARE_MTYPE(MSG_NATIVE_ERROR);

/*
* Adding New Messages Types
* -------------------------
* ==================
* Native Message API
* ==================
*
* -----------------------
* Defining A New Message:
* -----------------------
*
* 1) Start with struct mgmt_msg_header as the first (unnamed) field.
* 2) Add fixed-width fields on natural aligned boundaries.
* 3) Add an optional variable field aligned on a 64-bit boundary, this is
* done so that: `value = (HDR + 1)` to works.
*
* These rules are so the messages may be read from and written directly to
* "the wire", easily, using common programming languages (e.g., C, rust, go,
* python, ...)
*
* Fixed And Known Variable Length Messages:
* -----------------------------------------
*
* For fixed-length and variable length message where the length is known
* up-front one should allocate new messages with the XCALLOC() and XFREE()
* functions with an MTYPE dedicated for that message type. The new MTYPE type
* should be declared below.
*
* Unknown Variable Length Messages:
* ---------------------------------
*
* If using a variable length field and the length is not known at message
* creation time, you can use the `appendable` API functions to allocate and
* manipulate the message.
*
* Notable Appendable API Functions:
* ---------------------------------
*
* mgmt_msg_appendable_alloc_msg() - Allocate an appendable msg.
* mgmt_msg_appendable_free_msg() - Free an appendable native msg.
* mgmt_msg_appendable_append() - Append data to the end of the msg.
* mgmt_msg_appendable_get_msg_len() - Get the total length of the msg.
*
*
* -------------------------------------
* [Advanced Use] Dynamic Array Messages
* -------------------------------------
*
* NOTE: Most users can simply use mgmt_msg_appendable_append() and skip this
* section.
*
* This section is only important to understand if you wish to utilize the fact
* that native messages allocated with mgmt_msg_appendable_alloc_msg are
* actually allocated as uint8_t dynamic arrays (`darr`).
*
* Native messages structs have 2 simple rules:
* You can utilize all the darr_xxxx() API to manipulate the variable length
* message data in a native message. To do so you simply need to understand that
* the native message is actually a `uint8_t *` darr. So, for example, to append
* data to the end of a message one could do the following:
*
* 1) All fields should be naturally aligned.
* 2) Any required padding should be explicitly reserved.
* void append_metric_path(struct mgmt_msg_my_msg *msg)
* {
* msg = (struct mggm_msg_my_msg *)
* darr_strcat((uint8_t *)msg, "/metric");
*
* This is so for all intents and purposes the messages may be read and written
* direct from "the wire", easily, using common programming languages (e.g.,
* C, rust, go, python, ...)
* // ...
* }
*
* Additionally by design fixed fields precede the variable length data which
* comes at the end. The zero length arrays fields are aligned such that this is so:
* NOTE: If reallocs happen the original passed in pointer will be updated;
* however, any other pointers into the message will become invalid, and so they
* should always be discarded or reinitialized after using any reallocating
* darr_xxx() API functions.
*
* sizeof(struct mgmt_msg_foo) == offsetof(struct mgmt_msg_foo, field)
* void append_metric_path(struct mgmt_msg_my_msg *msg)
* {
* char *xpath = msg->xpath; // pointer into message
*
* darr_in_strcat((uint8_t *)msg, "/metric");
* // msg may have been updated to point at new memory
*
* xpath = NULL; // now invalid
* xpath = msg->xpath; // reinitialize
* // ...
* }
*
* Rather than worry about this, it's typical when using dynamic arrays to always
* work from the main pointer to the dynamic array, rather than caching multiple
* pointers into the data. Modern compilers will optimize the code so that it
* adds no extra execution cost.
*
* void append_metric_path(struct mgmt_msg_my_msg *msg)
* {
* darr_in_strcat((uint8_t *)msg, "/metric");
*
* // Use `msg->xpath` directly rather creating and using an
* // `xpath = msg->xpath` local variable.
*
* if (strcmp(msg->xpath, "foobar/metric")) {
* // ...
* }
* }
*
* This allows things like `value = (HDR + 1)` to work.
*/

DECLARE_MTYPE(MSG_NATIVE_MSG);
DECLARE_MTYPE(MSG_NATIVE_ERROR);
DECLARE_MTYPE(MSG_NATIVE_GET_TREE);

/*
* Native message codes
*/
Expand Down Expand Up @@ -78,6 +160,7 @@ _Static_assert(sizeof(struct mgmt_msg_header) ==

/**
* struct mgmt_msg_error - Common error message.
*
* @error: An error value.
* @errst: Description of error can be 0 length.
*
Expand All @@ -97,6 +180,7 @@ _Static_assert(sizeof(struct mgmt_msg_error) ==

/**
* struct mgmt_msg_get_tree - Message carrying xpath query request.
*
* @result_type: ``LYD_FORMAT`` for the returned result.
* @xpath: the query for the data to return.
*/
Expand All @@ -113,6 +197,7 @@ _Static_assert(sizeof(struct mgmt_msg_get_tree) ==

/**
* struct mgmt_msg_tree_data - Message carrying tree data.
*
* @partial_error: If the full result could not be returned do to this error.
* @result_type: ``LYD_FORMAT`` for format of the @result value.
* @more: if this is a partial return and there will be more coming.
Expand Down Expand Up @@ -162,6 +247,103 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn,
const char *errfmt, va_list ap)
PRINTFRR(6, 0);

/**
* mgmt_msg_appendable_alloc_msg() - Create an appendable msg.
* @msg_type: The message structure type.
*
* This function takes a C type (e.g., `struct mgmt_msg_get_tree`) as an
* argument and returns a new appendable message. The newly allocated message
* should be used with the other `appendable` functions.
*
* Importantly the mgmt_msg_appendable_append() function can be used to add data
* to the end of the message, and mgmt_msg_get_appendable_msg_len() can be used
* to obtain the total length of the message (i.e., the fixed sized header plus
* the variable length data that has been appended).
*
* Additionally, a dynamic array (darr) pointer can be obtained using
* mgmt_msg_get_appendable_darr() which allows adding and manipulating the
* variable data that follows the fixed sized header.
*
* Return: A `msg_type` object created using a dynamic_array.
*/
#define mgmt_msg_appendable_alloc_msg(msg_type) \
({ \
uint8_t *buf = NULL; \
(typeof(msg_type) *)darr_append_nz(buf, sizeof(msg_type)); \
})

/**
* mgmt_msg_free_appendable_msg() - Free an appendable native msg.
* @msg - pointer to message allocated by mgmt_msg_create_appendable_msg().
*/
#define mgmt_msg_appendable_free_msg(msg) darr_free(msg)

/**
* mgmt_msg_appendable_get_msg_len() - Get the total length of the msg.
* @msg: the appendable message.
*
* Return: the total length of the message, fixed + variable length.
*/
#define mgmt_msg_appendable_get_msg_len(msg) (darr_len((uint8_t *)(msg)))

/**
* mgmt_msg_appendable_append() - Append data to the end of the msg.
* @msg: (IN/OUT) Pointer to the appendable message, variable may be updated.
* @data: data to append.
* @len: length of data to append.
*
* Append @data of length @len to the appendable message @msg.
*
* NOTE: Be aware @msg pointer may change as a result of reallocating the
* message to fit the new data. Any other pointers into the old message should
* be discarded.
*
* Return: a pointer to the newly appended data.
*/
#define mgmt_msg_appendable_append(msg, data, len) \
memcpy(darr_append(mgmt_msg_get_appendable_darr(msg), len), data, len)



/**
* mgmt_msg_appendable_get_darrp() - Return a ptr to the dynamic array ptr.
* @msg: Pointer to the appendable message.
*
* NOTE: Most users can simply use mgmt_msg_appendable_append() instead of this.
*
* This function obtains a pointer to the dynamic byte array for this message,
* this array actually includes the message header if one is going to look at
* the length value. With that in mind any of the `darr_*()` functions/API may
* be used to manipulate the variable data at the end of the message.
*
* NOTE: The pointer returned is actually a pointer to the message pointer
* passed in to this function. This pointer to pointer is required so that
* realloc can be done inside the darr API.
*
* NOTE: If reallocs happen the original passed in pointer will be updated;
* however, any other pointers into the message will become invalid and so they
* should always be discarded after using the returned value.
*
* Example:
*
* void append_metric_path(struct mgmt_msg_my_msg *msg)
* {
* char *xpath = msg->xpath; // pointer into message
* uint8_t **darp;
*
* darrp = mgmt_msg_appendable_get_darrp(msg);
* darr_in_strcat(*darrp, "/metric");
*
* xpath = NULL; // now invalid
* xpath = msg->xpath;
* }
*
*
* Return: A pointer to the first argument -- which is a pointer to a pointer to
* a dynamic array.
*/
#define mgmt_msg_appendable_get_darrp(msg) ((uint8_t **)&(msg))

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit b369923

Please sign in to comment.