]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/northbound.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / lib / northbound.c
index b755264be19526087fc730fe1d1ff7ffb623d1e0..775f6ff92f9494352f3dbe3c97f374887b2df392 100644 (file)
@@ -61,7 +61,7 @@ static int nb_callback_configuration(struct nb_context *context,
                                     struct nb_config_change *change,
                                     char *errmsg, size_t errmsg_len);
 static struct nb_transaction *
-nb_transaction_new(struct nb_context *context, struct nb_config *config,
+nb_transaction_new(struct nb_context context, struct nb_config *config,
                   struct nb_config_cbs *changes, const char *comment,
                   char *errmsg, size_t errmsg_len);
 static void nb_transaction_free(struct nb_transaction *transaction);
@@ -93,7 +93,9 @@ static int nb_node_new_cb(const struct lysc_node *snode, void *arg)
 {
        struct nb_node *nb_node;
        struct lysc_node *sparent, *sparent_list;
+       struct frr_yang_module_info *module;
 
+       module = (struct frr_yang_module_info *)arg;
        nb_node = XCALLOC(MTYPE_NB_NODE, sizeof(*nb_node));
        yang_snode_get_path(snode, YANG_PATH_DATA, nb_node->xpath,
                            sizeof(nb_node->xpath));
@@ -128,6 +130,9 @@ static int nb_node_new_cb(const struct lysc_node *snode, void *arg)
        assert(snode->priv == NULL);
        ((struct lysc_node *)snode)->priv = nb_node;
 
+       if (module && module->ignore_cbs)
+               SET_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS);
+
        return YANG_ITER_CONTINUE;
 }
 
@@ -162,7 +167,7 @@ struct nb_node *nb_node_find(const char *path)
         * Use libyang to find the schema node associated to the path and get
         * the northbound node from there (snode private pointer).
         */
-       snode = lys_find_path(ly_native_ctx, NULL, path, 0);
+       snode = yang_find_snode(ly_native_ctx, path, 0);
        if (!snode)
                return NULL;
 
@@ -230,6 +235,9 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node)
 {
        unsigned int error = 0;
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return error;
+
        error += nb_node_validate_cb(nb_node, NB_OP_CREATE,
                                     !!nb_node->cbs.create, false);
        error += nb_node_validate_cb(nb_node, NB_OP_MODIFY,
@@ -297,6 +305,8 @@ struct nb_config *nb_config_new(struct lyd_node *dnode)
                config->dnode = yang_dnode_new(ly_native_ctx, true);
        config->version = 0;
 
+       RB_INIT(nb_config_cbs, &config->cfg_chgs);
+
        return config;
 }
 
@@ -304,6 +314,7 @@ void nb_config_free(struct nb_config *config)
 {
        if (config->dnode)
                yang_dnode_free(config->dnode);
+       nb_config_diff_del_changes(&config->cfg_chgs);
        XFREE(MTYPE_NB_CONFIG, config);
 }
 
@@ -315,6 +326,8 @@ struct nb_config *nb_config_dup(const struct nb_config *config)
        dup->dnode = yang_dnode_dup(config->dnode);
        dup->version = config->version;
 
+       RB_INIT(nb_config_cbs, &dup->cfg_chgs);
+
        return dup;
 }
 
@@ -405,7 +418,7 @@ static void nb_config_diff_add_change(struct nb_config_cbs *changes,
        RB_INSERT(nb_config_cbs, changes, &change->cb);
 }
 
