diff options
-rw-r--r-- | lib/mgmt_be_client.c | 35 | ||||
-rw-r--r-- | lib/mgmt_fe_client.c | 27 | ||||
-rw-r--r-- | lib/mgmt_msg_native.h | 130 | ||||
-rw-r--r-- | lib/yang.c | 40 | ||||
-rw-r--r-- | lib/yang.h | 7 | ||||
-rw-r--r-- | mgmtd/mgmt_be_adapter.c | 26 | ||||
-rwxr-xr-x | tests/topotests/lib/fe_client.py | 10 |
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) |