Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: mgmtd: add xpath arg to YANG notification message #15381

Merged
merged 2 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading