]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: add fine-grained debugging in the northbound
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 12 Apr 2019 21:00:26 +0000 (18:00 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Mon, 15 Apr 2019 18:59:38 +0000 (15:59 -0300)
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 <renato@opensourcerouting.org>
lib/northbound.c
lib/northbound.h
lib/northbound_cli.c
lib/northbound_confd.c
lib/northbound_sysrepo.c

index edf7e0eca6893add20ad0dbbd5927b23d78500ee..9deb9c6cceb28a9dc908f56f6bdec85b6c0d3d4b 100644 (file)
@@ -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);
index bb6b62af7d4197084897993e7460c408d272967a..bfa28b3f65505071686977ffcd3958f85096f8cf 100644 (file)
@@ -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.
  */
index 917b04810502f030ba8cab81d3e8ccc7ee3c6038..48faa7595aa04709730050e7e42487c6a27193b7 100644 (file)
@@ -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"
 #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) {
index a499d48c12ad4889ada85ed352c5df0425e0a205..0df286511ecea668bad11fdb39a6fc590a75ea9a 100644 (file)
@@ -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;
 }
index f426f52bd99ab89b78fa7bee745fec5314598868..4359c39cafce83cc1f76b09fa8e42d14cbb18970 100644 (file)
@@ -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;
 }