DEFUN_NOSH(debug_all, debug_all_cmd, "[no] debug all",
NO_STR DEBUG_STR "Toggle all debugging output\n")
{
- bool set = strmatch(argv[0]->text, "no");
+ bool set = !strmatch(argv[0]->text, "no");
uint32_t mode = DEBUG_NODE2MODE(vty->node);
if (callbacks->debug_set_all)
#include "log.h"
#include "lib_errors.h"
#include "command.h"
+#include "debug.h"
#include "db.h"
#include "northbound.h"
#include "northbound_cli.h"
*/
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,
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;
}
* 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;
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))
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,
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)
/* 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);
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;
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;
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;
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",
/* 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);
{
int ret;
+ DEBUGD(&nb_dbg_notif, "northbound notification: %s", xpath);
+
ret = hook_call(nb_notification_send, xpath, arguments);
if (arguments)
list_delete(&arguments);
/* Forward declaration(s). */
struct vty;
+struct debug;
/* Northbound events. */
enum nb_event {
/* 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.
*/
#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;
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;
}
/* 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)
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) {
#include "log.h"
#include "lib_errors.h"
#include "command.h"
+#include "debug.h"
#include "libfrr.h"
#include "version.h"
#include "northbound.h"
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;
/* 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 {
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(
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);
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);
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__);
}
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);
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);
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;
/* 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++;
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);
}
/* 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;
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)
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,
}
hook_register(frr_fini, frr_confd_finish);
+ frr_confd_cli_init();
return 0;
}
#include "log.h"
#include "lib_errors.h"
#include "command.h"
+#include "debug.h"
#include "memory.h"
#include "libfrr.h"
#include "version.h"
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;
}
/* 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;
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,
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,
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,
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)
{
}
hook_register(frr_fini, frr_sr_finish);
+ frr_sr_cli_init();
return 0;
}