mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-25 22:30:52 +00:00
Merge pull request #15381 from LabNConsulting/chopps/nb-notif
lib: mgmtd: add xpath arg to YANG notification message
This commit is contained in:
commit
5332e447d9
@ -163,6 +163,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
|
|||||||
_hook_unregister(&_hook_##hookname, \
|
_hook_unregister(&_hook_##hookname, \
|
||||||
_hook_typecheck_arg_##hookname(func), arg, true)
|
_hook_typecheck_arg_##hookname(func), arg, true)
|
||||||
|
|
||||||
|
#define hook_have_hooks(hookname) (_hook_##hookname.entries != NULL)
|
||||||
|
|
||||||
/* invoke hooks
|
/* invoke hooks
|
||||||
* this is private (static) to the file that has the DEFINE_HOOK statement
|
* this is private (static) to the file that has the DEFINE_HOOK statement
|
||||||
*/
|
*/
|
||||||
|
@ -311,13 +311,15 @@ static int be_client_send_error(struct mgmt_be_client *client, uint64_t txn_id,
|
|||||||
return ret;
|
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_be_client *client = __be_client;
|
||||||
struct mgmt_msg_notify_data *msg = NULL;
|
struct mgmt_msg_notify_data *msg = NULL;
|
||||||
LYD_FORMAT format = LYD_JSON;
|
LYD_FORMAT format = LYD_JSON;
|
||||||
uint8_t **darrp;
|
uint8_t **darrp;
|
||||||
LY_ERR err;
|
LY_ERR err;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
assert(tree);
|
assert(tree);
|
||||||
|
|
||||||
@ -331,6 +333,8 @@ void mgmt_be_send_notification(struct lyd_node *tree)
|
|||||||
msg->code = MGMT_MSG_CODE_NOTIFY;
|
msg->code = MGMT_MSG_CODE_NOTIFY;
|
||||||
msg->result_type = format;
|
msg->result_type = format;
|
||||||
|
|
||||||
|
mgmt_msg_native_xpath_encode(msg, xpath);
|
||||||
|
|
||||||
darrp = mgmt_msg_native_get_darrp(msg);
|
darrp = mgmt_msg_native_get_darrp(msg);
|
||||||
err = yang_print_tree_append(darrp, tree, format,
|
err = yang_print_tree_append(darrp, tree, format,
|
||||||
(LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT |
|
(LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT |
|
||||||
@ -339,6 +343,7 @@ void mgmt_be_send_notification(struct lyd_node *tree)
|
|||||||
flog_err(EC_LIB_LIBYANG,
|
flog_err(EC_LIB_LIBYANG,
|
||||||
"%s: error creating notification data: %s", __func__,
|
"%s: error creating notification data: %s", __func__,
|
||||||
ly_strerrcode(err));
|
ly_strerrcode(err));
|
||||||
|
ret = 1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,53 +351,7 @@ void mgmt_be_send_notification(struct lyd_node *tree)
|
|||||||
mgmt_msg_native_get_msg_len(msg), false);
|
mgmt_msg_native_get_msg_len(msg), false);
|
||||||
done:
|
done:
|
||||||
mgmt_msg_native_free_msg(msg);
|
mgmt_msg_native_free_msg(msg);
|
||||||
lyd_free_all(tree);
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx,
|
static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx,
|
||||||
@ -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 mgmt_msg_notify_data *notif_msg = msgbuf;
|
||||||
struct nb_node *nb_node;
|
struct nb_node *nb_node;
|
||||||
char notif[XPATH_MAXLEN];
|
|
||||||
struct lyd_node *dnode;
|
struct lyd_node *dnode;
|
||||||
|
const char *data;
|
||||||
|
const char *notif;
|
||||||
LY_ERR err;
|
LY_ERR err;
|
||||||
|
|
||||||
debug_be_client("Received notification for client %s", client->name);
|
debug_be_client("Received notification for client %s", client->name);
|
||||||
|
|
||||||
err = yang_parse_notification(notif_msg->result_type,
|
notif = mgmt_msg_native_xpath_data_decode(notif_msg, msg_len, data);
|
||||||
(char *)notif_msg->result, &dnode);
|
if (!notif || !data) {
|
||||||
if (err)
|
log_err_be_client("Corrupt notify msg");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
lysc_path(dnode->schema, LYSC_PATH_DATA, notif, sizeof(notif));
|
|
||||||
|
|
||||||
nb_node = nb_node_find(notif);
|
nb_node = nb_node_find(notif);
|
||||||
if (!nb_node || !nb_node->cbs.notify) {
|
if (!nb_node) {
|
||||||
debug_be_client("No notification callback for %s", notif);
|
log_err_be_client("No schema found for notification: %s", notif);
|
||||||
goto cleanup;
|
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);
|
nb_callback_notify(nb_node, notif, dnode);
|
||||||
cleanup:
|
|
||||||
lyd_free_all(dnode);
|
lyd_free_all(dnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1202,7 +1174,7 @@ struct mgmt_be_client *mgmt_be_client_create(const char *client_name,
|
|||||||
"BE-client", debug_check_be_client());
|
"BE-client", debug_check_be_client());
|
||||||
|
|
||||||
/* Hook to receive notifications */
|
/* 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);
|
client);
|
||||||
|
|
||||||
debug_be_client("Initialized client '%s'", client_name);
|
debug_be_client("Initialized client '%s'", client_name);
|
||||||
|
@ -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_config_xpaths, char **config_xpaths,
|
||||||
int n_oper_xpaths, char **oper_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.
|
* Destroy backend client and cleanup everything.
|
||||||
*/
|
*/
|
||||||
|
@ -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_notify_data *notify_msg;
|
||||||
struct mgmt_msg_tree_data *tree_msg;
|
struct mgmt_msg_tree_data *tree_msg;
|
||||||
struct mgmt_msg_error *err_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,
|
debug_fe_client("Got native message for session-id %" PRIu64,
|
||||||
msg->refer_id);
|
msg->refer_id);
|
||||||
@ -563,20 +564,17 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify_msg->result_type != LYD_LYB &&
|
data = mgmt_msg_native_data_decode(notify_msg, msg_len);
|
||||||
!MGMT_MSG_VALIDATE_NUL_TERM(notify_msg, msg_len)) {
|
if (!data) {
|
||||||
log_err_fe_client("Corrupt error msg recv");
|
log_err_fe_client("Corrupt error msg recv");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (notify_msg->result_type == LYD_JSON)
|
dlen = mgmt_msg_native_data_len_decode(notify_msg, msg_len);
|
||||||
notify_data = (char *)notify_msg->result;
|
if (notify_msg->result_type != LYD_JSON)
|
||||||
else
|
data = yang_convert_lyd_format(data, dlen,
|
||||||
notify_data =
|
notify_msg->result_type,
|
||||||
yang_convert_lyd_format(notify_msg->result,
|
LYD_JSON, true);
|
||||||
msg_len,
|
if (!data) {
|
||||||
notify_msg->result_type,
|
|
||||||
LYD_JSON, true);
|
|
||||||
if (!notify_data) {
|
|
||||||
log_err_fe_client("Can't convert format %d to JSON",
|
log_err_fe_client("Can't convert format %d to JSON",
|
||||||
notify_msg->result_type);
|
notify_msg->result_type);
|
||||||
return;
|
return;
|
||||||
@ -588,11 +586,10 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
|
|||||||
session->client->cbs
|
session->client->cbs
|
||||||
.async_notification(client, client->user_data,
|
.async_notification(client, client->user_data,
|
||||||
session->client_id,
|
session->client_id,
|
||||||
session->user_ctx,
|
session->user_ctx, data);
|
||||||
notify_data);
|
|
||||||
}
|
}
|
||||||
if (notify_msg->result_type != LYD_JSON)
|
if (notify_msg->result_type != LYD_JSON)
|
||||||
darr_free(notify_data);
|
darr_free(data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_err_fe_client("unknown native message session-id %" PRIu64
|
log_err_fe_client("unknown native message session-id %" PRIu64
|
||||||
|
@ -77,6 +77,11 @@ extern "C" {
|
|||||||
* mgmt_msg_native_get_msg_len() - Get the total length of the msg.
|
* mgmt_msg_native_get_msg_len() - Get the total length of the msg.
|
||||||
* mgmt_msg_native_send_msg() - Send the message.
|
* 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
|
* [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.
|
* struct mgmt_msg_notify_data - Message carrying notification data.
|
||||||
*
|
*
|
||||||
* @result_type: ``LYD_FORMAT`` for format of the @result value.
|
* @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_notify_data {
|
||||||
struct mgmt_msg_header;
|
struct mgmt_msg_header;
|
||||||
uint8_t result_type;
|
uint8_t result_type;
|
||||||
uint8_t resv2[7];
|
uint8_t resv2[7];
|
||||||
|
|
||||||
alignas(8) uint8_t result[];
|
alignas(8) char data[];
|
||||||
};
|
};
|
||||||
_Static_assert(sizeof(struct mgmt_msg_notify_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");
|
"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.
|
* Return: a pointer to the newly appended data.
|
||||||
*/
|
*/
|
||||||
#define mgmt_msg_native_append(msg, data, len) \
|
#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.
|
* 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))
|
#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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2076,20 +2076,68 @@ DEFINE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments),
|
|||||||
|
|
||||||
int nb_notification_send(const char *xpath, struct list *arguments)
|
int nb_notification_send(const char *xpath, struct list *arguments)
|
||||||
{
|
{
|
||||||
|
struct lyd_node *root = NULL;
|
||||||
|
struct lyd_node *dnode;
|
||||||
|
struct yang_data *data;
|
||||||
|
struct listnode *ln;
|
||||||
|
LY_ERR err;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DEBUGD(&nb_dbg_notif, "northbound notification: %s", xpath);
|
DEBUGD(&nb_dbg_notif, "northbound notification: %s", xpath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call old hook functions
|
||||||
|
*/
|
||||||
ret = hook_call(nb_notification_send, xpath, arguments);
|
ret = hook_call(nb_notification_send, xpath, arguments);
|
||||||
|
|
||||||
|
if (!hook_have_hooks(nb_notification_tree_send))
|
||||||
|
goto done;
|
||||||
|
/*
|
||||||
|
* Convert yang data arguments list to a libyang data tree for new hook
|
||||||
|
* functions.
|
||||||
|
*/
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(arguments, ln, data)) {
|
||||||
|
err = lyd_new_path(root, ly_native_ctx, data->xpath,
|
||||||
|
data->value, LYD_NEW_PATH_UPDATE, &dnode);
|
||||||
|
if (err != LY_SUCCESS)
|
||||||
|
goto lyerr;
|
||||||
|
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) {
|
||||||
|
lyerr:
|
||||||
|
flog_err(EC_LIB_LIBYANG,
|
||||||
|
"%s: error creating notification data: %s",
|
||||||
|
__func__, ly_strerrcode(err));
|
||||||
|
ret += 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call new hook functions
|
||||||
|
*/
|
||||||
|
ret += nb_notification_tree_send(xpath, root);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (root)
|
||||||
|
lyd_free_all(root);
|
||||||
if (arguments)
|
if (arguments)
|
||||||
list_delete(&arguments);
|
list_delete(&arguments);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_HOOK(nb_notification_tree_send, (struct lyd_node *tree), (tree));
|
DEFINE_HOOK(nb_notification_tree_send,
|
||||||
|
(const char *xpath, const struct lyd_node *tree), (xpath, tree));
|
||||||
|
|
||||||
int nb_notification_tree_send(struct lyd_node *tree)
|
int nb_notification_tree_send(const char *xpath, const struct lyd_node *tree)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -2098,8 +2146,7 @@ int nb_notification_tree_send(struct lyd_node *tree)
|
|||||||
DEBUGD(&nb_dbg_notif, "northbound tree notification: %s",
|
DEBUGD(&nb_dbg_notif, "northbound tree notification: %s",
|
||||||
tree->schema->name);
|
tree->schema->name);
|
||||||
|
|
||||||
ret = hook_call(nb_notification_tree_send, tree);
|
ret = hook_call(nb_notification_tree_send, xpath, tree);
|
||||||
lyd_free_all(tree);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -803,6 +803,8 @@ typedef enum nb_error (*nb_oper_data_finish_cb)(const struct lyd_node *tree,
|
|||||||
/* Hooks. */
|
/* Hooks. */
|
||||||
DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments),
|
DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments),
|
||||||
(xpath, arguments));
|
(xpath, arguments));
|
||||||
|
DECLARE_HOOK(nb_notification_tree_send,
|
||||||
|
(const char *xpath, const struct lyd_node *tree), (xpath, tree));
|
||||||
DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
|
DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
|
||||||
DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
|
DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
|
||||||
|
|
||||||
@ -1491,14 +1493,17 @@ extern int nb_notification_send(const char *xpath, struct list *arguments);
|
|||||||
* Send a YANG notification from a backend . This is a no-op unless th
|
* Send a YANG notification from a backend . This is a no-op unless th
|
||||||
* 'nb_notification_tree_send' hook was registered by a northbound plugin.
|
* 'nb_notification_tree_send' hook was registered by a northbound plugin.
|
||||||
*
|
*
|
||||||
|
* xpath
|
||||||
|
* XPath of the YANG notification.
|
||||||
|
*
|
||||||
* tree
|
* tree
|
||||||
* The libyang tree for the notification. The tree will be freed by
|
* The libyang tree for the notification.
|
||||||
* this call.
|
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* NB_OK on success, NB_ERR otherwise.
|
* NB_OK on success, NB_ERR otherwise.
|
||||||
*/
|
*/
|
||||||
extern int nb_notification_tree_send(struct lyd_node *tree);
|
extern int nb_notification_tree_send(const char *xpath,
|
||||||
|
const struct lyd_node *tree);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Associate a user pointer to a configuration node.
|
* Associate a user pointer to a configuration node.
|
||||||
|
40
lib/yang.c
40
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);
|
zlog(priority, "libyang: %s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
|
LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format,
|
||||||
struct lyd_node **notif)
|
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;
|
struct ly_in *in = NULL;
|
||||||
bool found = false;
|
|
||||||
LY_ERR err;
|
LY_ERR err;
|
||||||
|
|
||||||
err = ly_in_new_memory(data, &in);
|
err = ly_in_new_memory(data, &in);
|
||||||
@ -736,26 +736,20 @@ LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
err = lyd_find_xpath3(NULL, tree, xpath, NULL, &set);
|
||||||
* Notification can be a child of some data node, so traverse the tree
|
if (err) {
|
||||||
* until we find the notification.
|
zlog_err("Failed to parse notification: %s", ly_last_errmsg());
|
||||||
*/
|
lyd_free_all(tree);
|
||||||
LYD_TREE_DFS_BEGIN (tree, dnode) {
|
return err;
|
||||||
if (dnode->schema->nodetype == LYS_NOTIF) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
LYD_TREE_DFS_END(tree, dnode);
|
|
||||||
}
|
}
|
||||||
|
if (set->count == 0) {
|
||||||
if (!found) {
|
zlog_err("Notification not found in the parsed tree: %s", xpath);
|
||||||
zlog_err("Notification not found in the parsed tree");
|
ly_set_free(set, NULL);
|
||||||
lyd_free_all(tree);
|
lyd_free_all(tree);
|
||||||
return LY_ENOTFOUND;
|
return LY_ENOTFOUND;
|
||||||
}
|
}
|
||||||
|
*notif = set->dnodes[0];
|
||||||
*notif = dnode;
|
ly_set_free(set, NULL);
|
||||||
|
|
||||||
return LY_SUCCESS;
|
return LY_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,9 +784,9 @@ uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format,
|
|||||||
return darr;
|
return darr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *yang_convert_lyd_format(const uint8_t *data, size_t data_len,
|
char *yang_convert_lyd_format(const char *data, size_t data_len,
|
||||||
LYD_FORMAT in_format,
|
LYD_FORMAT in_format, LYD_FORMAT out_format,
|
||||||
LYD_FORMAT out_format, bool shrink)
|
bool shrink)
|
||||||
{
|
{
|
||||||
struct lyd_node *tree = NULL;
|
struct lyd_node *tree = NULL;
|
||||||
uint32_t options = LYD_PRINT_WD_EXPLICIT | LYD_PRINT_WITHSIBLINGS;
|
uint32_t options = LYD_PRINT_WD_EXPLICIT | LYD_PRINT_WITHSIBLINGS;
|
||||||
|
@ -611,6 +611,7 @@ extern void yang_debugging_set(bool enable);
|
|||||||
* Parse a YANG notification.
|
* Parse a YANG notification.
|
||||||
*
|
*
|
||||||
* Args:
|
* Args:
|
||||||
|
* xpath: xpath of notification.
|
||||||
* format: LYD_FORMAT of input data.
|
* format: LYD_FORMAT of input data.
|
||||||
* data: input data.
|
* data: input data.
|
||||||
* notif: pointer to the libyang data tree to store the parsed notification.
|
* 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
|
* the pointer to the notification node is still returned, but it's
|
||||||
* part of the full data tree with all its parents.
|
* part of the full data tree with all its parents.
|
||||||
*/
|
*/
|
||||||
extern LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
|
extern LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format,
|
||||||
struct lyd_node **notif);
|
const char *data, struct lyd_node **notif);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Print" the yang tree in `root` into dynamic sized array.
|
* "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:
|
* Return:
|
||||||
* A darr based string or NULL for error.
|
* 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 in_format,
|
||||||
LYD_FORMAT out_format, bool shrink);
|
LYD_FORMAT out_format, bool shrink);
|
||||||
|
|
||||||
|
@ -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_client_adapter *adapter;
|
||||||
struct mgmt_be_xpath_map *map;
|
struct mgmt_be_xpath_map *map;
|
||||||
char notif[XPATH_MAXLEN];
|
struct nb_node *nb_node;
|
||||||
struct lyd_node *dnode;
|
const char *notif;
|
||||||
LY_ERR err;
|
uint id, len;
|
||||||
uint id;
|
|
||||||
|
|
||||||
if (!darr_len(be_notif_xpath_map))
|
if (!darr_len(be_notif_xpath_map))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err = yang_parse_notification(msg->result_type, (char *)msg->result,
|
notif = mgmt_msg_native_xpath_decode(msg, msglen);
|
||||||
&dnode);
|
if (!notif) {
|
||||||
if (err)
|
__log_err("Corrupt notify msg");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lysc_path(dnode->schema, LYSC_PATH_DATA, notif, sizeof(notif));
|
nb_node = nb_node_find(notif);
|
||||||
|
if (!nb_node) {
|
||||||
lyd_free_all(dnode);
|
__log_err("No schema found for notification: %s", notif);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
darr_foreach_p (be_notif_xpath_map, map) {
|
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;
|
continue;
|
||||||
|
|
||||||
FOREACH_BE_CLIENT_BITS (id, map->clients) {
|
FOREACH_BE_CLIENT_BITS (id, map->clients) {
|
||||||
|
@ -321,12 +321,18 @@ class Session:
|
|||||||
while True:
|
while True:
|
||||||
logging.debug("Waiting for Notify Message")
|
logging.debug("Waiting for Notify Message")
|
||||||
mhdr, mfixed, mdata = self.recv_native_msg()
|
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:
|
if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY:
|
||||||
logging.debug("Received Notify Message: %s: %s", mfixed, mdata)
|
logging.debug("Received Notify Message: %s: %s", mfixed, mdata)
|
||||||
else:
|
else:
|
||||||
raise Exception(f"Received NON-NOTIFY Message: {mfixed}: {mdata}")
|
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:
|
if not xpaths:
|
||||||
return result
|
return result
|
||||||
js = json.loads(result)
|
js = json.loads(result)
|
||||||
|
Loading…
Reference in New Issue
Block a user