mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-11 18:48:14 +00:00
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 <renato@opensourcerouting.org>
This commit is contained in:
parent
e0cade1bbc
commit
9eb2c0a1dc
@ -23,6 +23,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "lib_errors.h"
|
#include "lib_errors.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "northbound.h"
|
#include "northbound.h"
|
||||||
#include "northbound_cli.h"
|
#include "northbound_cli.h"
|
||||||
@ -40,7 +41,7 @@ struct nb_config *running_config;
|
|||||||
*/
|
*/
|
||||||
static bool transaction_in_progress;
|
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);
|
struct nb_config_change *change);
|
||||||
static struct nb_transaction *nb_transaction_new(struct nb_config *config,
|
static struct nb_transaction *nb_transaction_new(struct nb_config *config,
|
||||||
struct nb_config_cbs *changes,
|
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;
|
struct nb_config_change *change = (struct nb_config_change *)cb;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nb_configuration_callback(NB_EV_VALIDATE, change);
|
ret = nb_callback_configuration(NB_EV_VALIDATE, change);
|
||||||
if (ret != NB_OK)
|
if (ret != NB_OK)
|
||||||
return NB_ERR_VALIDATION;
|
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
|
* Call the northbound configuration callback associated to a given
|
||||||
* configuration change.
|
* 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)
|
struct nb_config_change *change)
|
||||||
{
|
{
|
||||||
enum nb_operation operation = change->cb.operation;
|
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;
|
union nb_resource *resource;
|
||||||
int ret = NB_ERR;
|
int ret = NB_ERR;
|
||||||
|
|
||||||
if (debug_northbound) {
|
if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL)) {
|
||||||
const char *value = "(none)";
|
const char *value = "(none)";
|
||||||
|
|
||||||
if (dnode && !yang_snode_is_typeless_data(dnode->schema))
|
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;
|
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,
|
static struct nb_transaction *nb_transaction_new(struct nb_config *config,
|
||||||
struct nb_config_cbs *changes,
|
struct nb_config_cbs *changes,
|
||||||
enum nb_client client,
|
enum nb_client client,
|
||||||
@ -843,7 +895,7 @@ static int nb_transaction_process(enum nb_event event,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Call the appropriate callback. */
|
/* Call the appropriate callback. */
|
||||||
ret = nb_configuration_callback(event, change);
|
ret = nb_callback_configuration(event, change);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NB_EV_PREPARE:
|
case NB_EV_PREPARE:
|
||||||
if (ret != NB_OK)
|
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. */
|
/* Call the 'apply_finish' callbacks, sorted by their priorities. */
|
||||||
RB_FOREACH (cb, nb_config_cbs, &cbs) {
|
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,
|
nb_log_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH,
|
||||||
cb->xpath, NULL);
|
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))
|
if (lys_is_key((struct lys_node_leaf *)nb_node->snode, NULL))
|
||||||
return NB_OK;
|
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)
|
if (data == NULL)
|
||||||
/* Leaf of type "empty" is not present. */
|
/* Leaf of type "empty" is not present. */
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
@ -1034,7 +1086,7 @@ static int nb_oper_data_iter_container(const struct nb_node *nb_node,
|
|||||||
struct yang_data *data;
|
struct yang_data *data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
data = nb_node->cbs.get_elem(xpath, list_entry);
|
data = nb_callback_get_elem(nb_node, xpath, list_entry);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
/* Presence container is not present. */
|
/* Presence container is not present. */
|
||||||
return NB_OK;
|
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;
|
struct yang_data *data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
list_entry =
|
list_entry = nb_callback_get_next(nb_node, parent_list_entry,
|
||||||
nb_node->cbs.get_next(parent_list_entry, list_entry);
|
list_entry);
|
||||||
if (!list_entry)
|
if (!list_entry)
|
||||||
/* End of the list. */
|
/* End of the list. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
data = nb_node->cbs.get_elem(xpath, list_entry);
|
data = nb_callback_get_elem(nb_node, xpath, list_entry);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1105,15 +1157,16 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Obtain list entry. */
|
/* Obtain list entry. */
|
||||||
list_entry =
|
list_entry = nb_callback_get_next(nb_node, parent_list_entry,
|
||||||
nb_node->cbs.get_next(parent_list_entry, list_entry);
|
list_entry);
|
||||||
if (!list_entry)
|
if (!list_entry)
|
||||||
/* End of the list. */
|
/* End of the list. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) {
|
if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) {
|
||||||
/* Obtain the list entry keys. */
|
/* 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) {
|
!= NB_OK) {
|
||||||
flog_warn(EC_LIB_NB_CB_STATE,
|
flog_warn(EC_LIB_NB_CB_STATE,
|
||||||
"%s: failed to get list keys",
|
"%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. */
|
/* Find the list entry pointer. */
|
||||||
nn = dn->schema->priv;
|
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) {
|
if (list_entry == NULL) {
|
||||||
list_delete(&list_dnodes);
|
list_delete(&list_dnodes);
|
||||||
yang_dnode_free(dnode);
|
yang_dnode_free(dnode);
|
||||||
@ -1485,6 +1539,8 @@ int nb_notification_send(const char *xpath, struct list *arguments)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
DEBUGD(&nb_dbg_notif, "northbound notification: %s", xpath);
|
||||||
|
|
||||||
ret = hook_call(nb_notification_send, xpath, arguments);
|
ret = hook_call(nb_notification_send, xpath, arguments);
|
||||||
if (arguments)
|
if (arguments)
|
||||||
list_delete(&arguments);
|
list_delete(&arguments);
|
||||||
|
@ -33,6 +33,7 @@ extern "C" {
|
|||||||
|
|
||||||
/* Forward declaration(s). */
|
/* Forward declaration(s). */
|
||||||
struct vty;
|
struct vty;
|
||||||
|
struct debug;
|
||||||
|
|
||||||
/* Northbound events. */
|
/* Northbound events. */
|
||||||
enum nb_event {
|
enum nb_event {
|
||||||
@ -458,12 +459,38 @@ typedef int (*nb_oper_data_cb)(const struct lys_node *snode,
|
|||||||
/* Iterate over direct child nodes only. */
|
/* Iterate over direct child nodes only. */
|
||||||
#define NB_OPER_DATA_ITER_NORECURSE 0x0001
|
#define NB_OPER_DATA_ITER_NORECURSE 0x0001
|
||||||
|
|
||||||
|
/* 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_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;
|
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.
|
* Create a northbound node for all YANG schema nodes.
|
||||||
*/
|
*/
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "termtable.h"
|
#include "termtable.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "yang_translator.h"
|
#include "yang_translator.h"
|
||||||
#include "northbound.h"
|
#include "northbound.h"
|
||||||
#include "northbound_cli.h"
|
#include "northbound_cli.h"
|
||||||
@ -34,7 +35,12 @@
|
|||||||
#include "lib/northbound_cli_clippy.c"
|
#include "lib/northbound_cli_clippy.c"
|
||||||
#endif
|
#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;
|
struct nb_config *vty_shared_candidate_config;
|
||||||
static struct thread_master *master;
|
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;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nb_node->cbs.rpc(xpath, input, output);
|
ret = nb_callback_rpc(nb_node, xpath, input, output);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case NB_OK:
|
case NB_OK:
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@ -1540,36 +1546,90 @@ DEFPY (rollback_config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Debug CLI commands. */
|
/* Debug CLI commands. */
|
||||||
DEFUN (debug_nb,
|
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)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < array_size(nb_debugs); i++) {
|
||||||
|
DEBUG_FLAGS_SET(nb_debugs[i], flags, set);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (debug_nb,
|
||||||
debug_nb_cmd,
|
debug_nb_cmd,
|
||||||
"debug northbound",
|
"[no] debug northbound\
|
||||||
|
[<\
|
||||||
|
callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\
|
||||||
|
|notifications$notifications\
|
||||||
|
|events$events\
|
||||||
|
>]",
|
||||||
|
NO_STR
|
||||||
DEBUG_STR
|
DEBUG_STR
|
||||||
"Northbound Debugging\n")
|
"Northbound debugging\n"
|
||||||
|
"Callbacks\n"
|
||||||
|
"Configuration\n"
|
||||||
|
"State\n"
|
||||||
|
"RPC\n"
|
||||||
|
"Notifications\n"
|
||||||
|
"Events\n")
|
||||||
{
|
{
|
||||||
debug_northbound = 1;
|
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;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (no_debug_nb,
|
DEFINE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
|
||||||
no_debug_nb_cmd,
|
|
||||||
"no debug northbound",
|
|
||||||
NO_STR DEBUG_STR
|
|
||||||
"Northbound Debugging\n")
|
|
||||||
{
|
|
||||||
debug_northbound = 0;
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nb_debug_config_write(struct vty *vty)
|
static int nb_debug_config_write(struct vty *vty)
|
||||||
{
|
{
|
||||||
if (debug_northbound)
|
for (unsigned int i = 0; i < array_size(nb_debugs); i++)
|
||||||
vty_out(vty, "debug northbound\n");
|
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;
|
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};
|
static struct cmd_node nb_debug_node = {NORTHBOUND_DEBUG_NODE, "", 1};
|
||||||
|
|
||||||
void nb_cli_install_default(int node)
|
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);
|
vty_shared_candidate_config = nb_config_new(NULL);
|
||||||
|
|
||||||
/* Install debug commands */
|
/* Install debug commands */
|
||||||
|
debug_init(&nb_dbg_cbs);
|
||||||
install_node(&nb_debug_node, nb_debug_config_write);
|
install_node(&nb_debug_node, nb_debug_config_write);
|
||||||
install_element(ENABLE_NODE, &debug_nb_cmd);
|
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, &debug_nb_cmd);
|
||||||
install_element(CONFIG_NODE, &no_debug_nb_cmd);
|
|
||||||
|
|
||||||
/* Install commands specific to the transaction-base mode. */
|
/* Install commands specific to the transaction-base mode. */
|
||||||
if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
|
if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "lib_errors.h"
|
#include "lib_errors.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "libfrr.h"
|
#include "libfrr.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "northbound.h"
|
#include "northbound.h"
|
||||||
@ -33,6 +34,8 @@
|
|||||||
|
|
||||||
DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module")
|
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 thread_master *master;
|
||||||
static struct sockaddr confd_addr;
|
static struct sockaddr confd_addr;
|
||||||
static int cdb_sub_sock, dp_ctl_sock, dp_worker_sock;
|
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. */
|
/* Obtain list entry. */
|
||||||
if (!CHECK_FLAG(nb_node_list->flags, F_NB_NODE_KEYLESS_LIST)) {
|
if (!CHECK_FLAG(nb_node_list->flags, F_NB_NODE_KEYLESS_LIST)) {
|
||||||
*list_entry = nb_node_list->cbs.lookup_entry(
|
*list_entry = nb_callback_lookup_entry(
|
||||||
*list_entry, &keys);
|
nb_node, *list_entry, &keys);
|
||||||
if (*list_entry == NULL)
|
if (*list_entry == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
@ -545,9 +548,8 @@ static int frr_confd_init_cdb(void)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
nb_node = snode->priv;
|
nb_node = snode->priv;
|
||||||
if (debug_northbound)
|
DEBUGD(&nb_dbg_client_confd, "%s: subscribing to '%s'",
|
||||||
zlog_debug("%s: subscribing to '%s'", __func__,
|
__func__, nb_node->xpath);
|
||||||
nb_node->xpath);
|
|
||||||
|
|
||||||
spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint));
|
spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint));
|
||||||
ret = cdb_subscribe2(
|
ret = cdb_subscribe2(
|
||||||
@ -630,7 +632,7 @@ static int frr_confd_data_get_elem(struct confd_trans_ctx *tctx,
|
|||||||
return CONFD_OK;
|
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) {
|
||||||
if (data->value) {
|
if (data->value) {
|
||||||
CONFD_SET_STR(&v, 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;
|
return CONFD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nb_next = nb_node->cbs.get_next(parent_list_entry,
|
nb_next = nb_callback_get_next(nb_node, parent_list_entry,
|
||||||
(next == -1) ? NULL : (void *)next);
|
(next == -1) ? NULL : (void *)next);
|
||||||
if (!nb_next) {
|
if (!nb_next) {
|
||||||
/* End of the list or leaf-list. */
|
/* End of the list or leaf-list. */
|
||||||
confd_data_reply_next_key(tctx, NULL, -1, -1);
|
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;
|
struct yang_list_keys keys;
|
||||||
|
|
||||||
memset(&keys, 0, sizeof(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,
|
flog_warn(EC_LIB_NB_CB_STATE,
|
||||||
"%s: failed to get list keys",
|
"%s: failed to get list keys",
|
||||||
__func__);
|
__func__);
|
||||||
@ -729,7 +732,7 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LYS_LEAFLIST:
|
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) {
|
||||||
if (data->value) {
|
if (data->value) {
|
||||||
CONFD_SET_STR(&v[0], 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,
|
snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath,
|
||||||
child->name);
|
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) {
|
||||||
if (data->value)
|
if (data->value)
|
||||||
CONFD_SET_STR(v, 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];
|
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)
|
if (!nb_next)
|
||||||
/* End of the list. */
|
/* End of the list. */
|
||||||
break;
|
break;
|
||||||
@ -876,7 +881,7 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx,
|
|||||||
/* Leaf-lists require special handling. */
|
/* Leaf-lists require special handling. */
|
||||||
if (nb_node->snode->nodetype == LYS_LEAFLIST) {
|
if (nb_node->snode->nodetype == LYS_LEAFLIST) {
|
||||||
object->v = XMALLOC(MTYPE_CONFD, sizeof(confd_value_t));
|
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);
|
assert(data && data->value);
|
||||||
CONFD_SET_STR(object->v, data->value);
|
CONFD_SET_STR(object->v, data->value);
|
||||||
nvalues++;
|
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",
|
snprintf(xpath_child, sizeof(xpath_child), "%s/%s",
|
||||||
xpath, child->name);
|
xpath, child->name);
|
||||||
data = nb_node_child->cbs.get_elem(xpath_child,
|
data = nb_callback_get_elem(nb_node_child, xpath_child,
|
||||||
nb_next);
|
nb_next);
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data->value)
|
if (data->value)
|
||||||
CONFD_SET_STR(v, 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. */
|
/* 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",
|
flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s",
|
||||||
__func__, xpath);
|
__func__, xpath);
|
||||||
ret = CONFD_ERR;
|
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))
|
if (snode->parent && CHECK_FLAG(snode->parent->flags, LYS_CONFIG_R))
|
||||||
return YANG_ITER_CONTINUE;
|
return YANG_ITER_CONTINUE;
|
||||||
|
|
||||||
if (debug_northbound)
|
DEBUGD(&nb_dbg_client_confd,
|
||||||
zlog_debug("%s: providing data to '%s' (callpoint %s)",
|
"%s: providing data to '%s' (callpoint %s)", __func__,
|
||||||
__func__, nb_node->xpath, snode->name);
|
nb_node->xpath, snode->name);
|
||||||
|
|
||||||
strlcpy(data_cbs->callpoint, snode->name, sizeof(data_cbs->callpoint));
|
strlcpy(data_cbs->callpoint, snode->name, sizeof(data_cbs->callpoint));
|
||||||
if (confd_register_data_cb(dctx, data_cbs) != CONFD_OK)
|
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);
|
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 ------------ */
|
/* ------------ Main ------------ */
|
||||||
|
|
||||||
static int frr_confd_calculate_snode_hash(const struct lys_node *snode,
|
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);
|
hook_register(frr_fini, frr_confd_finish);
|
||||||
|
frr_confd_cli_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "lib_errors.h"
|
#include "lib_errors.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "libfrr.h"
|
#include "libfrr.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -33,6 +34,8 @@
|
|||||||
|
|
||||||
DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module")
|
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 thread_master *master;
|
||||||
static struct list *sysrepo_threads;
|
static struct list *sysrepo_threads;
|
||||||
static sr_session_ctx_t *session;
|
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. */
|
/* 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",
|
flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s",
|
||||||
__func__, xpath);
|
__func__, xpath);
|
||||||
ret = SR_ERR_OPERATION_FAILED;
|
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;
|
return YANG_ITER_CONTINUE;
|
||||||
|
|
||||||
nb_node = snode->priv;
|
nb_node = snode->priv;
|
||||||
if (debug_northbound)
|
|
||||||
zlog_debug("%s: providing data to '%s'", __func__,
|
DEBUGD(&nb_dbg_client_sysrepo, "%s: providing data to '%s'", __func__,
|
||||||
nb_node->xpath);
|
nb_node->xpath);
|
||||||
|
|
||||||
ret = sr_dp_get_items_subscribe(
|
ret = sr_dp_get_items_subscribe(
|
||||||
session, nb_node->xpath, frr_sr_state_cb, NULL,
|
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;
|
return YANG_ITER_CONTINUE;
|
||||||
|
|
||||||
nb_node = snode->priv;
|
nb_node = snode->priv;
|
||||||
if (debug_northbound)
|
|
||||||
zlog_debug("%s: providing RPC to '%s'", __func__,
|
DEBUGD(&nb_dbg_client_sysrepo, "%s: providing RPC to '%s'", __func__,
|
||||||
nb_node->xpath);
|
nb_node->xpath);
|
||||||
|
|
||||||
ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
|
ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
|
||||||
NULL, SR_SUBSCR_CTX_REUSE,
|
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;
|
return YANG_ITER_CONTINUE;
|
||||||
|
|
||||||
nb_node = snode->priv;
|
nb_node = snode->priv;
|
||||||
if (debug_northbound)
|
|
||||||
zlog_debug("%s: providing action to '%s'", __func__,
|
DEBUGD(&nb_dbg_client_sysrepo, "%s: providing action to '%s'", __func__,
|
||||||
nb_node->xpath);
|
nb_node->xpath);
|
||||||
|
|
||||||
ret = sr_action_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
|
ret = sr_action_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
|
||||||
NULL, SR_SUBSCR_CTX_REUSE,
|
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;
|
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. */
|
/* FRR's Sysrepo initialization. */
|
||||||
static int frr_sr_init(const char *program_name)
|
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);
|
hook_register(frr_fini, frr_sr_finish);
|
||||||
|
frr_sr_cli_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user