Merge pull request #17782 from LabNConsulting/chopps/new-notify-msg-fmt

New YANG notify msg fmt
This commit is contained in:
Donald Sharp 2025-01-07 13:15:40 -05:00 committed by GitHub
commit 0a52c233d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 136 additions and 27 deletions

View File

@ -312,11 +312,11 @@ static int be_client_send_error(struct mgmt_be_client *client, uint64_t txn_id,
return ret; return ret;
} }
static int mgmt_be_send_notification(void *__be_client, const char *xpath, static int __send_notification(struct mgmt_be_client *client, const char *xpath,
const struct lyd_node *tree) const struct lyd_node *tree, uint8_t op)
{ {
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_LYB;
LYD_FORMAT format = LYD_JSON; LYD_FORMAT format = LYD_JSON;
uint8_t **darrp; uint8_t **darrp;
LY_ERR err; LY_ERR err;
@ -324,37 +324,91 @@ static int mgmt_be_send_notification(void *__be_client, const char *xpath,
assert(tree); assert(tree);
debug_be_client("%s: sending YANG notification: %s", __func__, debug_be_client("%s: sending %sYANG %snotification: %s", __func__,
tree->schema->name); op == NOTIFY_OP_DS_DELETE ? "delete "
: op == NOTIFY_OP_DS_REPLACE ? "replace "
: op == NOTIFY_OP_DS_PATCH ? "patch "
: "",
op == NOTIFY_OP_NOTIFICATION ? "" : "DS ", xpath ?: tree->schema->name);
/* /*
* Allocate a message and append the data to it using `format` * Allocate a message and append the data to it using `format`
*/ */
msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_notify_data, 0, msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_notify_data, 0, MTYPE_MSG_NATIVE_NOTIFY);
MTYPE_MSG_NATIVE_NOTIFY);
msg->code = MGMT_MSG_CODE_NOTIFY; msg->code = MGMT_MSG_CODE_NOTIFY;
msg->result_type = format; msg->result_type = format;
msg->op = op;
mgmt_msg_native_xpath_encode(msg, xpath); mgmt_msg_native_xpath_encode(msg, xpath);
if (tree) {
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 |
LYD_PRINT_WITHSIBLINGS)); LYD_PRINT_WITHSIBLINGS));
if (err) { if (err) {
flog_err(EC_LIB_LIBYANG, flog_err(EC_LIB_LIBYANG, "%s: error creating notification data: %s",
"%s: error creating notification data: %s", __func__, __func__, ly_strerrcode(err));
ly_strerrcode(err));
ret = 1; ret = 1;
goto done; goto done;
} }
}
(void)be_client_send_native_msg(client, msg, ret = be_client_send_native_msg(client, msg, 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);
return ret; return ret;
} }
/**
* mgmt_be_send_ds_delete_notification() - Send DS notification to mgmtd
*/
int mgmt_be_send_ds_delete_notification(const char *path)
{
if (!__be_client) {
debug_be_client("%s: No mgmtd connection for DS delete notification: %s", __func__,
path);
return 1;
}
return __send_notification(__be_client, path, NULL, NOTIFY_OP_DS_DELETE);
}
/**
* mgmt_be_send_ds_patch_notification() - Send a YANG patch DS notification to mgmtd
*/
int mgmt_be_send_ds_patch_notification(const char *path, const struct lyd_node *patch)
{
if (!__be_client) {
debug_be_client("%s: No mgmtd connection for DS delete notification: %s", __func__,
path);
return 1;
}
return __send_notification(__be_client, path, patch, NOTIFY_OP_DS_PATCH);
}
/**
* mgmt_be_send_ds_replace_notification() - Send a replace DS notification to mgmtd
*/
int mgmt_be_send_ds_replace_notification(const char *path, const struct lyd_node *tree)
{
if (!__be_client) {
debug_be_client("%s: No mgmtd connection for DS delete notification: %s", __func__,
path);
return 1;
}
return __send_notification(__be_client, path, tree, NOTIFY_OP_DS_REPLACE);
}
/**
* mgmt_be_send_notification() - Send notification to mgmtd
*
* This function is attached to the northbound notification hook.
*/
static int mgmt_be_send_notification(void *__client, const char *path, const struct lyd_node *tree)
{
__send_notification(__client, path, tree, NOTIFY_OP_NOTIFICATION);
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,
uint64_t txn_id, bool create) uint64_t txn_id, bool create)
{ {

View File

@ -112,6 +112,22 @@ extern struct mgmt_be_client *
mgmt_be_client_create(const char *name, struct mgmt_be_client_cbs *cbs, mgmt_be_client_create(const char *name, struct mgmt_be_client_cbs *cbs,
uintptr_t user_data, struct event_loop *event_loop); uintptr_t user_data, struct event_loop *event_loop);
/**
* mgmt_be_send_ds_delete_notification() - Send a datastore delete notification.
*/
extern int mgmt_be_send_ds_delete_notification(const char *path);
/**
* mgmt_be_send_ds_patch_notification() - Send a datastore YANG patch notification.
*/
extern int mgmt_be_send_ds_patch_notification(const char *path, const struct lyd_node *tree);
/**
* mgmt_be_send_ds_replace_notification() - Send a datastore replace notification.
*/
extern int mgmt_be_send_ds_replace_notification(const char *path, const struct lyd_node *tree);
/* /*
* Initialize library vty (adds debug support). * Initialize library vty (adds debug support).
* *

View File

@ -323,22 +323,29 @@ _Static_assert(sizeof(struct mgmt_msg_get_data) ==
offsetof(struct mgmt_msg_get_data, xpath), offsetof(struct mgmt_msg_get_data, xpath),
"Size mismatch"); "Size mismatch");
#define NOTIFY_OP_NOTIFICATION 0
#define NOTIFY_OP_DS_REPLACE 1
#define NOTIFY_OP_DS_DELETE 2
#define NOTIFY_OP_DS_PATCH 3
/** /**
* 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.
* @data: The xpath string of the notification followed by the tree data in * @data: The xpath string of the notification followed by the tree data in
* @result_type format. * @result_type format.
* @op: notify operation type.
*/ */
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 op;
uint8_t resv2[6];
alignas(8) char data[]; 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, data),
offsetof(struct mgmt_msg_notify_data, data),
"Size mismatch"); "Size mismatch");
#define EDIT_FLAG_IMPLICIT_LOCK 0x01 #define EDIT_FLAG_IMPLICIT_LOCK 0x01

