summaryrefslogtreecommitdiff
path: root/lib/northbound.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/northbound.c')
-rw-r--r--lib/northbound.c202
1 files changed, 140 insertions, 62 deletions
diff --git a/lib/northbound.c b/lib/northbound.c
index 9deb9c6cce..5e031ac2ce 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -22,6 +22,7 @@
#include "libfrr.h"
#include "log.h"
#include "lib_errors.h"
+#include "hash.h"
#include "command.h"
#include "debug.h"
#include "db.h"
@@ -31,10 +32,14 @@
DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node")
DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration")
+DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry")
/* Running configuration - shouldn't be modified directly. */
struct nb_config *running_config;
+/* Hash table of user pointers associated with configuration entries. */
+static struct hash *running_config_entries;
+
/*
* Global lock used to prevent multiple configuration transactions from
* happening concurrently.
@@ -454,13 +459,6 @@ int nb_candidate_edit(struct nb_config *candidate,
struct lyd_node *dnode;
char xpath_edit[XPATH_MAXLEN];
- if (!nb_operation_is_valid(operation, nb_node->snode)) {
- flog_warn(EC_LIB_NB_CANDIDATE_EDIT_ERROR,
- "%s: %s operation not valid for %s", __func__,
- nb_operation_name(operation), xpath);
- return NB_ERR;
- }
-
/* Use special notation for leaf-lists (RFC 6020, section 9.13.5). */
if (nb_node->snode->nodetype == LYS_LEAFLIST)
snprintf(xpath_edit, sizeof(xpath_edit), "%s[.='%s']", xpath,
@@ -535,38 +533,6 @@ int nb_candidate_update(struct nb_config *candidate)
}
/*
- * The northbound configuration callbacks use the 'priv' pointer present in the
- * libyang lyd_node structure to store pointers to FRR internal variables
- * associated to YANG lists and presence containers. Before commiting a
- * candidate configuration, we must restore the 'priv' pointers stored in the
- * running configuration since they might be lost while editing the candidate.
- */
-static void nb_candidate_restore_priv_pointers(struct nb_config *candidate)
-{
- struct lyd_node *root, *next, *dnode_iter;
-
- LY_TREE_FOR (running_config->dnode, root) {
- LY_TREE_DFS_BEGIN (root, next, dnode_iter) {
- struct lyd_node *dnode_candidate;
- char xpath[XPATH_MAXLEN];
-
- if (!dnode_iter->priv)
- goto next;
-
- yang_dnode_get_path(dnode_iter, xpath, sizeof(xpath));
- dnode_candidate =
- yang_dnode_get(candidate->dnode, xpath);
- if (dnode_candidate)
- yang_dnode_set_entry(dnode_candidate,
- dnode_iter->priv);
-
- next:
- LY_TREE_DFS_END(root, next, dnode_iter);
- }
- }
-}
-
-/*
* Perform YANG syntactic and semantic validation.
*
* WARNING: lyd_validate() can change the configuration as part of the
@@ -588,7 +554,6 @@ static int nb_candidate_validate_changes(struct nb_config *candidate,
{
struct nb_config_cb *cb;
- nb_candidate_restore_priv_pointers(candidate);
RB_FOREACH (cb, nb_config_cbs, changes) {
struct nb_config_change *change = (struct nb_config_change *)cb;
int ret;
@@ -753,40 +718,44 @@ static int nb_callback_configuration(const enum nb_event event,
ret = (*nb_node->cbs.move)(event, dnode);
break;
default:
- break;
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unknown operation (%u) [xpath %s]", __func__,
+ operation, xpath);
+ exit(1);
}
if (ret != NB_OK) {
- enum lib_log_refs ref = 0;
+ int priority;
+ enum lib_log_refs ref;
switch (event) {
case NB_EV_VALIDATE:
+ priority = LOG_WARNING;
ref = EC_LIB_NB_CB_CONFIG_VALIDATE;
break;
case NB_EV_PREPARE:
+ priority = LOG_WARNING;
ref = EC_LIB_NB_CB_CONFIG_PREPARE;
break;
case NB_EV_ABORT:
+ priority = LOG_WARNING;
ref = EC_LIB_NB_CB_CONFIG_ABORT;
break;
case NB_EV_APPLY:
+ priority = LOG_ERR;
ref = EC_LIB_NB_CB_CONFIG_APPLY;
break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unknown event (%u) [xpath %s]",
+ __func__, event, xpath);
+ exit(1);
}
- if (event == NB_EV_VALIDATE || event == NB_EV_PREPARE)
- flog_warn(
- ref,
- "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
- __func__, nb_err_name(ret),
- nb_event_name(event),
- nb_operation_name(operation), xpath);
- else
- flog_err(
- ref,
- "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
- __func__, nb_err_name(ret),
- nb_event_name(event),
- nb_operation_name(operation), xpath);
+
+ flog(priority, ref,
+ "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
+ __func__, nb_err_name(ret), nb_event_name(event),
+ nb_operation_name(operation), xpath);
}
return ret;
@@ -1548,6 +1517,116 @@ int nb_notification_send(const char *xpath, struct list *arguments)
return ret;
}
+/* Running configuration user pointers management. */
+struct nb_config_entry {
+ char xpath[XPATH_MAXLEN];
+ void *entry;
+};
+
+static bool running_config_entry_cmp(const void *value1, const void *value2)
+{
+ const struct nb_config_entry *c1 = value1;
+ const struct nb_config_entry *c2 = value2;
+
+ return strmatch(c1->xpath, c2->xpath);
+}
+
+static unsigned int running_config_entry_key_make(void *value)
+{
+ return string_hash_make(value);
+}
+
+static void *running_config_entry_alloc(void *p)
+{
+ struct nb_config_entry *new, *key = p;
+
+ new = XCALLOC(MTYPE_NB_CONFIG_ENTRY, sizeof(*new));
+ strlcpy(new->xpath, key->xpath, sizeof(new->xpath));
+
+ return new;
+}
+
+static void running_config_entry_free(void *arg)
+{
+ XFREE(MTYPE_NB_CONFIG_ENTRY, arg);
+}
+
+void nb_running_set_entry(const struct lyd_node *dnode, void *entry)
+{
+ struct nb_config_entry *config, s;
+
+ yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+ config = hash_get(running_config_entries, &s,
+ running_config_entry_alloc);
+ config->entry = entry;
+}
+
+static void *nb_running_unset_entry_helper(const struct lyd_node *dnode)
+{
+ struct nb_config_entry *config, s;
+ struct lyd_node *child;
+ void *entry = NULL;
+
+ yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+ config = hash_release(running_config_entries, &s);
+ if (config) {
+ entry = config->entry;
+ running_config_entry_free(config);
+ }
+
+ /* Unset user pointers from the child nodes. */
+ if (CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER)) {
+ LY_TREE_FOR (dnode->child, child) {
+ (void)nb_running_unset_entry_helper(child);
+ }
+ }
+
+ return entry;
+}
+
+void *nb_running_unset_entry(const struct lyd_node *dnode)
+{
+ void *entry;
+
+ entry = nb_running_unset_entry_helper(dnode);
+ assert(entry);
+
+ return entry;
+}
+
+void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
+ bool abort_if_not_found)
+{
+ const struct lyd_node *orig_dnode = dnode;
+ char xpath_buf[XPATH_MAXLEN];
+
+ assert(dnode || xpath);
+
+ if (!dnode)
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+
+ while (dnode) {
+ struct nb_config_entry *config, s;
+
+ yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+ config = hash_lookup(running_config_entries, &s);
+ if (config)
+ return config->entry;
+
+ dnode = dnode->parent;
+ }
+
+ if (!abort_if_not_found)
+ return NULL;
+
+ yang_dnode_get_path(orig_dnode, xpath_buf, sizeof(xpath_buf));
+ flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
+ "%s: failed to find entry [xpath %s]", __func__, xpath_buf);
+ zlog_backtrace(LOG_ERR);
+ abort();
+}
+
+/* Logging functions. */
const char *nb_event_name(enum nb_event event)
{
switch (event) {
@@ -1677,14 +1756,11 @@ void nb_init(struct thread_master *tm,
exit(1);
}
- /* Initialize the northbound database (used for the rollback log). */
- if (nb_db_init() != NB_OK)
- flog_warn(EC_LIB_NB_DATABASE,
- "%s: failed to initialize northbound database",
- __func__);
-
/* Create an empty running configuration. */
running_config = nb_config_new(NULL);
+ running_config_entries = hash_create(running_config_entry_key_make,
+ running_config_entry_cmp,
+ "Running Configuration Entries");
/* Initialize the northbound CLI. */
nb_cli_init(tm);
@@ -1699,5 +1775,7 @@ void nb_terminate(void)
nb_nodes_delete();
/* Delete the running configuration. */
+ hash_clean(running_config_entries, running_config_entry_free);
+ hash_free(running_config_entries);
nb_config_free(running_config);
}