From 9eb2c0a1dc80c2693f3290df85e04dbe58f7575d Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 12 Apr 2019 18:00:26 -0300 Subject: [PATCH] lib: add fine-grained debugging in the northbound Split the "debug northbound" command into the following commands: * debug northbound callbacks configuration * debug northbound callbacks state * debug northbound callbacks rpc * debug northbound notifications * debug northbound events * debug northbound client confd * debug northbound client sysrepo If "debug northbound" is entered alone, all of its suboptions are enabled. This commit also adds code to debug state/rpc callbacks and notifications (only configuration callbacks were logged before). Use the debugging infrastructure from "lib/debug.h" in order to benefit from its facilities (e.g. MT-safe debugging) and avoid code duplication. Signed-off-by: Renato Westphal --- lib/northbound.c | 86 ++++++++++++++++++++++++++++------- lib/northbound.h | 29 +++++++++++- lib/northbound_cli.c | 97 ++++++++++++++++++++++++++++++++-------- lib/northbound_confd.c | 92 +++++++++++++++++++++++++++++-------- lib/northbound_sysrepo.c | 70 ++++++++++++++++++++++++----- 5 files changed, 310 insertions(+), 64 deletions(-) diff --git a/lib/northbound.c b/lib/northbound.c index edf7e0eca6..9deb9c6cce 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -23,6 +23,7 @@ #include "log.h" #include "lib_errors.h" #include "command.h" +#include "debug.h" #include "db.h" #include "northbound.h" #include "northbound_cli.h" @@ -40,7 +41,7 @@ struct nb_config *running_config; */ static bool transaction_in_progress; -static int nb_configuration_callback(const enum nb_event event, +static int nb_callback_configuration(const enum nb_event event, struct nb_config_change *change); static struct nb_transaction *nb_transaction_new(struct nb_config *config, struct nb_config_cbs *changes, @@ -592,7 +593,7 @@ static int nb_candidate_validate_changes(struct nb_config *candidate, struct nb_config_change *change = (struct nb_config_change *)cb; int ret; - ret = nb_configuration_callback(NB_EV_VALIDATE, change); + ret = nb_callback_configuration(NB_EV_VALIDATE, change); if (ret != NB_OK) return NB_ERR_VALIDATION; } @@ -714,7 +715,7 @@ static void nb_log_callback(const enum nb_event event, * Call the northbound configuration callback associated to a given * configuration change. */ -static int nb_configuration_callback(const enum nb_event event, +static int nb_callback_configuration(const enum nb_event event, struct nb_config_change *change) { enum nb_operation operation = change->cb.operation; @@ -724,7 +725,7 @@ static int nb_configuration_callback(const enum nb_event event, union nb_resource *resource; int ret = NB_ERR; - if (debug_northbound) { + if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL)) { const char *value = "(none)"; if (dnode && !yang_snode_is_typeless_data(dnode->schema)) @@ -791,6 +792,57 @@ static int nb_configuration_callback(const enum nb_event event, return ret; } +struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node, + const char *xpath, + const void *list_entry) +{ + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (get_elem): xpath [%s] list_entry [%p]", + xpath, list_entry); + + return nb_node->cbs.get_elem(xpath, list_entry); +} + +const void *nb_callback_get_next(const struct nb_node *nb_node, + const void *parent_list_entry, + const void *list_entry) +{ + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (get_next): node [%s] parent_list_entry [%p] list_entry [%p]", + nb_node->xpath, parent_list_entry, list_entry); + + return nb_node->cbs.get_next(parent_list_entry, list_entry); +} + +int nb_callback_get_keys(const struct nb_node *nb_node, const void *list_entry, + struct yang_list_keys *keys) +{ + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (get_keys): node [%s] list_entry [%p]", + nb_node->xpath, list_entry); + + return nb_node->cbs.get_keys(list_entry, keys); +} + +const void *nb_callback_lookup_entry(const struct nb_node *nb_node, + const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (lookup_entry): node [%s] parent_list_entry [%p]", + nb_node->xpath, parent_list_entry); + + return nb_node->cbs.lookup_entry(parent_list_entry, keys); +} + +int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, + const struct list *input, struct list *output) +{ + DEBUGD(&nb_dbg_cbs_rpc, "northbound RPC: %s", xpath); + + return nb_node->cbs.rpc(xpath, input, output); +} + static struct nb_transaction *nb_transaction_new(struct nb_config *config, struct nb_config_cbs *changes, enum nb_client client, @@ -843,7 +895,7 @@ static int nb_transaction_process(enum nb_event event, break; /* Call the appropriate callback. */ - ret = nb_configuration_callback(event, change); + ret = nb_callback_configuration(event, change); switch (event) { case NB_EV_PREPARE: if (ret != NB_OK) @@ -958,7 +1010,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) /* Call the 'apply_finish' callbacks, sorted by their priorities. */ RB_FOREACH (cb, nb_config_cbs, &cbs) { - if (debug_northbound) + if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL)) nb_log_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, cb->xpath, NULL); @@ -1010,7 +1062,7 @@ static int nb_oper_data_iter_leaf(const struct nb_node *nb_node, if (lys_is_key((struct lys_node_leaf *)nb_node->snode, NULL)) return NB_OK; - data = nb_node->cbs.get_elem(xpath, list_entry); + data = nb_callback_get_elem(nb_node, xpath, list_entry); if (data == NULL) /* Leaf of type "empty" is not present. */ return NB_OK; @@ -1034,7 +1086,7 @@ static int nb_oper_data_iter_container(const struct nb_node *nb_node, struct yang_data *data; int ret; - data = nb_node->cbs.get_elem(xpath, list_entry); + data = nb_callback_get_elem(nb_node, xpath, list_entry); if (data == NULL) /* Presence container is not present. */ return NB_OK; @@ -1066,13 +1118,13 @@ nb_oper_data_iter_leaflist(const struct nb_node *nb_node, const char *xpath, struct yang_data *data; int ret; - list_entry = - nb_node->cbs.get_next(parent_list_entry, list_entry); + list_entry = nb_callback_get_next(nb_node, parent_list_entry, + list_entry); if (!list_entry) /* End of the list. */ break; - data = nb_node->cbs.get_elem(xpath, list_entry); + data = nb_callback_get_elem(nb_node, xpath, list_entry); if (data == NULL) continue; @@ -1105,15 +1157,16 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node, int ret; /* Obtain list entry. */ - list_entry = - nb_node->cbs.get_next(parent_list_entry, list_entry); + list_entry = nb_callback_get_next(nb_node, parent_list_entry, + list_entry); if (!list_entry) /* End of the list. */ break; if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) { /* Obtain the list entry keys. */ - if (nb_node->cbs.get_keys(list_entry, &list_keys) + if (nb_callback_get_keys(nb_node, list_entry, + &list_keys) != NB_OK) { flog_warn(EC_LIB_NB_CB_STATE, "%s: failed to get list keys", @@ -1291,7 +1344,8 @@ int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator, /* Find the list entry pointer. */ nn = dn->schema->priv; - list_entry = nn->cbs.lookup_entry(list_entry, &list_keys); + list_entry = + nb_callback_lookup_entry(nn, list_entry, &list_keys); if (list_entry == NULL) { list_delete(&list_dnodes); yang_dnode_free(dnode); @@ -1485,6 +1539,8 @@ int nb_notification_send(const char *xpath, struct list *arguments) { int ret; + DEBUGD(&nb_dbg_notif, "northbound notification: %s", xpath); + ret = hook_call(nb_notification_send, xpath, arguments); if (arguments) list_delete(&arguments); diff --git a/lib/northbound.h b/lib/northbound.h index bb6b62af7d..bfa28b3f65 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -33,6 +33,7 @@ extern "C" { /* Forward declaration(s). */ struct vty; +struct debug; /* Northbound events. */ enum nb_event { @@ -458,12 +459,38 @@ typedef int (*nb_oper_data_cb)(const struct lys_node *snode, /* Iterate over direct child nodes only. */ #define NB_OPER_DATA_ITER_NORECURSE 0x0001 +/* Hooks. */ DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments), (xpath, arguments)) +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)) -extern int debug_northbound; +/* Northbound debugging records */ +extern struct debug nb_dbg_cbs_config; +extern struct debug nb_dbg_cbs_state; +extern struct debug nb_dbg_cbs_rpc; +extern struct debug nb_dbg_notif; +extern struct debug nb_dbg_events; + +/* Global running configuration. */ extern struct nb_config *running_config; +/* Wrappers for the northbound callbacks. */ +extern struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node, + const char *xpath, + const void *list_entry); +extern const void *nb_callback_get_next(const struct nb_node *nb_node, + const void *parent_list_entry, + const void *list_entry); +extern int nb_callback_get_keys(const struct nb_node *nb_node, + const void *list_entry, + struct yang_list_keys *keys); +extern const void *nb_callback_lookup_entry(const struct nb_node *nb_node, + const void *parent_list_entry, + const struct yang_list_keys *keys); +extern int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, + const struct list *input, struct list *output); + /* * Create a northbound node for all YANG schema nodes. */ diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 917b048105..48faa7595a 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -26,6 +26,7 @@ #include "command.h" #include "termtable.h" #include "db.h" +#include "debug.h" #include "yang_translator.h" #include "northbound.h" #include "northbound_cli.h" @@ -34,7 +35,12 @@ #include "lib/northbound_cli_clippy.c" #endif -int debug_northbound; +struct debug nb_dbg_cbs_config = {0, "Northbound callbacks: configuration"}; +struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"}; +struct debug nb_dbg_cbs_rpc = {0, "Northbound callbacks: RPCs"}; +struct debug nb_dbg_notif = {0, "Northbound notifications"}; +struct debug nb_dbg_events = {0, "Northbound events"}; + struct nb_config *vty_shared_candidate_config; static struct thread_master *master; @@ -208,7 +214,7 @@ int nb_cli_rpc(const char *xpath, struct list *input, struct list *output) return CMD_WARNING; } - ret = nb_node->cbs.rpc(xpath, input, output); + ret = nb_callback_rpc(nb_node, xpath, input, output); switch (ret) { case NB_OK: return CMD_SUCCESS; @@ -1540,36 +1546,90 @@ DEFPY (rollback_config, } /* Debug CLI commands. */ -DEFUN (debug_nb, - debug_nb_cmd, - "debug northbound", - DEBUG_STR - "Northbound Debugging\n") +static struct debug *nb_debugs[] = { + &nb_dbg_cbs_config, &nb_dbg_cbs_state, &nb_dbg_cbs_rpc, + &nb_dbg_notif, &nb_dbg_events, +}; + +static const char *const nb_debugs_conflines[] = { + "debug northbound callbacks configuration", + "debug northbound callbacks state", + "debug northbound callbacks rpc", + "debug northbound notifications", + "debug northbound events", +}; + +DEFINE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set)); + +static void nb_debug_set_all(uint32_t flags, bool set) { - debug_northbound = 1; + for (unsigned int i = 0; i < array_size(nb_debugs); i++) { + DEBUG_FLAGS_SET(nb_debugs[i], flags, set); - return CMD_SUCCESS; + /* If all modes have been turned off, don't preserve options. */ + if (!DEBUG_MODE_CHECK(nb_debugs[i], DEBUG_MODE_ALL)) + DEBUG_CLEAR(nb_debugs[i]); + } + + hook_call(nb_client_debug_set_all, flags, set); } -DEFUN (no_debug_nb, - no_debug_nb_cmd, - "no debug northbound", - NO_STR DEBUG_STR - "Northbound Debugging\n") +DEFPY (debug_nb, + debug_nb_cmd, + "[no] debug northbound\ + [<\ + callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\ + |notifications$notifications\ + |events$events\ + >]", + NO_STR + DEBUG_STR + "Northbound debugging\n" + "Callbacks\n" + "Configuration\n" + "State\n" + "RPC\n" + "Notifications\n" + "Events\n") { - debug_northbound = 0; + uint32_t mode = DEBUG_NODE2MODE(vty->node); + + if (cbs) { + bool none = (!cbs_cfg && !cbs_state && !cbs_rpc); + + if (none || cbs_cfg) + DEBUG_MODE_SET(&nb_dbg_cbs_config, mode, !no); + if (none || cbs_state) + DEBUG_MODE_SET(&nb_dbg_cbs_state, mode, !no); + if (none || cbs_rpc) + DEBUG_MODE_SET(&nb_dbg_cbs_rpc, mode, !no); + } + if (notifications) + DEBUG_MODE_SET(&nb_dbg_notif, mode, !no); + if (events) + DEBUG_MODE_SET(&nb_dbg_events, mode, !no); + + /* no specific debug --> act on all of them */ + if (strmatch(argv[argc - 1]->text, "northbound")) + nb_debug_set_all(mode, !no); return CMD_SUCCESS; } +DEFINE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty)); + static int nb_debug_config_write(struct vty *vty) { - if (debug_northbound) - vty_out(vty, "debug northbound\n"); + for (unsigned int i = 0; i < array_size(nb_debugs); i++) + if (DEBUG_MODE_CHECK(nb_debugs[i], DEBUG_MODE_CONF)) + vty_out(vty, "%s\n", nb_debugs_conflines[i]); + + hook_call(nb_client_debug_config_write, vty); return 1; } +static struct debug_callbacks nb_dbg_cbs = {.debug_set_all = nb_debug_set_all}; static struct cmd_node nb_debug_node = {NORTHBOUND_DEBUG_NODE, "", 1}; void nb_cli_install_default(int node) @@ -1633,11 +1693,10 @@ void nb_cli_init(struct thread_master *tm) vty_shared_candidate_config = nb_config_new(NULL); /* Install debug commands */ + debug_init(&nb_dbg_cbs); install_node(&nb_debug_node, nb_debug_config_write); install_element(ENABLE_NODE, &debug_nb_cmd); - install_element(ENABLE_NODE, &no_debug_nb_cmd); install_element(CONFIG_NODE, &debug_nb_cmd); - install_element(CONFIG_NODE, &no_debug_nb_cmd); /* Install commands specific to the transaction-base mode. */ if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) { diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index a499d48c12..0df286511e 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -22,6 +22,7 @@ #include "log.h" #include "lib_errors.h" #include "command.h" +#include "debug.h" #include "libfrr.h" #include "version.h" #include "northbound.h" @@ -33,6 +34,8 @@ DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module") +static struct debug nb_dbg_client_confd = {0, "Northbound client: ConfD"}; + static struct thread_master *master; static struct sockaddr confd_addr; static int cdb_sub_sock, dp_ctl_sock, dp_worker_sock; @@ -139,8 +142,8 @@ static int frr_confd_hkeypath_get_list_entry(const confd_hkeypath_t *kp, /* Obtain list entry. */ if (!CHECK_FLAG(nb_node_list->flags, F_NB_NODE_KEYLESS_LIST)) { - *list_entry = nb_node_list->cbs.lookup_entry( - *list_entry, &keys); + *list_entry = nb_callback_lookup_entry( + nb_node, *list_entry, &keys); if (*list_entry == NULL) return -1; } else { @@ -545,9 +548,8 @@ static int frr_confd_init_cdb(void) continue; nb_node = snode->priv; - if (debug_northbound) - zlog_debug("%s: subscribing to '%s'", __func__, - nb_node->xpath); + DEBUGD(&nb_dbg_client_confd, "%s: subscribing to '%s'", + __func__, nb_node->xpath); spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint)); ret = cdb_subscribe2( @@ -630,7 +632,7 @@ static int frr_confd_data_get_elem(struct confd_trans_ctx *tctx, return CONFD_OK; } - data = nb_node->cbs.get_elem(xpath, list_entry); + data = nb_callback_get_elem(nb_node, xpath, list_entry); if (data) { if (data->value) { CONFD_SET_STR(&v, data->value); @@ -670,8 +672,8 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx, return CONFD_OK; } - nb_next = nb_node->cbs.get_next(parent_list_entry, - (next == -1) ? NULL : (void *)next); + nb_next = nb_callback_get_next(nb_node, parent_list_entry, + (next == -1) ? NULL : (void *)next); if (!nb_next) { /* End of the list or leaf-list. */ confd_data_reply_next_key(tctx, NULL, -1, -1); @@ -684,7 +686,8 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx, struct yang_list_keys keys; memset(&keys, 0, sizeof(keys)); - if (nb_node->cbs.get_keys(nb_next, &keys) != NB_OK) { + if (nb_callback_get_keys(nb_node, nb_next, &keys) + != NB_OK) { flog_warn(EC_LIB_NB_CB_STATE, "%s: failed to get list keys", __func__); @@ -729,7 +732,7 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx, } break; case LYS_LEAFLIST: - data = nb_node->cbs.get_elem(xpath, nb_next); + data = nb_callback_get_elem(nb_node, xpath, nb_next); if (data) { if (data->value) { CONFD_SET_STR(&v[0], data->value); @@ -798,7 +801,8 @@ static int frr_confd_data_get_object(struct confd_trans_ctx *tctx, snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath, child->name); - data = nb_node_child->cbs.get_elem(xpath_child, list_entry); + data = nb_callback_get_elem(nb_node_child, xpath_child, + list_entry); if (data) { if (data->value) CONFD_SET_STR(v, data->value); @@ -866,7 +870,8 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, object = &objects[j]; - nb_next = nb_node->cbs.get_next(parent_list_entry, nb_next); + nb_next = nb_callback_get_next(nb_node, parent_list_entry, + nb_next); if (!nb_next) /* End of the list. */ break; @@ -876,7 +881,7 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, /* Leaf-lists require special handling. */ if (nb_node->snode->nodetype == LYS_LEAFLIST) { object->v = XMALLOC(MTYPE_CONFD, sizeof(confd_value_t)); - data = nb_node->cbs.get_elem(xpath, nb_next); + data = nb_callback_get_elem(nb_node, xpath, nb_next); assert(data && data->value); CONFD_SET_STR(object->v, data->value); nvalues++; @@ -927,8 +932,8 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath, child->name); - data = nb_node_child->cbs.get_elem(xpath_child, - nb_next); + data = nb_callback_get_elem(nb_node_child, xpath_child, + nb_next); if (data) { if (data->value) CONFD_SET_STR(v, data->value); @@ -1108,7 +1113,7 @@ static int frr_confd_action_execute(struct confd_user_info *uinfo, } /* Execute callback registered for this XPath. */ - if (nb_node->cbs.rpc(xpath, input, output) != NB_OK) { + if (nb_callback_rpc(nb_node, xpath, input, output) != NB_OK) { flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s", __func__, xpath); ret = CONFD_ERR; @@ -1185,9 +1190,9 @@ static int frr_confd_subscribe_state(const struct lys_node *snode, void *arg) if (snode->parent && CHECK_FLAG(snode->parent->flags, LYS_CONFIG_R)) return YANG_ITER_CONTINUE; - if (debug_northbound) - zlog_debug("%s: providing data to '%s' (callpoint %s)", - __func__, nb_node->xpath, snode->name); + DEBUGD(&nb_dbg_client_confd, + "%s: providing data to '%s' (callpoint %s)", __func__, + nb_node->xpath, snode->name); strlcpy(data_cbs->callpoint, snode->name, sizeof(data_cbs->callpoint)); if (confd_register_data_cb(dctx, data_cbs) != CONFD_OK) @@ -1328,6 +1333,54 @@ static void frr_confd_finish_dp(void) confd_release_daemon(dctx); } +/* ------------ CLI ------------ */ + +DEFUN (debug_nb_confd, + debug_nb_confd_cmd, + "[no] debug northbound client confd", + NO_STR + DEBUG_STR + "Northbound debugging\n" + "Client\n" + "ConfD\n") +{ + uint32_t mode = DEBUG_NODE2MODE(vty->node); + bool no = strmatch(argv[0]->text, "no"); + + DEBUG_MODE_SET(&nb_dbg_client_confd, mode, !no); + + return CMD_SUCCESS; +} + +static int frr_confd_debug_config_write(struct vty *vty) +{ + if (DEBUG_MODE_CHECK(&nb_dbg_client_confd, DEBUG_MODE_CONF)) + vty_out(vty, "debug northbound client confd\n"); + + return 0; +} + +static int frr_confd_debug_set_all(uint32_t flags, bool set) +{ + DEBUG_FLAGS_SET(&nb_dbg_client_confd, flags, set); + + /* If all modes have been turned off, don't preserve options. */ + if (!DEBUG_MODE_CHECK(&nb_dbg_client_confd, DEBUG_MODE_ALL)) + DEBUG_CLEAR(&nb_dbg_client_confd); + + return 0; +} + +static void frr_confd_cli_init(void) +{ + hook_register(nb_client_debug_config_write, + frr_confd_debug_config_write); + hook_register(nb_client_debug_set_all, frr_confd_debug_set_all); + + install_element(ENABLE_NODE, &debug_nb_confd_cmd); + install_element(CONFIG_NODE, &debug_nb_confd_cmd); +} + /* ------------ Main ------------ */ static int frr_confd_calculate_snode_hash(const struct lys_node *snode, @@ -1407,6 +1460,7 @@ static int frr_confd_module_late_init(struct thread_master *tm) } hook_register(frr_fini, frr_confd_finish); + frr_confd_cli_init(); return 0; } diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index f426f52bd9..4359c39caf 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -22,6 +22,7 @@ #include "log.h" #include "lib_errors.h" #include "command.h" +#include "debug.h" #include "memory.h" #include "libfrr.h" #include "version.h" @@ -33,6 +34,8 @@ DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module") +static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"}; + static struct thread_master *master; static struct list *sysrepo_threads; static sr_session_ctx_t *session; @@ -455,7 +458,7 @@ static int frr_sr_config_rpc_cb(const char *xpath, const sr_val_t *sr_input, } /* Execute callback registered for this XPath. */ - if (nb_node->cbs.rpc(xpath, input, output) != NB_OK) { + if (nb_callback_rpc(nb_node, xpath, input, output) != NB_OK) { flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s", __func__, xpath); ret = SR_ERR_OPERATION_FAILED; @@ -701,9 +704,9 @@ static int frr_sr_subscribe_state(const struct lys_node *snode, void *arg) return YANG_ITER_CONTINUE; nb_node = snode->priv; - if (debug_northbound) - zlog_debug("%s: providing data to '%s'", __func__, - nb_node->xpath); + + DEBUGD(&nb_dbg_client_sysrepo, "%s: providing data to '%s'", __func__, + nb_node->xpath); ret = sr_dp_get_items_subscribe( session, nb_node->xpath, frr_sr_state_cb, NULL, @@ -725,9 +728,9 @@ static int frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg) return YANG_ITER_CONTINUE; nb_node = snode->priv; - if (debug_northbound) - zlog_debug("%s: providing RPC to '%s'", __func__, - nb_node->xpath); + + DEBUGD(&nb_dbg_client_sysrepo, "%s: providing RPC to '%s'", __func__, + nb_node->xpath); ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb, NULL, SR_SUBSCR_CTX_REUSE, @@ -749,9 +752,9 @@ static int frr_sr_subscribe_action(const struct lys_node *snode, void *arg) return YANG_ITER_CONTINUE; nb_node = snode->priv; - if (debug_northbound) - zlog_debug("%s: providing action to '%s'", __func__, - nb_node->xpath); + + DEBUGD(&nb_dbg_client_sysrepo, "%s: providing action to '%s'", __func__, + nb_node->xpath); ret = sr_action_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb, NULL, SR_SUBSCR_CTX_REUSE, @@ -763,6 +766,52 @@ static int frr_sr_subscribe_action(const struct lys_node *snode, void *arg) return YANG_ITER_CONTINUE; } +/* CLI commands. */ +DEFUN (debug_nb_sr, + debug_nb_sr_cmd, + "[no] debug northbound client sysrepo", + NO_STR + DEBUG_STR + "Northbound debugging\n" + "Northbound client\n" + "Sysrepo\n") +{ + uint32_t mode = DEBUG_NODE2MODE(vty->node); + bool no = strmatch(argv[0]->text, "no"); + + DEBUG_MODE_SET(&nb_dbg_client_sysrepo, mode, !no); + + return CMD_SUCCESS; +} + +static int frr_sr_debug_config_write(struct vty *vty) +{ + if (DEBUG_MODE_CHECK(&nb_dbg_client_sysrepo, DEBUG_MODE_CONF)) + vty_out(vty, "debug northbound client sysrepo\n"); + + return 0; +} + +static int frr_sr_debug_set_all(uint32_t flags, bool set) +{ + DEBUG_FLAGS_SET(&nb_dbg_client_sysrepo, flags, set); + + /* If all modes have been turned off, don't preserve options. */ + if (!DEBUG_MODE_CHECK(&nb_dbg_client_sysrepo, DEBUG_MODE_ALL)) + DEBUG_CLEAR(&nb_dbg_client_sysrepo); + + return 0; +} + +static void frr_sr_cli_init(void) +{ + hook_register(nb_client_debug_config_write, frr_sr_debug_config_write); + hook_register(nb_client_debug_set_all, frr_sr_debug_set_all); + + install_element(ENABLE_NODE, &debug_nb_sr_cmd); + install_element(CONFIG_NODE, &debug_nb_sr_cmd); +} + /* FRR's Sysrepo initialization. */ static int frr_sr_init(const char *program_name) { @@ -851,6 +900,7 @@ static int frr_sr_module_late_init(struct thread_master *tm) } hook_register(frr_fini, frr_sr_finish); + frr_sr_cli_init(); return 0; } -- 2.39.5