summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/mgmt_be_client.c35
-rw-r--r--lib/mgmt_fe_client.c27
-rw-r--r--lib/mgmt_msg_native.h130
-rw-r--r--lib/yang.c40
-rw-r--r--lib/yang.h7
-rw-r--r--mgmtd/mgmt_be_adapter.c26
-rwxr-xr-xtests/topotests/lib/fe_client.py10
7 files changed, 206 insertions, 69 deletions
diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c
index 589bf82c9..5896db1e5 100644
--- a/lib/mgmt_be_client.c
+++ b/lib/mgmt_be_client.c
@@ -333,6 +333,8 @@ static int mgmt_be_send_notification(void *__be_client, const char *xpath,
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 |
@@ -921,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);
}
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index 9f98a241f..bfdecedc4 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -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);
@@ -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;
@@ -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
diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h
index 7273170a1..53bb81be2 100644
--- a/lib/mgmt_msg_native.h
+++ b/lib/mgmt_msg_native.h
@@ -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
@@ -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");
/*
@@ -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.
@@ -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
diff --git a/lib/yang.c b/lib/yang.c
index 3ce24a318..03044fc29 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -714,12 +714,12 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
zlog(priority, "libyang: %s", msg);
}
-LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
- struct lyd_node **notif)
+LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format,
+ const char *data, struct lyd_node **notif)
{
- struct lyd_node *tree, *dnode;
+ struct lyd_node *tree;
+ struct ly_set *set = NULL;
struct ly_in *in = NULL;
- bool found = false;
LY_ERR err;
err = ly_in_new_memory(data, &in);
@@ -736,26 +736,20 @@ LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
return err;
}
- /*
- * Notification can be a child of some data node, so traverse the tree
- * until we find the notification.
- */
- LYD_TREE_DFS_BEGIN (tree, dnode) {
- if (dnode->schema->nodetype == LYS_NOTIF) {
- found = true;
- break;
- }
- LYD_TREE_DFS_END(tree, dnode);
+ err = lyd_find_xpath3(NULL, tree, xpath, NULL, &set);
+ if (err) {
+ zlog_err("Failed to parse notification: %s", ly_last_errmsg());
+ lyd_free_all(tree);
+ return err;
}
-
- if (!found) {
- zlog_err("Notification not found in the parsed tree");
+ if (set->count == 0) {
+ zlog_err("Notification not found in the parsed tree: %s", xpath);
+ ly_set_free(set, NULL);
lyd_free_all(tree);
return LY_ENOTFOUND;
}
-
- *notif = dnode;
-
+ *notif = set->dnodes[0];
+ ly_set_free(set, NULL);
return LY_SUCCESS;
}
@@ -790,9 +784,9 @@ uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format,
return darr;
}
-char *yang_convert_lyd_format(const uint8_t *data, size_t data_len,
- LYD_FORMAT in_format,
- LYD_FORMAT out_format, bool shrink)
+char *yang_convert_lyd_format(const char *data, size_t data_len,
+ LYD_FORMAT in_format, LYD_FORMAT out_format,
+ bool shrink)
{
struct lyd_node *tree = NULL;
uint32_t options = LYD_PRINT_WD_EXPLICIT | LYD_PRINT_WITHSIBLINGS;
diff --git a/lib/yang.h b/lib/yang.h
index 9c221445c..65f6a73e0 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -611,6 +611,7 @@ extern void yang_debugging_set(bool enable);
* Parse a YANG notification.
*
* Args:
+ * xpath: xpath of notification.
* format: LYD_FORMAT of input data.
* data: input data.
* notif: pointer to the libyang data tree to store the parsed notification.
@@ -618,8 +619,8 @@ extern void yang_debugging_set(bool enable);
* the pointer to the notification node is still returned, but it's
* part of the full data tree with all its parents.
*/
-extern LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
- struct lyd_node **notif);
+extern LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format,
+ const char *data, struct lyd_node **notif);
/*
* "Print" the yang tree in `root` into dynamic sized array.
@@ -647,7 +648,7 @@ extern uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format,
* Return:
* A darr based string or NULL for error.
*/
-extern char *yang_convert_lyd_format(const uint8_t *data, size_t msg_len,
+extern char *yang_convert_lyd_format(const char *data, size_t msg_len,
LYD_FORMAT in_format,
LYD_FORMAT out_format, bool shrink);
diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c
index d85d87b4b..b311bf469 100644
--- a/mgmtd/mgmt_be_adapter.c
+++ b/mgmtd/mgmt_be_adapter.c
@@ -592,25 +592,29 @@ static void mgmt_be_adapter_send_notify(struct mgmt_msg_notify_data *msg,
{
struct mgmt_be_client_adapter *adapter;
struct mgmt_be_xpath_map *map;
- char notif[XPATH_MAXLEN];
- struct lyd_node *dnode;
- LY_ERR err;
- uint id;
+ struct nb_node *nb_node;
+ const char *notif;
+ uint id, len;
if (!darr_len(be_notif_xpath_map))
return;
- err = yang_parse_notification(msg->result_type, (char *)msg->result,
- &dnode);
- if (err)
+ notif = mgmt_msg_native_xpath_decode(msg, msglen);
+ if (!notif) {
+ __log_err("Corrupt notify msg");
return;
+ }
- lysc_path(dnode->schema, LYSC_PATH_DATA, notif, sizeof(notif));
-
- lyd_free_all(dnode);
+ nb_node = nb_node_find(notif);
+ if (!nb_node) {
+ __log_err("No schema found for notification: %s", notif);
+ return;
+ }
darr_foreach_p (be_notif_xpath_map, map) {
- if (strncmp(map->xpath_prefix, notif, strlen(map->xpath_prefix)))
+ len = strlen(map->xpath_prefix);
+ if (strncmp(map->xpath_prefix, nb_node->xpath, len) &&
+ strncmp(map->xpath_prefix, notif, len))
continue;
FOREACH_BE_CLIENT_BITS (id, map->clients) {
diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py
index ec643bb0b..07059ccf3 100755
--- a/tests/topotests/lib/fe_client.py
+++ b/tests/topotests/lib/fe_client.py
@@ -321,12 +321,18 @@ class Session:
while True:
logging.debug("Waiting for Notify Message")
mhdr, mfixed, mdata = self.recv_native_msg()
- assert mdata[-1] == 0
- result = mdata[:-1].decode("utf-8")
if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY:
logging.debug("Received Notify Message: %s: %s", mfixed, mdata)
else:
raise Exception(f"Received NON-NOTIFY Message: {mfixed}: {mdata}")
+
+ vsplit = mhdr[HDR_FIELD_VSPLIT]
+ assert mdata[vsplit - 1] == 0
+ xpath = mdata[: vsplit - 1].decode("utf-8")
+
+ assert mdata[-1] == 0
+ result = mdata[vsplit:-1].decode("utf-8")
+
if not xpaths:
return result
js = json.loads(result)