View File

@ -78,8 +78,13 @@ GET_DATA_FLAG_STATE = 0x1
GET_DATA_FLAG_CONFIG = 0x2 GET_DATA_FLAG_CONFIG = 0x2
GET_DATA_FLAG_EXACT = 0x4 GET_DATA_FLAG_EXACT = 0x4
MSG_NOTIFY_FMT = "=B7x" MSG_NOTIFY_FMT = "=BB6x"
NOTIFY_FIELD_RESULT_TYPE = 0 NOTIFY_FIELD_RESULT_TYPE = 0
NOTIFY_FIELD_OP = 1
NOTIFY_OP_NOTIFICATION = 0
NOTIFY_OP_REPLACE = 1
NOTIFY_OP_DELETE = 2
NOTIFY_OP_PATCH = 3
MSG_NOTIFY_SELECT_FMT = "=B7x" MSG_NOTIFY_SELECT_FMT = "=B7x"
@ -363,10 +368,12 @@ class Session:
raise Exception(f"Received NON-NOTIFY Message: {mfixed}: {mdata}") raise Exception(f"Received NON-NOTIFY Message: {mfixed}: {mdata}")
vsplit = mhdr[HDR_FIELD_VSPLIT] vsplit = mhdr[HDR_FIELD_VSPLIT]
result_type = mfixed[0]
op = mfixed[1]
assert mdata[vsplit - 1] == 0 assert mdata[vsplit - 1] == 0
assert mdata[-1] == 0 assert mdata[-1] == 0
# xpath = mdata[: vsplit - 1].decode("utf-8") xpath = mdata[: vsplit - 1].decode("utf-8")
return mdata[vsplit:-1].decode("utf-8") return result_type, op, xpath, mdata[vsplit:-1].decode("utf-8")
else: else:
raise TimeoutError("Timeout waiting for notifications") raise TimeoutError("Timeout waiting for notifications")
@ -389,6 +396,9 @@ def __parse_args():
parser.add_argument( parser.add_argument(
"-c", "--config-only", action="store_true", help="return config only" "-c", "--config-only", action="store_true", help="return config only"
) )
parser.add_argument(
"--datastore", action="store_true", help="listen for datastore notifications"
)
parser.add_argument( parser.add_argument(
"-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query" "-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query"
) )
@ -434,9 +444,31 @@ def __main():
if args.listen is not None: if args.listen is not None:
i = args.notify_count i = args.notify_count
if args.listen:
sess.add_notify_select(True, args.listen)
while i > 0 or args.notify_count == 0: while i > 0 or args.notify_count == 0:
notif = sess.recv_notify(args.listen) result_type, op, xpath, notif = sess.recv_notify()
if op == NOTIFY_OP_NOTIFICATION:
if args.datastore:
logging.warning("ignoring non-datastore notification: %s", notif)
else:
print(notif) print(notif)
elif not args.datastore:
logging.warning(
"ignoring datastore notification op: %s xpath: %s data: %s",
op,
xpath,
notif,
)
elif op == NOTIFY_OP_PATCH:
print(f"#OP=PATCH: {xpath}")
print(notif)
elif op == NOTIFY_OP_REPLACE:
print(f"#OP=REPLACE: {xpath}")
print(notif)
elif op == NOTIFY_OP_DELETE:
print(f"#OP=DELETE: {xpath}")
assert len(notif) == 0
i -= 1 i -= 1