Skip to content

Commit

Permalink
Merge pull request #15381 from LabNConsulting/chopps/nb-notif
Browse files Browse the repository at this point in the history
lib: mgmtd: add xpath arg to YANG notification message
  • Loading branch information
idryzhov authored Feb 19, 2024
2 parents 29a0c1c + 4a93d17 commit 5332e44
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 134 deletions.
2 changes: 2 additions & 0 deletions lib/hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
_hook_unregister(&_hook_##hookname, \
_hook_typecheck_arg_##hookname(func), arg, true)

#define hook_have_hooks(hookname) (_hook_##hookname.entries != NULL)

/* invoke hooks
* this is private (static) to the file that has the DEFINE_HOOK statement
*/
Expand Down
90 changes: 31 additions & 59 deletions lib/mgmt_be_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,15 @@ static int be_client_send_error(struct mgmt_be_client *client, uint64_t txn_id,
return ret;
}

void mgmt_be_send_notification(struct lyd_node *tree)
static int mgmt_be_send_notification(void *__be_client, const char *xpath,
const struct lyd_node *tree)
{
struct mgmt_be_client *client = __be_client;
struct mgmt_msg_notify_data *msg = NULL;
LYD_FORMAT format = LYD_JSON;
uint8_t **darrp;
LY_ERR err;
int ret = 0;

assert(tree);

Expand All @@ -331,6 +333,8 @@ void mgmt_be_send_notification(struct lyd_node *tree)
msg->code = MGMT_MSG_CODE_NOTIFY;
msg->result_type = format;

mgmt_msg_native_xpath_encode(msg, xpath);

darrp = mgmt_msg_native_get_darrp(msg);
err = yang_print_tree_append(darrp, tree, format,
(LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT |
Expand All @@ -339,60 +343,15 @@ void mgmt_be_send_notification(struct lyd_node *tree)
flog_err(EC_LIB_LIBYANG,
"%s: error creating notification data: %s", __func__,
ly_strerrcode(err));
ret = 1;
goto done;
}

(void)be_client_send_native_msg(client, msg,
mgmt_msg_native_get_msg_len(msg), false);
done:
mgmt_msg_native_free_msg(msg);
lyd_free_all(tree);
}

/*
* Convert old style NB notification data into new MGMTD YANG tree and send.
*/
static int mgmt_be_notification_send(void *arg, const char *xpath,
struct list *args)
{
struct lyd_node *root = NULL;
struct lyd_node *dnode;
struct yang_data *data;
struct listnode *ln;
LY_ERR err;

debug_be_client("%s: sending notification: %s", __func__, xpath);

/*
* Convert yang data args list to a libyang data tree
*/
for (ALL_LIST_ELEMENTS_RO(args, ln, data)) {
err = lyd_new_path(root, ly_native_ctx, data->xpath,
data->value, LYD_NEW_PATH_UPDATE, &dnode);
if (err != LY_SUCCESS) {
lyerr:
flog_err(EC_LIB_LIBYANG,
"%s: error creating notification data: %s",
__func__, ly_strerrcode(err));
if (root)
lyd_free_all(root);
return 1;
}
if (!root) {
root = dnode;
while (root->parent)
root = lyd_parent(root);
}
}

if (!root) {
err = lyd_new_path(NULL, ly_native_ctx, xpath, "", 0, &root);
if (err)
goto lyerr;
}

mgmt_be_send_notification(root);
return 0;
return ret;
}

static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx,
Expand Down Expand Up @@ -964,27 +923,40 @@ static void be_client_handle_notify(struct mgmt_be_client *client, void *msgbuf,
{
struct mgmt_msg_notify_data *notif_msg = msgbuf;
struct nb_node *nb_node;
char notif[XPATH_MAXLEN];
struct lyd_node *dnode;
const char *data;
const char *notif;
LY_ERR err;

debug_be_client("Received notification for client %s", client->name);

err = yang_parse_notification(notif_msg->result_type,
(char *)notif_msg->result, &dnode);
if (err)
notif = mgmt_msg_native_xpath_data_decode(notif_msg, msg_len, data);
if (!notif || !data) {
log_err_be_client("Corrupt notify msg");
return;

lysc_path(dnode->schema, LYSC_PATH_DATA, notif, sizeof(notif));
}

nb_node = nb_node_find(notif);
if (!nb_node || !nb_node->cbs.notify) {
debug_be_client("No notification callback for %s", notif);
goto cleanup;
if (!nb_node) {
log_err_be_client("No schema found for notification: %s", notif);
return;
}

if (!nb_node->cbs.notify) {
debug_be_client("No notification callback for: %s", notif);
return;
}

err = yang_parse_notification(notif, notif_msg->result_type, data,
&dnode);
if (err) {
log_err_be_client("Can't parse notification data for: %s",
notif);
return;
}

nb_callback_notify(nb_node, notif, dnode);
cleanup:

lyd_free_all(dnode);
}

Expand Down Expand Up @@ -1202,7 +1174,7 @@ struct mgmt_be_client *mgmt_be_client_create(const char *client_name,
"BE-client", debug_check_be_client());

/* Hook to receive notifications */
hook_register_arg(nb_notification_send, mgmt_be_notification_send,
hook_register_arg(nb_notification_tree_send, mgmt_be_send_notification,
client);

debug_be_client("Initialized client '%s'", client_name);
Expand Down
9 changes: 0 additions & 9 deletions lib/mgmt_be_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,6 @@ extern int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx,
int n_config_xpaths, char **config_xpaths,
int n_oper_xpaths, char **oper_xpaths);

/**
* mgmt_be_notification_send() - send a YANG notification to FE clients.
* @tree: libyang tree for the notification. The tree will be freed by
* this function.
*
*/
extern void mgmt_be_send_notification(struct lyd_node *tree);


/*
* Destroy backend client and cleanup everything.
*/
Expand Down
27 changes: 12 additions & 15 deletions lib/mgmt_fe_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,8 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
struct mgmt_msg_notify_data *notify_msg;
struct mgmt_msg_tree_data *tree_msg;
struct mgmt_msg_error *err_msg;
char *notify_data = NULL;
const char *data = NULL;
size_t dlen;

debug_fe_client("Got native message for session-id %" PRIu64,
msg->refer_id);
Expand Down Expand Up @@ -563,20 +564,17 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
return;
}

if (notify_msg->result_type != LYD_LYB &&
!MGMT_MSG_VALIDATE_NUL_TERM(notify_msg, msg_len)) {
data = mgmt_msg_native_data_decode(notify_msg, msg_len);
if (!data) {
log_err_fe_client("Corrupt error msg recv");
return;
}
if (notify_msg->result_type == LYD_JSON)
notify_data = (char *)notify_msg->result;
else
notify_data =
yang_convert_lyd_format(notify_msg->result,
msg_len,
notify_msg->result_type,
LYD_JSON, true);
if (!notify_data) {
dlen = mgmt_msg_native_data_len_decode(notify_msg, msg_len);
if (notify_msg->result_type != LYD_JSON)
data = yang_convert_lyd_format(data, dlen,
notify_msg->result_type,
LYD_JSON, true);
if (!data) {
log_err_fe_client("Can't convert format %d to JSON",
notify_msg->result_type);
return;
Expand All @@ -588,11 +586,10 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
session->client->cbs
.async_notification(client, client->user_data,
session->client_id,
session->user_ctx,
notify_data);
session->user_ctx, data);
}
if (notify_msg->result_type != LYD_JSON)
darr_free(notify_data);
darr_free(data);
break;
default:
log_err_fe_client("unknown native message session-id %" PRIu64
Expand Down
130 changes: 125 additions & 5 deletions lib/mgmt_msg_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ extern "C" {
* mgmt_msg_native_get_msg_len() - Get the total length of the msg.
* mgmt_msg_native_send_msg() - Send the message.
*
* mgmt_msg_native_xpath_encode() - Encode xpath in xpath, data format message.
* mgmt_msg_native_xpath_data_decode() - Decode xpath, data format message.
* mgmt_msg_native_xpath_decode() - Get the xpath, from xpath, data format message.
* mgmt_msg_native_data_decode() - Get the secondary data from xpath, data message.
* mgmt_msg_native_data_len_decode() - Get length of secondary data.
*
* -------------------------------------
* [Advanced Use] Dynamic Array Messages
Expand Down Expand Up @@ -299,18 +304,18 @@ _Static_assert(sizeof(struct mgmt_msg_get_data) ==
* struct mgmt_msg_notify_data - Message carrying notification data.
*
* @result_type: ``LYD_FORMAT`` for format of the @result value.
* @result: The tree data in @result_type format.
*
* @data: The xpath string of the notification followed by the tree data in
* @result_type format.
*/
struct mgmt_msg_notify_data {
struct mgmt_msg_header;
uint8_t result_type;
uint8_t resv2[7];

alignas(8) uint8_t result[];
alignas(8) char data[];
};
_Static_assert(sizeof(struct mgmt_msg_notify_data) ==
offsetof(struct mgmt_msg_notify_data, result),
offsetof(struct mgmt_msg_notify_data, data),
"Size mismatch");

/*
Expand Down Expand Up @@ -404,7 +409,12 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn,
* Return: a pointer to the newly appended data.
*/
#define mgmt_msg_native_append(msg, data, len) \
memcpy(darr_append(*mgmt_msg_native_get_darrp(msg), len), data, len)
({ \
uint8_t **darrp = mgmt_msg_native_get_darrp(msg); \
uint8_t *p = darr_append_n(*darrp, len); \
memcpy(p, data, len); \
p; \
})

/**
* mgmt_msg_native_send_msg(msg, short_circuit_ok) - Send a native msg.
Expand Down Expand Up @@ -458,6 +468,116 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn,
*/
#define mgmt_msg_native_get_darrp(msg) ((uint8_t **)&(msg))

/* ------------------------- */
/* Encode and Decode Helpers */
/* ------------------------- */

/**
* mgmt_msg_native_xpath_encode() - encode an xpath in a xpath, data message.
* @msg: Pointer to the native message.
* @xpath: The xpath string to encode.
*
* This function starts the encoding of a message that can be decoded with
* `mgmt_msg_native_xpath_data_decode()`. The variable length data is comprised
* of a NUL terminated string followed by some data of any format. This starts
* the first half of the encoding, after which one can simply append the
* secondary data to the message.
*/
#define mgmt_msg_native_xpath_encode(msg, xpath) \
do { \
size_t __slen = strlen(xpath) + 1; \
mgmt_msg_native_append(msg, xpath, __slen); \
(msg)->vsplit = __slen; \
} while (0)

/**
* mgmt_msg_native_xpath_data_decode() - decode an xpath, data format message.
* @msg: Pointer to the native message.
* @msglen: Length of the message.
* @data: [OUT] Pointer to the data section of the variable data
*
* This function decodes a message that was encoded with
* `mgmt_msg_native_xpath_encode()`. The variable length data is comprised of a
* NUL terminated string followed by some data of any format.
*
* Return:
* The xpath string or NULL if there was an error decoding (i.e., the
* message is corrupt).
*/
#define mgmt_msg_native_xpath_data_decode(msg, msglen, data) \
({ \
size_t __len = (msglen) - sizeof(*msg); \
const char *__s = NULL; \
if (msg->vsplit && msg->vsplit <= __len && \
msg->data[msg->vsplit - 1] == 0) { \
(data) = msg->data + msg->vsplit; \
__s = msg->data; \
} \
__s; \
})

/**
* mgmt_msg_native_xpath_decode() - return the xpath from xpath, data message.
* @msg: Pointer to the native message.
* @msglen: Length of the message.
*
* This function decodes the xpath from a message that was encoded with
* `mgmt_msg_native_xpath_encode()`. The variable length data is comprised of a
* NUL terminated string followed by some data of any format.
*
* Return:
* The xpath string or NULL if there was an error decoding (i.e., the
* message is corrupt).
*/
#define mgmt_msg_native_xpath_decode(msg, msglen) \
({ \
size_t __len = (msglen) - sizeof(*msg); \
const char *__s = msg->data; \
if (!msg->vsplit || msg->vsplit > __len || \
__s[msg->vsplit - 1] != 0) \
__s = NULL; \
__s; \
})

/**
* mgmt_msg_native_data_decode() - return the data from xpath, data message.
* @msg: Pointer to the native message.
* @msglen: Length of the message.
*
* This function decodes the secondary data from a message that was encoded with
* `mgmt_msg_native_xpath_encode()`. The variable length data is comprised of a
* NUL terminated string followed by some data of any format.
*
* Return:
* The secondary data or NULL if there was an error decoding (i.e., the
* message is corrupt).
*/
#define mgmt_msg_native_data_decode(msg, msglen) \
({ \
size_t __len = (msglen) - sizeof(*msg); \
const char *__data = msg->data + msg->vsplit; \
if (!msg->vsplit || msg->vsplit > __len || __data[-1] != 0) \
__data = NULL; \
__data; \
})

/**
* mgmt_msg_native_data_len_decode() - len of data in xpath, data format message.
* @msg: Pointer to the native message.
* @msglen: Length of the message.
*
* This function returns the length of the secondary variable data from a
* message that was encoded with `mgmt_msg_native_xpath_encode()`. The variable
* length data is comprised of a NUL terminated string followed by some data of
* any format.
*
* Return:
* The length of the secondary variable data. The message is assumed to be
* validated as not corrupt already.
*/
#define mgmt_msg_native_data_len_decode(msg, msglen) \
((msglen) - sizeof(*msg) - msg->vsplit)

#ifdef __cplusplus
}
#endif
Expand Down
Loading

0 comments on commit 5332e44

Please sign in to comment.