-static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
+void nb_config_diff_del_changes(struct nb_config_cbs *changes)
 {
        while (!RB_EMPTY(nb_config_cbs, changes)) {
                struct nb_config_change *change;
@@ -422,8 +435,8 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
  * configurations. Given a new subtree, calculate all new YANG data nodes,
  * excluding default leafs and leaf-lists. This is a recursive function.
  */
-static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
-                                  struct nb_config_cbs *changes)
+void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
+                           struct nb_config_cbs *changes)
 {
        enum nb_operation operation;
        struct lyd_node *child;
@@ -525,10 +538,16 @@ static inline void nb_config_diff_dnode_log(const char *context,
 }
 #endif
 
-/* Calculate the delta between two different configurations. */
-static void nb_config_diff(const struct nb_config *config1,
-                          const struct nb_config *config2,
-                          struct nb_config_cbs *changes)
+/*
+ * Calculate the delta between two different configurations.
+ *
+ * NOTE: 'config1' is the reference DB, while 'config2' is
+ * the DB being compared against 'config1'. Typically 'config1'
+ * should be the Running DB and 'config2' is the Candidate DB.
+ */
+void nb_config_diff(const struct nb_config *config1,
+                   const struct nb_config *config2,
+                   struct nb_config_cbs *changes)
 {
        struct lyd_node *diff = NULL;
        const struct lyd_node *root, *dnode;
@@ -734,6 +753,169 @@ int nb_candidate_edit(struct nb_config *candidate,
        return NB_OK;
 }
 
+static void nb_update_candidate_changes(struct nb_config *candidate,
+                                       struct nb_cfg_change *change,
+                                       uint32_t *seq)
+{
+       enum nb_operation oper = change->operation;
+       char *xpath = change->xpath;
+       struct lyd_node *root = NULL;
+       struct lyd_node *dnode;
+       struct nb_config_cbs *cfg_chgs = &candidate->cfg_chgs;
+       int op;
+
+       switch (oper) {
+       case NB_OP_CREATE:
+       case NB_OP_MODIFY:
+               root = yang_dnode_get(candidate->dnode, xpath);
+               break;
+       case NB_OP_DESTROY:
+               root = yang_dnode_get(running_config->dnode, xpath);
+               /* code */
+               break;
+       case NB_OP_MOVE:
+       case NB_OP_PRE_VALIDATE:
+       case NB_OP_APPLY_FINISH:
+       case NB_OP_GET_ELEM:
+       case NB_OP_GET_NEXT:
+       case NB_OP_GET_KEYS:
+       case NB_OP_LOOKUP_ENTRY:
+       case NB_OP_RPC:
+               break;
+       default:
+               assert(!"non-enum value, invalid");
+       }
+
+       if (!root)
+               return;
+
+       LYD_TREE_DFS_BEGIN (root, dnode) {
+               op = nb_lyd_diff_get_op(dnode);
+               switch (op) {
+               case 'c':
+                       nb_config_diff_created(dnode, seq, cfg_chgs);
+                       LYD_TREE_DFS_continue = 1;
+                       break;
+               case 'd':
+                       nb_config_diff_deleted(dnode, seq, cfg_chgs);
+                       LYD_TREE_DFS_continue = 1;
+                       break;
+               case 'r':
+                       nb_config_diff_add_change(cfg_chgs, NB_OP_MODIFY, seq,
+                                                 dnode);
+                       break;
+               default:
+                       break;
+               }
+               LYD_TREE_DFS_END(root, dnode);
+       }
+}
+
+static bool nb_is_operation_allowed(struct nb_node *nb_node,
+                                   struct nb_cfg_change *change)
+{
+       enum nb_operation oper = change->operation;
+
+       if (lysc_is_key(nb_node->snode)) {
+               if (oper == NB_OP_MODIFY || oper == NB_OP_DESTROY)
+                       return false;
+       }
+       return true;
+}
+
+void nb_candidate_edit_config_changes(
+       struct nb_config *candidate_config, struct nb_cfg_change cfg_changes[],
+       size_t num_cfg_changes, const char *xpath_base, const char *curr_xpath,
+       int xpath_index, char *err_buf, int err_bufsize, bool *error)
+{
+       uint32_t seq = 0;
+
+       if (error)
+               *error = false;
+
+       if (xpath_base == NULL)
+               xpath_base = "";
+
+       /* Edit candidate configuration. */
+       for (size_t i = 0; i < num_cfg_changes; i++) {
+               struct nb_cfg_change *change = &cfg_changes[i];
+               struct nb_node *nb_node;
+               char xpath[XPATH_MAXLEN];
+               struct yang_data *data;
+               int ret;
+
+               /* Handle relative XPaths. */
+               memset(xpath, 0, sizeof(xpath));
+               if (xpath_index > 0 &&
+                   (xpath_base[0] == '.' || change->xpath[0] == '.'))
+                       strlcpy(xpath, curr_xpath, sizeof(xpath));
+               if (xpath_base[0]) {
+                       if (xpath_base[0] == '.')
+                               strlcat(xpath, xpath_base + 1, sizeof(xpath));
+                       else
+                               strlcat(xpath, xpath_base, sizeof(xpath));
+               }
+               if (change->xpath[0] == '.')
+                       strlcat(xpath, change->xpath + 1, sizeof(xpath));
+               else
+                       strlcpy(xpath, change->xpath, sizeof(xpath));
+
+               /* Find the northbound node associated to the data path. */
+               nb_node = nb_node_find(xpath);
+               if (!nb_node) {
+                       flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
+                                 "%s: unknown data path: %s", __func__, xpath);
+                       if (error)
+                               *error = true;
+                       continue;
+               }
+               /* Find if the node to be edited is not a key node */
+               if (!nb_is_operation_allowed(nb_node, change)) {
+                       zlog_err(" Xpath %s points to key node", xpath);
+                       if (error)
+                               *error = true;
+                       break;
+               }
+
+               /* If the value is not set, get the default if it exists. */
+               if (change->value == NULL)
+                       change->value = yang_snode_get_default(nb_node->snode);
+               data = yang_data_new(xpath, change->value);
+
+               /*
+                * Ignore "not found" errors when editing the candidate
+                * configuration.
+                */
+               ret = nb_candidate_edit(candidate_config, nb_node,
+                                       change->operation, xpath, NULL, data);
+               yang_data_free(data);
+               if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
+                       flog_warn(
+                               EC_LIB_NB_CANDIDATE_EDIT_ERROR,
+                               "%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
+                               __func__, nb_operation_name(change->operation),
+                               xpath);
+                       if (error)
+                               *error = true;
+                       continue;
+               }
+               nb_update_candidate_changes(candidate_config, change, &seq);
+       }
+
+       if (error && *error) {
+               char buf[BUFSIZ];
+
+               /*
+                * Failure to edit the candidate configuration should never
+                * happen in practice, unless there's a bug in the code. When
+                * that happens, log the error but otherwise ignore it.
+                */
+               snprintf(err_buf, err_bufsize,
+                        "%% Failed to edit configuration.\n\n%s",
+                        yang_print_errors(ly_native_ctx, buf, sizeof(buf)));
+       }
+}
+
 bool nb_candidate_needs_update(const struct nb_config *candidate)
 {
        if (candidate->version < running_config->version)
@@ -761,12 +943,13 @@ int nb_candidate_update(struct nb_config *candidate)
  * WARNING: lyd_validate() can change the configuration as part of the
  * validation process.
  */
-static int nb_candidate_validate_yang(struct nb_config *candidate, char *errmsg,
-                                     size_t errmsg_len)
+int nb_candidate_validate_yang(struct nb_config *candidate, bool no_state,
+                              char *errmsg, size_t errmsg_len)
 {
        if (lyd_validate_all(&candidate->dnode, ly_native_ctx,
-                            LYD_VALIDATE_NO_STATE, NULL)
-           != 0) {
+                            no_state ? LYD_VALIDATE_NO_STATE
+                                     : LYD_VALIDATE_PRESENT,
+                            NULL) != 0) {
                yang_print_errors(ly_native_ctx, errmsg, errmsg_len);
                return NB_ERR_VALIDATION;
        }
@@ -775,10 +958,10 @@ static int nb_candidate_validate_yang(struct nb_config *candidate, char *errmsg,
 }
 
 /* Perform code-level validation using the northbound callbacks. */
-static int nb_candidate_validate_code(struct nb_context *context,
-                                     struct nb_config *candidate,
-                                     struct nb_config_cbs *changes,
-                                     char *errmsg, size_t errmsg_len)
+int nb_candidate_validate_code(struct nb_context *context,
+                              struct nb_config *candidate,
+                              struct nb_config_cbs *changes, char *errmsg,
+                              size_t errmsg_len)
 {
        struct nb_config_cb *cb;
        struct lyd_node *root, *child;
@@ -816,6 +999,21 @@ static int nb_candidate_validate_code(struct nb_context *context,
        return NB_OK;
 }
 
+int nb_candidate_diff_and_validate_yang(struct nb_context *context,
+                                       struct nb_config *candidate,
+                                       struct nb_config_cbs *changes,
+                                       char *errmsg, size_t errmsg_len)
+{
+       if (nb_candidate_validate_yang(candidate, true, errmsg,
+                                      sizeof(errmsg_len)) != NB_OK)
+               return NB_ERR_VALIDATION;
+
+       RB_INIT(nb_config_cbs, changes);
+       nb_config_diff(running_config, candidate, changes);
+
+       return NB_OK;
+}
+
 int nb_candidate_validate(struct nb_context *context,
                          struct nb_config *candidate, char *errmsg,
                          size_t errmsg_len)
@@ -823,11 +1021,11 @@ int nb_candidate_validate(struct nb_context *context,
        struct nb_config_cbs changes;
        int ret;
 
-       if (nb_candidate_validate_yang(candidate, errmsg, errmsg_len) != NB_OK)
-               return NB_ERR_VALIDATION;
+       ret = nb_candidate_diff_and_validate_yang(context, candidate, &changes,
+                                                 errmsg, errmsg_len);
+       if (ret != NB_OK)
+               return ret;
 
-       RB_INIT(nb_config_cbs, &changes);
-       nb_config_diff(running_config, candidate, &changes);
        ret = nb_candidate_validate_code(context, candidate, &changes, errmsg,
                                         errmsg_len);
        nb_config_diff_del_changes(&changes);
@@ -835,16 +1033,18 @@ int nb_candidate_validate(struct nb_context *context,
        return ret;
 }
 
-int nb_candidate_commit_prepare(struct nb_context *context,
+int nb_candidate_commit_prepare(struct nb_context context,
                                struct nb_config *candidate,
                                const char *comment,
                                struct nb_transaction **transaction,
+                               bool skip_validate, bool ignore_zero_change,
                                char *errmsg, size_t errmsg_len)
 {
        struct nb_config_cbs changes;
 
-       if (nb_candidate_validate_yang(candidate, errmsg, errmsg_len)
-           != NB_OK) {
+       if (!skip_validate &&
+           nb_candidate_validate_yang(candidate, true, errmsg, errmsg_len) !=
+                   NB_OK) {
                flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
                          "%s: failed to validate candidate configuration",
                          __func__);
@@ -853,16 +1053,16 @@ int nb_candidate_commit_prepare(struct nb_context *context,
 
        RB_INIT(nb_config_cbs, &changes);
        nb_config_diff(running_config, candidate, &changes);
-       if (RB_EMPTY(nb_config_cbs, &changes)) {
+       if (!ignore_zero_change && RB_EMPTY(nb_config_cbs, &changes)) {
                snprintf(
                        errmsg, errmsg_len,
                        "No changes to apply were found during preparation phase");
                return NB_ERR_NO_CHANGES;
        }
 
-       if (nb_candidate_validate_code(context, candidate, &changes, errmsg,
-                                      errmsg_len)
-           != NB_OK) {
+       if (!skip_validate &&
+           nb_candidate_validate_code(&context, candidate, &changes, errmsg,
+                                      errmsg_len) != NB_OK) {
                flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
                          "%s: failed to validate candidate configuration",
                          __func__);
@@ -870,8 +1070,12 @@ int nb_candidate_commit_prepare(struct nb_context *context,
                return NB_ERR_VALIDATION;
        }
 
-       *transaction = nb_transaction_new(context, candidate, &changes, comment,
-                                         errmsg, errmsg_len);
+       /*
+        * Re-use an existing transaction if provided. Else allocate a new one.
+        */
+       if (!*transaction)
+               *transaction = nb_transaction_new(context, candidate, &changes,
+                                                 comment, errmsg, errmsg_len);
        if (*transaction == NULL) {
                flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
                          "%s: failed to create transaction: %s", __func__,
@@ -913,7 +1117,7 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction,
        nb_transaction_free(transaction);
 }
 
-int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate,
+int nb_candidate_commit(struct nb_context context, struct nb_config *candidate,
                        bool save_transaction, const char *comment,
                        uint32_t *transaction_id, char *errmsg,
                        size_t errmsg_len)
@@ -922,7 +1126,8 @@ int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate,
        int ret;
 
        ret = nb_candidate_commit_prepare(context, candidate, comment,
-                                         &transaction, errmsg, errmsg_len);
+                                         &transaction, false, false, errmsg,
+                                         errmsg_len);
        /*
         * Apply the changes if the preparation phase succeeded. Otherwise abort
         * the transaction.
@@ -1016,6 +1221,8 @@ static int nb_callback_create(struct nb_context *context,
        bool unexpected_error = false;
        int ret;
 
+       assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS));
+
        nb_log_config_callback(event, NB_OP_CREATE, dnode);
 
        args.context = context;
@@ -1065,6 +1272,8 @@ static int nb_callback_modify(struct nb_context *context,
        bool unexpected_error = false;
        int ret;
 
+       assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS));
+
        nb_log_config_callback(event, NB_OP_MODIFY, dnode);
 
        args.context = context;
@@ -1114,6 +1323,8 @@ static int nb_callback_destroy(struct nb_context *context,
        bool unexpected_error = false;
        int ret;
 
+       assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS));
+
        nb_log_config_callback(event, NB_OP_DESTROY, dnode);
 
        args.context = context;
@@ -1157,6 +1368,8 @@ static int nb_callback_move(struct nb_context *context,
        bool unexpected_error = false;
        int ret;
 
+       assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS));
+
        nb_log_config_callback(event, NB_OP_MOVE, dnode);
 
        args.context = context;
@@ -1200,6 +1413,9 @@ static int nb_callback_pre_validate(struct nb_context *context,
        bool unexpected_error = false;
        int ret;
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return 0;
+
        nb_log_config_callback(NB_EV_VALIDATE, NB_OP_PRE_VALIDATE, dnode);
 
        args.dnode = dnode;
@@ -1231,6 +1447,9 @@ static void nb_callback_apply_finish(struct nb_context *context,
 {
        struct nb_cb_apply_finish_args args = {};
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return;
+
        nb_log_config_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, dnode);
 
        args.context = context;
@@ -1246,6 +1465,9 @@ struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node,
 {
        struct nb_cb_get_elem_args args = {};
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return NULL;
+
        DEBUGD(&nb_dbg_cbs_state,
               "northbound callback (get_elem): xpath [%s] list_entry [%p]",
               xpath, list_entry);
@@ -1261,6 +1483,9 @@ const void *nb_callback_get_next(const struct nb_node *nb_node,
 {
        struct nb_cb_get_next_args args = {};
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return NULL;
+
        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);
@@ -1275,6 +1500,9 @@ int nb_callback_get_keys(const struct nb_node *nb_node, const void *list_entry,
 {
        struct nb_cb_get_keys_args args = {};
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return 0;
+
        DEBUGD(&nb_dbg_cbs_state,
               "northbound callback (get_keys): node [%s] list_entry [%p]",
               nb_node->xpath, list_entry);
@@ -1290,6 +1518,9 @@ const void *nb_callback_lookup_entry(const struct nb_node *nb_node,
 {
        struct nb_cb_lookup_entry_args args = {};
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return NULL;
+
        DEBUGD(&nb_dbg_cbs_state,
               "northbound callback (lookup_entry): node [%s] parent_list_entry [%p]",
               nb_node->xpath, parent_list_entry);
@@ -1305,6 +1536,9 @@ int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath,
 {
        struct nb_cb_rpc_args args = {};
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return 0;
+
        DEBUGD(&nb_dbg_cbs_rpc, "northbound RPC: %s", xpath);
 
        args.xpath = xpath;
@@ -1331,6 +1565,9 @@ static int nb_callback_configuration(struct nb_context *context,
        union nb_resource *resource;
        int ret = NB_ERR;
 
+       if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS))
+               return NB_OK;
+
        if (event == NB_EV_VALIDATE)
                resource = NULL;
        else
@@ -1411,13 +1648,13 @@ static int nb_callback_configuration(struct nb_context *context,
 }
 
 static struct nb_transaction *
-nb_transaction_new(struct nb_context *context, struct nb_config *config,
+nb_transaction_new(struct nb_context context, struct nb_config *config,
                   struct nb_config_cbs *changes, const char *comment,
                   char *errmsg, size_t errmsg_len)
 {
        struct nb_transaction *transaction;
 
-       if (nb_running_lock_check(context->client, context->user)) {
+       if (nb_running_lock_check(context.client, context.user)) {
                strlcpy(errmsg,
                        "running configuration is locked by another client",
                        errmsg_len);
@@ -1469,7 +1706,7 @@ static int nb_transaction_process(enum nb_event event,
                        break;
 
                /* Call the appropriate callback. */
-               ret = nb_callback_configuration(transaction->context, event,
+               ret = nb_callback_configuration(&transaction->context, event,
                                                change, errmsg, errmsg_len);
                switch (event) {
                case NB_EV_PREPARE:
@@ -1584,7 +1821,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)
-               nb_callback_apply_finish(transaction->context, cb->nb_node,
+               nb_callback_apply_finish(&transaction->context, cb->nb_node,
                                         cb->dnode, errmsg, errmsg_len);
 
        /* Release memory. */
@@ -1734,7 +1971,7 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node,
        /* Iterate over all list entries. */
        do {
                const struct lysc_node_leaf *skey;
-               struct yang_list_keys list_keys;
+               struct yang_list_keys list_keys = {};
                char xpath[XPATH_MAXLEN * 2];
                int ret;
 
@@ -1892,8 +2129,8 @@ int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator,
         * all YANG lists (if any).
         */
 
-       LY_ERR err = lyd_new_path(NULL, ly_native_ctx, xpath, NULL,
-                                 LYD_NEW_PATH_UPDATE, &dnode);
+       LY_ERR err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0,
+                                  LYD_NEW_PATH_UPDATE, NULL, &dnode);
        if (err || !dnode) {
                const char *errmsg =
                        err ? ly_errmsg(ly_native_ctx) : "node not found";
@@ -2390,6 +2627,10 @@ const char *nb_client_name(enum nb_client client)
                return "gRPC";
        case NB_CLIENT_PCEP:
                return "Pcep";
+       case NB_CLIENT_MGMTD_SERVER:
+               return "MGMTD Server";
+       case NB_CLIENT_MGMTD_BE:
+               return "MGMT Backend";
        case NB_CLIENT_NONE:
                return "None";
        }
@@ -2399,6 +2640,10 @@ const char *nb_client_name(enum nb_client client)
 
 static void nb_load_callbacks(const struct frr_yang_module_info *module)
 {
+
+       if (module->ignore_cbs)
+               return;
+
        for (size_t i = 0; module->nodes[i].xpath; i++) {
                struct nb_node *nb_node;
                uint32_t priority;
@@ -2440,7 +2685,7 @@ void nb_validate_callbacks(void)
 }
 
 
-void nb_init(struct thread_master *tm,
+void nb_init(struct event_loop *tm,
             const struct frr_yang_module_info *const modules[],
             size_t nmodules, bool db_enabled)
 {
@@ -2472,7 +2717,8 @@ void nb_init(struct thread_master *tm,
 
        /* Initialize the compiled nodes with northbound data */
        for (size_t i = 0; i < nmodules; i++) {
-               yang_snodes_iterate(loaded[i]->info, nb_node_new_cb, 0, NULL);
+               yang_snodes_iterate(loaded[i]->info, nb_node_new_cb, 0,
+                                   (void *)modules[i]);
                nb_load_callbacks(modules[i]);
        }
 
@@ -2499,8 +2745,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);
+       hash_clean_and_free(&running_config_entries, running_config_entry_free);
        nb_config_free(running_config);
        pthread_mutex_destroy(&running_config_mgmt_lock.mtx);
 }