]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #3393 from donaldsharp/rnh_resend
authorRenato Westphal <renato@openbsd.org>
Wed, 28 Nov 2018 22:30:15 +0000 (20:30 -0200)
committerGitHub <noreply@github.com>
Wed, 28 Nov 2018 22:30:15 +0000 (20:30 -0200)
zebra: Always resend nexthop information when registered

13 files changed:
configure.ac
lib/command.c
lib/if.c
lib/northbound_cli.c
lib/northbound_cli.h
lib/northbound_confd.c
lib/prefix.c
lib/vty.h
lib/yang.c
lib/yang.h
lib/yang_translator.c
ripd/rip_cli.c
ripd/rip_northbound.c

index c925509fafac96f46bf451f13aa3f9ae425b06dd..09d57ab0f294fdcd6a19b406e4eb21f89bc87166 100755 (executable)
@@ -1627,7 +1627,7 @@ dnl ---------------
 dnl confd
 dnl ---------------
 if test "$enable_confd" != "" -a "$enable_confd" != "no"; then
-   AC_CHECK_PROG([CONFD], [confd], [confd], [/bin/false])
+   AC_CHECK_PROG([CONFD], [confd], [confd], [/bin/false], "${enable_confd}/bin")
    if test "x$CONFD" = "x/bin/false"; then
       AC_MSG_ERROR([confd was not found on your system.])]
    fi
index bd000c37465d1f7859edf80449f41703a0875ba2..a01aabcc2a285ab4b67b1a15c67acd2f65a561d4 100644 (file)
@@ -1051,8 +1051,13 @@ static int cmd_execute_command_real(vector vline, enum filter_type filter,
        int ret;
        if (matched_element->daemon)
                ret = CMD_SUCCESS_DAEMON;
-       else
+       else {
+               /* Clear enqueued configuration changes. */
+               vty->num_cfg_changes = 0;
+               memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
+
                ret = matched_element->func(matched_element, vty, argc, argv);
+       }
 
        // delete list and cmd_token's in it
        list_delete(&argv_list);
index e02c89b9acea3e0b4daa114c739bc89057c5374e..0fd65da03a06be957888d03b2ff2bd72df6ef9cb 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -1086,12 +1086,6 @@ DEFPY_NOSH (interface,
        VRF_CMD_HELP_STR)
 {
        char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_CREATE,
-               },
-       };
        vrf_id_t vrf_id;
        struct interface *ifp;
        int ret;
@@ -1136,7 +1130,8 @@ DEFPY_NOSH (interface,
                 "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname,
                 vrfname);
 
-       ret = nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+       ret = nb_cli_apply_changes(vty, xpath_list);
        if (ret == CMD_SUCCESS) {
                VTY_PUSH_XPATH(INTERFACE_NODE, xpath_list);
 
@@ -1162,22 +1157,14 @@ DEFPY (no_interface,
        "Interface's name\n"
        VRF_CMD_HELP_STR)
 {
-       char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_DELETE,
-               },
-       };
-
        if (!vrfname)
                vrfname = VRF_DEFAULT_NAME;
 
-       snprintf(xpath_list, sizeof(xpath_list),
-                "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname,
-                vrfname);
+       nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
 
-       return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
+       return nb_cli_apply_changes(
+               vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+               ifname, vrfname);
 }
 
 static void cli_show_interface(struct vty *vty, struct lyd_node *dnode,
@@ -1203,18 +1190,12 @@ DEFPY (interface_desc,
        "Interface specific description\n"
        "Characters describing this interface\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./description",
-                       .operation = NB_OP_MODIFY,
-               },
-       };
        char *desc;
        int ret;
 
        desc = argv_concat(argv, argc, 1);
-       changes[0].value = desc;
-       ret = nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc);
+       ret = nb_cli_apply_changes(vty, NULL);
        XFREE(MTYPE_TMP, desc);
 
        return ret;
@@ -1226,14 +1207,9 @@ DEFPY  (no_interface_desc,
        NO_STR
        "Interface specific description\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./description",
-                       .operation = NB_OP_DELETE,
-               },
-       };
+       nb_cli_enqueue_change(vty, "./description", NB_OP_DELETE, NULL);
 
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 static void cli_show_interface_desc(struct vty *vty, struct lyd_node *dnode,
@@ -1338,7 +1314,7 @@ static int lib_interface_delete(enum nb_event event,
 {
        struct interface *ifp;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
 
        switch (event) {
        case NB_EV_VALIDATE:
@@ -1372,7 +1348,7 @@ static int lib_interface_description_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        if (ifp->desc)
                XFREE(MTYPE_TMP, ifp->desc);
        description = yang_dnode_get_string(dnode, NULL);
@@ -1389,7 +1365,7 @@ static int lib_interface_description_delete(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        if (ifp->desc)
                XFREE(MTYPE_TMP, ifp->desc);
 
index 8ae44e72d52b0b1d800ffcdc0cab574d03d5b31e..94f7bb7c1e5b58118c9d12ec9a83795e020924f6 100644 (file)
@@ -56,10 +56,30 @@ static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx)
        ly_err_clean(ly_ctx, NULL);
 }
 
-int nb_cli_cfg_change(struct vty *vty, char *xpath_base,
-                     struct cli_config_change changes[], size_t size)
+void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
+                          enum nb_operation operation, const char *value)
+{
+       struct vty_cfg_change *change;
+
+       if (vty->num_cfg_changes == VTY_MAXCFGCHANGES) {
+               /* Not expected to happen. */
+               vty_out(vty,
+                       "%% Exceeded the maximum number of changes (%u) for a single command\n\n",
+                       VTY_MAXCFGCHANGES);
+               return;
+       }
+
+       change = &vty->cfg_changes[vty->num_cfg_changes++];
+       change->xpath = xpath;
+       change->operation = operation;
+       change->value = value;
+}
+
+int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
 {
        struct nb_config *candidate_transitory;
+       char xpath_base[XPATH_MAXLEN];
+       va_list ap;
        bool error = false;
        int ret;
 
@@ -72,9 +92,14 @@ int nb_cli_cfg_change(struct vty *vty, char *xpath_base,
         */
        candidate_transitory = nb_config_dup(vty->candidate_config);
 
+       /* Parse the base XPath format string. */
+       va_start(ap, xpath_base_fmt);
+       vsnprintf(xpath_base, sizeof(xpath_base), xpath_base_fmt, ap);
+       va_end(ap);
+
        /* Edit candidate configuration. */
-       for (size_t i = 0; i < size; i++) {
-               struct cli_config_change *change = &changes[i];
+       for (size_t i = 0; i < vty->num_cfg_changes; i++) {
+               struct vty_cfg_change *change = &vty->cfg_changes[i];
                struct nb_node *nb_node;
                char xpath[XPATH_MAXLEN];
                struct yang_data *data;
@@ -82,19 +107,21 @@ int nb_cli_cfg_change(struct vty *vty, char *xpath_base,
                /* Handle relative XPaths. */
                memset(xpath, 0, sizeof(xpath));
                if (vty->xpath_index > 0
-                   && ((xpath_base && xpath_base[0] == '.')
+                   && ((xpath_base_fmt && xpath_base[0] == '.')
                        || change->xpath[0] == '.'))
                        strlcpy(xpath, VTY_CURR_XPATH, sizeof(xpath));
-               if (xpath_base) {
+               if (xpath_base_fmt) {
                        if (xpath_base[0] == '.')
-                               xpath_base++;
-                       strlcat(xpath, xpath_base, sizeof(xpath));
+                               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,
index 7f4a64c014bf5affd348446df8aabcd9b9010299..febcbd86f17baa40a9e711910b99764ffa0a46c3 100644 (file)
 
 #include "northbound.h"
 
-struct cli_config_change {
-       /*
-        * XPath (absolute or relative) of the configuration option being
-        * edited.
-        */
-       char xpath[XPATH_MAXLEN];
-
-       /*
-        * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or
-        * NB_OP_DELETE).
-        */
-       enum nb_operation operation;
-
-       /*
-        * New value of the configuration option. Should be NULL for typeless
-        * YANG data (e.g. presence-containers). For convenience, NULL can also
-        * be used to restore a leaf to its default value.
-        */
-       const char *value;
-};
-
 /* Possible formats in which a configuration can be displayed. */
 enum nb_cfg_format {
        NB_CFG_FMT_CMDS = 0,
@@ -52,13 +31,80 @@ enum nb_cfg_format {
 
 extern struct nb_config *vty_shared_candidate_config;
 
-/* Prototypes. */
-extern int nb_cli_cfg_change(struct vty *vty, char *xpath_list,
-                            struct cli_config_change changes[], size_t size);
+/*
+ * Enqueue change to be applied in the candidate configuration.
+ *
+ * vty
+ *    The vty context.
+ *
+ * xpath
+ *    XPath (absolute or relative) of the configuration option being edited.
+ *
+ * operation
+ *    Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DELETE).
+ *
+ * value
+ *    New value of the configuration option. Should be NULL for typeless YANG
+ *    data (e.g. presence-containers). For convenience, NULL can also be used
+ *    to restore a leaf to its default value.
+ */
+extern void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
+                                 enum nb_operation operation,
+                                 const char *value);
+
+/*
+ * Apply enqueued changes to the candidate configuration.
+ *
+ * vty
+ *    The vty context.
+ *
+ * xpath_base_fmt
+ *    Prepend the given XPath (absolute or relative) to all enqueued
+ *    configuration changes.
+ *
+ * Returns:
+ *    CMD_SUCCESS on success, CMD_WARNING_CONFIG_FAILED otherwise.
+ */
+extern int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt,
+                               ...);
+
+/*
+ * Execute a YANG RPC or Action.
+ *
+ * xpath
+ *    XPath of the YANG RPC or Action node.
+ *
+ * input
+ *    List of 'yang_data' structures containing the RPC input parameters. It
+ *    can be set to NULL when there are no input parameters.
+ *
+ * output
+ *    List of 'yang_data' structures used to retrieve the RPC output parameters.
+ *    It can be set to NULL when it's known that the given YANG RPC or Action
+ *    doesn't have any output parameters.
+ *
+ * Returns:
+ *    CMD_SUCCESS on success, CMD_WARNING otherwise.
+ */
 extern int nb_cli_rpc(const char *xpath, struct list *input,
                      struct list *output);
+
+/*
+ * Show CLI commands associated to the given YANG data node.
+ *
+ * vty
+ *    The vty terminal to dump the configuration to.
+ *
+ * dnode
+ *    libyang data node that should be shown in the form of CLI commands.
+ *
+ * show_defaults
+ *    Specify whether to display default configuration values or not.
+ */
 extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode,
                                   bool show_defaults);
+
+/* Prototypes of internal functions. */
 extern void nb_cli_install_default(int node);
 extern void nb_cli_init(void);
 extern void nb_cli_terminate(void);
index 8cfa2fe113821fdee3d1bbbcf7e2e117a09407b0..ec5e0c32c3ba3f4a6b0880538bda8b426ec0ee33 100644 (file)
@@ -951,9 +951,11 @@ static int frr_confd_dp_read(struct thread *thread)
        ret = confd_fd_ready(dctx, fd);
        if (ret == CONFD_EOF) {
                flog_err_confd("confd_fd_ready");
+               frr_confd_finish();
                return -1;
        } else if (ret == CONFD_ERR && confd_errno != CONFD_ERR_EXTERNAL) {
                flog_err_confd("confd_fd_ready");
+               frr_confd_finish();
                return -1;
        }
 
index 21c3af7d49e8f164a46e18278429708423952981..858f860ee8e1f8e99e169bc5fe75eae00a056739 100644 (file)
@@ -853,7 +853,7 @@ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p)
        /* String doesn't contail slash. */
        if (pnt == NULL) {
                /* Convert string to prefix. */
-               ret = inet_aton(str, &p->prefix);
+               ret = inet_pton(AF_INET, str, &p->prefix);
                if (ret == 0)
                        return 0;
 
index 4c434fb2f206eaa43c6113d622528e53119ec47a..5cc077523f7c5b4731ddbe9e00c45bf1547e0996 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
 #define VTY_MAXHIST 20
 #define VTY_MAXDEPTH 8
 
+#define VTY_MAXCFGCHANGES 8
+
 struct vty_error {
        char error_buf[VTY_BUFSIZ];
        uint32_t line_num;
 };
 
+struct vty_cfg_change {
+       const char *xpath;
+       enum nb_operation operation;
+       const char *value;
+};
+
 /* VTY struct. */
 struct vty {
        /* File descripter of this vty. */
@@ -98,6 +106,10 @@ struct vty {
        /* History insert end point */
        int hindex;
 
+       /* Changes enqueued to be applied in the candidate configuration. */
+       size_t num_cfg_changes;
+       struct vty_cfg_change cfg_changes[VTY_MAXCFGCHANGES];
+
        /* XPath of the current node */
        int xpath_index;
        char xpath[VTY_MAXDEPTH][XPATH_MAXLEN];
index a7a50a46b0fcb225aff52c24217e96cda2083ad1..757982d36793d09dc4423b9c5394aa3294506561 100644 (file)
@@ -344,6 +344,29 @@ void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
        free(xpath_ptr);
 }
 
+const char *yang_dnode_get_schema_name(const struct lyd_node *dnode,
+                                      const char *xpath_fmt, ...)
+{
+       if (xpath_fmt) {
+               va_list ap;
+               char xpath[XPATH_MAXLEN];
+
+               va_start(ap, xpath_fmt);
+               vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+               va_end(ap);
+
+               dnode = yang_dnode_get(dnode, xpath);
+               if (!dnode) {
+                       flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
+                                "%s: couldn't find %s", __func__, xpath);
+                       zlog_backtrace(LOG_ERR);
+                       abort();
+               }
+       }
+
+       return dnode->schema->name;
+}
+
 struct lyd_node *yang_dnode_get(const struct lyd_node *dnode,
                                const char *xpath_fmt, ...)
 {
@@ -470,7 +493,8 @@ void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry)
        lyd_set_private(dnode, entry);
 }
 
-void *yang_dnode_get_entry(const struct lyd_node *dnode)
+void *yang_dnode_get_entry(const struct lyd_node *dnode,
+                          bool abort_if_not_found)
 {
        const struct lyd_node *orig_dnode = dnode;
        char xpath[XPATH_MAXLEN];
@@ -489,6 +513,9 @@ void *yang_dnode_get_entry(const struct lyd_node *dnode)
                dnode = dnode->parent;
        }
 
+       if (!abort_if_not_found)
+               return NULL;
+
        yang_dnode_get_path(orig_dnode, xpath, sizeof(xpath));
        flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
                 "%s: failed to find entry [xpath %s]", __func__, xpath);
@@ -609,13 +636,13 @@ void yang_init(void)
        ly_log_options(LY_LOLOG | LY_LOSTORE);
 
        /* Initialize libyang container for native models. */
-       ly_native_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD);
+       ly_native_ctx =
+               ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD);
        if (!ly_native_ctx) {
                flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
                exit(1);
        }
        ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
-       ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH);
        ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
 
        /* Detect if the required libyang plugin(s) were loaded successfully. */
index b0348e320b3b6ab5b7073e2357c8f53acfe4b150..c920060071fd186a32c74c3a08ae9542d8267607 100644 (file)
@@ -284,6 +284,22 @@ extern const struct lys_type *yang_snode_get_type(const struct lys_node *snode);
 extern void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
                                size_t xpath_len);
 
+/*
+ * Return the schema name of the given libyang data node.
+ *
+ * dnode
+ *    libyang data node.
+ *
+ * xpath_fmt
+ *    Optional XPath expression (absolute or relative) to specify a different
+ *    data node to operate on in the same data tree.
+ *
+ * Returns:
+ *    Schema name of the libyang data node.
+ */
+extern const char *yang_dnode_get_schema_name(const struct lyd_node *dnode,
+                                             const char *xpath_fmt, ...);
+
 /*
  * Find a libyang data node by its YANG data path.
  *
@@ -369,15 +385,37 @@ extern void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value);
 extern void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry);
 
 /*
- * Find the closest data node that contains an user pointer and return it.
+ * Find the user pointer associated to the given libyang data node.
+ *
+ * The data node is traversed by following the parent pointers until an user
+ * pointer is found or until the root node is reached.
  *
  * dnode
  *    libyang data node to operate on.
  *
+ * abort_if_not_found
+ *    When set to true, abort the program if no user pointer is found.
+ *
+ *    As a rule of thumb, this parameter should be set to true in the following
+ *    scenarios:
+ *    - Calling this function from any northbound configuration callback during
+ *      the NB_EV_APPLY phase.
+ *    - Calling this function from a 'delete' northbound configuration callback
+ *      during any phase.
+ *
+ *    In both the above cases, the libyang data node should contain an user
+ *    pointer except when there's a bug in the code, in which case it's better
+ *    to abort the program right away and eliminate the need for unnecessary
+ *    NULL checks.
+ *
+ *    In all other cases, this parameter should be set to false and the caller
+ *    should check if the function returned NULL or not.
+ *
  * Returns:
  *    User pointer if found, NULL otherwise.
  */
-extern void *yang_dnode_get_entry(const struct lyd_node *dnode);
+extern void *yang_dnode_get_entry(const struct lyd_node *dnode,
+                                 bool abort_if_not_found);
 
 /*
  * Create a new libyang data node.
index 27b92a0e6bf8878e60798a0e4736e1e457ccdd89..02da3ebd6af4254ff7ed7cbb281dcaf94ca3853a 100644 (file)
@@ -162,12 +162,12 @@ struct yang_translator *yang_translator_load(const char *path)
        RB_INSERT(yang_translators, &yang_translators, translator);
 
        /* Initialize the translator libyang context. */
-       translator->ly_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD);
+       translator->ly_ctx =
+               ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD);
        if (!translator->ly_ctx) {
                flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
                goto error;
        }
-       ly_ctx_set_searchdir(translator->ly_ctx, YANG_MODELS_PATH);
 
        /* Load modules and deviations. */
        set = lyd_find_path(dnode, "./module");
@@ -515,12 +515,12 @@ static void str_replace(char *o_string, const char *s_string,
 
 void yang_translator_init(void)
 {
-       ly_translator_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD);
+       ly_translator_ctx =
+               ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD);
        if (!ly_translator_ctx) {
                flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
                exit(1);
        }
-       ly_ctx_set_searchdir(ly_translator_ctx, YANG_MODELS_PATH);
 
        if (!ly_ctx_load_module(ly_translator_ctx, "frr-module-translator",
                                NULL)) {
index 510aa661553ec1ab4cdb9bc6900d999bbdb02c4c..e0e5d95895c970cbe2d322f0d5f8d507ead4cfb1 100644 (file)
@@ -45,17 +45,12 @@ DEFPY_NOSH (router_rip,
 {
        int ret;
 
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "/frr-ripd:ripd/instance",
-                       .operation = NB_OP_CREATE,
-                       .value = NULL,
-               },
-       };
-
-       ret = nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_CREATE,
+                             NULL);
+
+       ret = nb_cli_apply_changes(vty, NULL);
        if (ret == CMD_SUCCESS)
-               VTY_PUSH_XPATH(RIP_NODE, changes[0].xpath);
+               VTY_PUSH_XPATH(RIP_NODE, "/frr-ripd:ripd/instance");
 
        return ret;
 }
@@ -67,15 +62,10 @@ DEFPY (no_router_rip,
        "Enable a routing process\n"
        "Routing Information Protocol (RIP)\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "/frr-ripd:ripd/instance",
-                       .operation = NB_OP_DELETE,
-                       .value = NULL,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DELETE,
+                             NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_router_rip(struct vty *vty, struct lyd_node *dnode,
@@ -94,15 +84,10 @@ DEFPY (rip_allow_ecmp,
        NO_STR
        "Allow Equal Cost MultiPath\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./allow-ecmp",
-                       .operation = NB_OP_MODIFY,
-                       .value = no ? "false" : "true",
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./allow-ecmp", NB_OP_MODIFY,
+                             no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_allow_ecmp(struct vty *vty, struct lyd_node *dnode,
@@ -124,15 +109,10 @@ DEFPY (rip_default_information_originate,
        "Control distribution of default route\n"
        "Distribute a default route\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./default-information-originate",
-                       .operation = NB_OP_MODIFY,
-                       .value = no ? "false" : "true",
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./default-information-originate",
+                             NB_OP_MODIFY, no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_default_information_originate(struct vty *vty,
@@ -154,15 +134,10 @@ DEFPY (rip_default_metric,
        "Set a metric of redistribute routes\n"
        "Default metric\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./default-metric",
-                       .operation = NB_OP_MODIFY,
-                       .value = default_metric_str,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./default-metric", NB_OP_MODIFY,
+                             default_metric_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFPY (no_rip_default_metric,
@@ -172,15 +147,9 @@ DEFPY (no_rip_default_metric,
        "Set a metric of redistribute routes\n"
        "Default metric\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./default-metric",
-                       .operation = NB_OP_MODIFY,
-                       .value = NULL,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./default-metric", NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_default_metric(struct vty *vty, struct lyd_node *dnode,
@@ -199,15 +168,10 @@ DEFPY (rip_distance,
        "Administrative distance\n"
        "Distance value\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./distance/default",
-                       .operation = NB_OP_MODIFY,
-                       .value = distance_str,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./distance/default", NB_OP_MODIFY,
+                             distance_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFPY (no_rip_distance,
@@ -217,21 +181,19 @@ DEFPY (no_rip_distance,
        "Administrative distance\n"
        "Distance value\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./distance/default",
-                       .operation = NB_OP_MODIFY,
-                       .value = NULL,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./distance/default", NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_distance(struct vty *vty, struct lyd_node *dnode,
                           bool show_defaults)
 {
-       vty_out(vty, " distance %s\n", yang_dnode_get_string(dnode, NULL));
+       if (yang_dnode_is_default(dnode, NULL))
+               vty_out(vty, " no distance\n");
+       else
+               vty_out(vty, " distance %s\n",
+                       yang_dnode_get_string(dnode, NULL));
 }
 
 /*
@@ -239,57 +201,23 @@ void cli_show_rip_distance(struct vty *vty, struct lyd_node *dnode,
  */
 DEFPY (rip_distance_source,
        rip_distance_source_cmd,
-       "distance (1-255) A.B.C.D/M$prefix [WORD$acl]",
-       "Administrative distance\n"
-       "Distance value\n"
-       "IP source prefix\n"
-       "Access list name\n")
-{
-       char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_CREATE,
-               },
-               {
-                       .xpath = "./distance",
-                       .operation = NB_OP_MODIFY,
-                       .value = distance_str,
-               },
-               {
-                       .xpath = "./access-list",
-                       .operation = acl ? NB_OP_MODIFY : NB_OP_DELETE,
-                       .value = acl,
-               },
-       };
-
-       snprintf(xpath_list, sizeof(xpath_list),
-                "./distance/source[prefix='%s']", prefix_str);
-
-       return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
-}
-
-DEFPY (no_rip_distance_source,
-       no_rip_distance_source_cmd,
-       "no distance (1-255) A.B.C.D/M$prefix [WORD$acl]",
+       "[no] distance (1-255) A.B.C.D/M$prefix [WORD$acl]",
        NO_STR
        "Administrative distance\n"
        "Distance value\n"
        "IP source prefix\n"
        "Access list name\n")
 {
-       char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_DELETE,
-               },
-       };
-
-       snprintf(xpath_list, sizeof(xpath_list),
-                "./distance/source[prefix='%s']", prefix_str);
-
-       return nb_cli_cfg_change(vty, xpath_list, changes, 1);
+       if (!no) {
+               nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+               nb_cli_enqueue_change(vty, "./distance", NB_OP_MODIFY, NULL);
+               nb_cli_enqueue_change(vty, "./access-list",
+                                     acl ? NB_OP_MODIFY : NB_OP_DELETE, acl);
+       } else
+               nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+
+       return nb_cli_apply_changes(vty, "./distance/source[prefix='%s']",
+                                   prefix_str);
 }
 
 void cli_show_rip_distance_source(struct vty *vty, struct lyd_node *dnode,
@@ -314,15 +242,10 @@ DEFPY (rip_neighbor,
        "Specify a neighbor router\n"
        "Neighbor address\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./explicit-neighbor",
-                       .operation = no ? NB_OP_DELETE : NB_OP_CREATE,
-                       .value = neighbor_str,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./explicit-neighbor",
+                             no ? NB_OP_DELETE : NB_OP_CREATE, neighbor_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_neighbor(struct vty *vty, struct lyd_node *dnode,
@@ -341,15 +264,10 @@ DEFPY (rip_network_prefix,
        "Enable routing on an IP network\n"
        "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./network",
-                       .operation = no ? NB_OP_DELETE : NB_OP_CREATE,
-                       .value = network_str,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./network",
+                             no ? NB_OP_DELETE : NB_OP_CREATE, network_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_network_prefix(struct vty *vty, struct lyd_node *dnode,
@@ -368,15 +286,10 @@ DEFPY (rip_network_if,
        "Enable routing on an IP network\n"
        "Interface name\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./interface",
-                       .operation = no ? NB_OP_DELETE : NB_OP_CREATE,
-                       .value = network,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./interface",
+                             no ? NB_OP_DELETE : NB_OP_CREATE, network);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_network_interface(struct vty *vty, struct lyd_node *dnode,
@@ -390,42 +303,7 @@ void cli_show_rip_network_interface(struct vty *vty, struct lyd_node *dnode,
  */
 DEFPY (rip_offset_list,
        rip_offset_list_cmd,
-       "offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]",
-       "Modify RIP metric\n"
-       "Access-list name\n"
-       "For incoming updates\n"
-       "For outgoing updates\n"
-       "Metric value\n"
-       "Interface to match\n")
-{
-       char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_CREATE,
-               },
-               {
-                       .xpath = "./access-list",
-                       .operation = NB_OP_MODIFY,
-                       .value = acl,
-               },
-               {
-                       .xpath = "./metric",
-                       .operation = NB_OP_MODIFY,
-                       .value = metric_str,
-               },
-       };
-
-       snprintf(xpath_list, sizeof(xpath_list),
-                "./offset-list[interface='%s'][direction='%s']",
-                ifname ? ifname : "*", direction);
-
-       return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
-}
-
-DEFPY (no_rip_offset_list,
-       no_rip_offset_list_cmd,
-       "no offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]",
+       "[no] offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]",
        NO_STR
        "Modify RIP metric\n"
        "Access-list name\n"
@@ -434,19 +312,17 @@ DEFPY (no_rip_offset_list,
        "Metric value\n"
        "Interface to match\n")
 {
-       char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_DELETE,
-               },
-       };
-
-       snprintf(xpath_list, sizeof(xpath_list),
-                "./offset-list[interface='%s'][direction='%s']",
-                ifname ? ifname : "*", direction);
-
-       return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
+       if (!no) {
+               nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+               nb_cli_enqueue_change(vty, "./access-list", NB_OP_MODIFY, acl);
+               nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY,
+                                     metric_str);
+       } else
+               nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+
+       return nb_cli_apply_changes(
+               vty, "./offset-list[interface='%s'][direction='%s']",
+               ifname ? ifname : "*", direction);
 }
 
 void cli_show_rip_offset_list(struct vty *vty, struct lyd_node *dnode,
@@ -475,15 +351,10 @@ DEFPY (rip_passive_default,
        "Suppress routing updates on an interface\n"
        "default for all interfaces\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./passive-default",
-                       .operation = NB_OP_MODIFY,
-                       .value = no ? "false" : "true",
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./passive-default", NB_OP_MODIFY,
+                             no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_passive_default(struct vty *vty, struct lyd_node *dnode,
@@ -506,20 +377,12 @@ DEFPY (rip_passive_interface,
        "Suppress routing updates on an interface\n"
        "Interface name\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./passive-interface",
-                       .operation = no ? NB_OP_DELETE : NB_OP_CREATE,
-                       .value = ifname,
-               },
-               {
-                       .xpath = "./non-passive-interface",
-                       .operation = no ? NB_OP_CREATE : NB_OP_DELETE,
-                       .value = ifname,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./passive-interface",
+                             no ? NB_OP_DELETE : NB_OP_CREATE, ifname);
+       nb_cli_enqueue_change(vty, "./non-passive-interface",
+                             no ? NB_OP_CREATE : NB_OP_DELETE, ifname);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_passive_interface(struct vty *vty, struct lyd_node *dnode,
@@ -541,41 +404,7 @@ void cli_show_rip_non_passive_interface(struct vty *vty, struct lyd_node *dnode,
  */
 DEFPY (rip_redistribute,
        rip_redistribute_cmd,
-       "redistribute " FRR_REDIST_STR_RIPD "$protocol [{metric (0-16)|route-map WORD}]",
-       REDIST_STR
-       FRR_REDIST_HELP_STR_RIPD
-       "Metric\n"
-       "Metric value\n"
-       "Route map reference\n"
-       "Pointer to route-map entries\n")
-{
-       char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_CREATE,
-               },
-               {
-                       .xpath = "./route-map",
-                       .operation = route_map ? NB_OP_MODIFY : NB_OP_DELETE,
-                       .value = route_map,
-               },
-               {
-                       .xpath = "./metric",
-                       .operation = metric_str ? NB_OP_MODIFY : NB_OP_DELETE,
-                       .value = metric_str,
-               },
-       };
-
-       snprintf(xpath_list, sizeof(xpath_list),
-                "./redistribute[protocol='%s']", protocol);
-
-       return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
-}
-
-DEFPY (no_rip_redistribute,
-       no_rip_redistribute_cmd,
-       "no redistribute " FRR_REDIST_STR_RIPD "$protocol [{metric (0-16)|route-map WORD}]",
+       "[no] redistribute " FRR_REDIST_STR_RIPD "$protocol [{metric (0-16)|route-map WORD}]",
        NO_STR
        REDIST_STR
        FRR_REDIST_HELP_STR_RIPD
@@ -584,18 +413,19 @@ DEFPY (no_rip_redistribute,
        "Route map reference\n"
        "Pointer to route-map entries\n")
 {
-       char xpath_list[XPATH_MAXLEN];
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = ".",
-                       .operation = NB_OP_DELETE,
-               },
-       };
-
-       snprintf(xpath_list, sizeof(xpath_list),
-                "./redistribute[protocol='%s']", protocol);
-
-       return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
+       if (!no) {
+               nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+               nb_cli_enqueue_change(vty, "./route-map",
+                                     route_map ? NB_OP_MODIFY : NB_OP_DELETE,
+                                     route_map);
+               nb_cli_enqueue_change(vty, "./metric",
+                                     metric_str ? NB_OP_MODIFY : NB_OP_DELETE,
+                                     metric_str);
+       } else
+               nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+
+       return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']",
+                                   protocol);
 }
 
 void cli_show_rip_redistribute(struct vty *vty, struct lyd_node *dnode,
@@ -622,15 +452,10 @@ DEFPY (rip_route,
        "RIP static route configuration\n"
        "IP prefix <network>/<length>\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./static-route",
-                       .operation = no ? NB_OP_DELETE : NB_OP_CREATE,
-                       .value = route_str,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./static-route",
+                             no ? NB_OP_DELETE : NB_OP_CREATE, route_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_route(struct vty *vty, struct lyd_node *dnode,
@@ -651,25 +476,14 @@ DEFPY (rip_timers,
        "Routing information timeout timer. Default is 180.\n"
        "Garbage collection timer. Default is 120.\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./timers/update-interval",
-                       .operation = NB_OP_MODIFY,
-                       .value = update_str,
-               },
-               {
-                       .xpath = "./timers/holddown-interval",
-                       .operation = NB_OP_MODIFY,
-                       .value = timeout_str,
-               },
-               {
-                       .xpath = "./timers/flush-interval",
-                       .operation = NB_OP_MODIFY,
-                       .value = garbage_str,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./update-interval", NB_OP_MODIFY,
+                             update_str);
+       nb_cli_enqueue_change(vty, "./holddown-interval", NB_OP_MODIFY,
+                             timeout_str);
+       nb_cli_enqueue_change(vty, "./flush-interval", NB_OP_MODIFY,
+                             garbage_str);
+
+       return nb_cli_apply_changes(vty, "./timers");
 }
 
 DEFPY (no_rip_timers,
@@ -682,25 +496,11 @@ DEFPY (no_rip_timers,
        "Routing information timeout timer. Default is 180.\n"
        "Garbage collection timer. Default is 120.\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./timers/update-interval",
-                       .operation = NB_OP_MODIFY,
-                       .value =  NULL,
-               },
-               {
-                       .xpath = "./timers/holddown-interval",
-                       .operation = NB_OP_MODIFY,
-                       .value =  NULL,
-               },
-               {
-                       .xpath = "./timers/flush-interval",
-                       .operation = NB_OP_MODIFY,
-                       .value =  NULL,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./update-interval", NB_OP_MODIFY, NULL);
+       nb_cli_enqueue_change(vty, "./holddown-interval", NB_OP_MODIFY, NULL);
+       nb_cli_enqueue_change(vty, "./flush-interval", NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, "./timers");
 }
 
 void cli_show_rip_timers(struct vty *vty, struct lyd_node *dnode,
@@ -721,20 +521,11 @@ DEFPY (rip_version,
        "Set routing protocol version\n"
        "version\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./version/receive",
-                       .operation = NB_OP_MODIFY,
-                       .value = version_str,
-               },
-               {
-                       .xpath = "./version/send",
-                       .operation = NB_OP_MODIFY,
-                       .value = version_str,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./version/receive", NB_OP_MODIFY,
+                             version_str);
+       nb_cli_enqueue_change(vty, "./version/send", NB_OP_MODIFY, version_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFPY (no_rip_version,
@@ -744,18 +535,10 @@ DEFPY (no_rip_version,
        "Set routing protocol version\n"
        "version\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./version/receive",
-                       .operation = NB_OP_MODIFY,
-               },
-               {
-                       .xpath = "./version/send",
-                       .operation = NB_OP_MODIFY,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./version/receive", NB_OP_MODIFY, NULL);
+       nb_cli_enqueue_change(vty, "./version/send", NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_rip_version(struct vty *vty, struct lyd_node *dnode,
@@ -790,21 +573,18 @@ DEFPY (ip_rip_split_horizon,
        "Perform split horizon\n"
        "With poisoned-reverse\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/split-horizon",
-                       .operation = NB_OP_MODIFY,
-               },
-       };
+       const char *value;
 
        if (no)
-               changes[0].value = "disabled";
+               value = "disabled";
        else if (poisoned_reverse)
-               changes[0].value = "poison-reverse";
+               value = "poison-reverse";
        else
-               changes[0].value = "simple";
+               value = "simple";
+
+       nb_cli_enqueue_change(vty, "./split-horizon", NB_OP_MODIFY, value);
 
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 void cli_show_ip_rip_split_horizon(struct vty *vty, struct lyd_node *dnode,
@@ -837,15 +617,10 @@ DEFPY (ip_rip_v2_broadcast,
        "Routing Information Protocol\n"
        "Send ip broadcast v2 update\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/v2-broadcast",
-                       .operation = NB_OP_MODIFY,
-                       .value = no ? "false" : "true",
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./v2-broadcast", NB_OP_MODIFY,
+                             no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 void cli_show_ip_rip_v2_broadcast(struct vty *vty, struct lyd_node *dnode,
@@ -871,23 +646,20 @@ DEFPY (ip_rip_receive_version,
        "RIP version 2\n"
        "None\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/version-receive",
-                       .operation = NB_OP_MODIFY,
-               },
-       };
+       const char *value;
 
        if (v1 && v2)
-               changes[0].value = "both";
+               value = "both";
        else if (v1)
-               changes[0].value = "1";
+               value = "1";
        else if (v2)
-               changes[0].value = "2";
+               value = "2";
        else
-               changes[0].value = "none";
+               value = "none";
+
+       nb_cli_enqueue_change(vty, "./version-receive", NB_OP_MODIFY, value);
 
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 DEFPY (no_ip_rip_receive_version,
@@ -902,15 +674,9 @@ DEFPY (no_ip_rip_receive_version,
        "RIP version 2\n"
        "None\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/version-receive",
-                       .operation = NB_OP_MODIFY,
-                       .value = NULL,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./version-receive", NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 void cli_show_ip_rip_receive_version(struct vty *vty, struct lyd_node *dnode,
@@ -949,23 +715,20 @@ DEFPY (ip_rip_send_version,
        "RIP version 2\n"
        "None\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/version-send",
-                       .operation = NB_OP_MODIFY,
-               },
-       };
+       const char *value;
 
        if (v1 && v2)
-               changes[0].value = "both";
+               value = "both";
        else if (v1)
-               changes[0].value = "1";
+               value = "1";
        else if (v2)
-               changes[0].value = "2";
+               value = "2";
        else
-               changes[0].value = "none";
+               value = "none";
+
+       nb_cli_enqueue_change(vty, "./version-send", NB_OP_MODIFY, value);
 
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 DEFPY (no_ip_rip_send_version,
@@ -980,15 +743,9 @@ DEFPY (no_ip_rip_send_version,
        "RIP version 2\n"
        "None\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/version-send",
-                       .operation = NB_OP_MODIFY,
-                       .value = NULL,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./version-send", NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 void cli_show_ip_rip_send_version(struct vty *vty, struct lyd_node *dnode,
@@ -1029,26 +786,21 @@ DEFPY (ip_rip_authentication_mode,
        "Old ripd compatible\n"
        "Clear text authentication\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/authentication-scheme/mode",
-                       .operation = NB_OP_MODIFY,
-                       .value = strmatch(mode, "md5") ? "md5" : "plain-text",
-               },
-               {
-                       .xpath = "./frr-ripd:rip/authentication-scheme/md5-auth-length",
-                       .operation = NB_OP_MODIFY,
-               },
-       };
+       const char *value = NULL;
 
        if (auth_length) {
                if (strmatch(auth_length, "rfc"))
-                       changes[1].value = "16";
+                       value = "16";
                else
-                       changes[1].value = "20";
+                       value = "20";
        }
 
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./authentication-scheme/mode", NB_OP_MODIFY,
+                             strmatch(mode, "md5") ? "md5" : "plain-text");
+       nb_cli_enqueue_change(vty, "./authentication-scheme/md5-auth-length",
+                             NB_OP_MODIFY, value);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 DEFPY (no_ip_rip_authentication_mode,
@@ -1065,18 +817,12 @@ DEFPY (no_ip_rip_authentication_mode,
        "Old ripd compatible\n"
        "Clear text authentication\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/authentication-scheme/mode",
-                       .operation = NB_OP_MODIFY,
-               },
-               {
-                       .xpath = "./frr-ripd:rip/authentication-scheme/md5-auth-length",
-                       .operation = NB_OP_MODIFY,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./authentication-scheme/mode", NB_OP_MODIFY,
+                             NULL);
+       nb_cli_enqueue_change(vty, "./authentication-scheme/md5-auth-length",
+                             NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 void cli_show_ip_rip_authentication_scheme(struct vty *vty,
@@ -1117,14 +863,6 @@ DEFPY (ip_rip_authentication_string,
        "Authentication string\n"
        "Authentication string\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/authentication-password",
-                       .operation = NB_OP_MODIFY,
-                       .value = password,
-               },
-       };
-
        if (strlen(password) > 16) {
                vty_out(vty,
                        "%% RIPv2 authentication string must be shorter than 16\n");
@@ -1138,7 +876,10 @@ DEFPY (ip_rip_authentication_string,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./authentication-password", NB_OP_MODIFY,
+                             password);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 DEFPY (no_ip_rip_authentication_string,
@@ -1151,14 +892,10 @@ DEFPY (no_ip_rip_authentication_string,
        "Authentication string\n"
        "Authentication string\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/authentication-password",
-                       .operation = NB_OP_DELETE,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./authentication-password", NB_OP_MODIFY,
+                             NULL);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 void cli_show_ip_rip_authentication_string(struct vty *vty,
@@ -1181,14 +918,6 @@ DEFPY (ip_rip_authentication_key_chain,
        "Authentication key-chain\n"
        "name of key-chain\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/authentication-key-chain",
-                       .operation = NB_OP_MODIFY,
-                       .value = keychain,
-               },
-       };
-
        if (yang_dnode_exists(vty->candidate_config->dnode, "%s%s",
                              VTY_CURR_XPATH,
                              "/frr-ripd:rip/authentication-password")) {
@@ -1196,7 +925,10 @@ DEFPY (ip_rip_authentication_key_chain,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_MODIFY,
+                             keychain);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 DEFPY (no_ip_rip_authentication_key_chain,
@@ -1209,14 +941,10 @@ DEFPY (no_ip_rip_authentication_key_chain,
        "Authentication key-chain\n"
        "name of key-chain\n")
 {
-       struct cli_config_change changes[] = {
-               {
-                       .xpath = "./frr-ripd:rip/authentication-key-chain",
-                       .operation = NB_OP_DELETE,
-               },
-       };
-
-       return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
+       nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DELETE,
+                             NULL);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
 }
 
 void cli_show_ip_rip_authentication_key_chain(struct vty *vty,
@@ -1252,16 +980,13 @@ void rip_cli_init(void)
        install_element(RIP_NODE, &rip_distance_cmd);
        install_element(RIP_NODE, &no_rip_distance_cmd);
        install_element(RIP_NODE, &rip_distance_source_cmd);
-       install_element(RIP_NODE, &no_rip_distance_source_cmd);
        install_element(RIP_NODE, &rip_neighbor_cmd);
        install_element(RIP_NODE, &rip_network_prefix_cmd);
        install_element(RIP_NODE, &rip_network_if_cmd);
        install_element(RIP_NODE, &rip_offset_list_cmd);
-       install_element(RIP_NODE, &no_rip_offset_list_cmd);
        install_element(RIP_NODE, &rip_passive_default_cmd);
        install_element(RIP_NODE, &rip_passive_interface_cmd);
        install_element(RIP_NODE, &rip_redistribute_cmd);
-       install_element(RIP_NODE, &no_rip_redistribute_cmd);
        install_element(RIP_NODE, &rip_route_cmd);
        install_element(RIP_NODE, &rip_timers_cmd);
        install_element(RIP_NODE, &no_rip_timers_cmd);
index bb32409a2488d420747b57b9a993f1f3afdbce6e..d1e298c25cd568b28f7737fbb5841946f9ae2334 100644 (file)
@@ -188,7 +188,7 @@ static int ripd_instance_distance_source_delete(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rn = yang_dnode_get_entry(dnode);
+       rn = yang_dnode_get_entry(dnode, true);
        rdistance = rn->info;
        if (rdistance->access_list)
                free(rdistance->access_list);
@@ -216,7 +216,7 @@ ripd_instance_distance_source_distance_modify(enum nb_event event,
                return NB_OK;
 
        /* Set distance value. */
-       rn = yang_dnode_get_entry(dnode);
+       rn = yang_dnode_get_entry(dnode, true);
        distance = yang_dnode_get_uint8(dnode, NULL);
        rdistance = rn->info;
        rdistance->distance = distance;
@@ -242,7 +242,7 @@ ripd_instance_distance_source_access_list_modify(enum nb_event event,
        acl_name = yang_dnode_get_string(dnode, NULL);
 
        /* Set access-list */
-       rn = yang_dnode_get_entry(dnode);
+       rn = yang_dnode_get_entry(dnode, true);
        rdistance = rn->info;
        if (rdistance->access_list)
                free(rdistance->access_list);
@@ -262,7 +262,7 @@ ripd_instance_distance_source_access_list_delete(enum nb_event event,
                return NB_OK;
 
        /* Reset access-list configuration. */
-       rn = yang_dnode_get_entry(dnode);
+       rn = yang_dnode_get_entry(dnode, true);
        rdistance = rn->info;
        free(rdistance->access_list);
        rdistance->access_list = NULL;
@@ -396,7 +396,7 @@ static int ripd_instance_offset_list_delete(enum nb_event event,
 
        direct = yang_dnode_get_enum(dnode, "./direction");
 
-       offset = yang_dnode_get_entry(dnode);
+       offset = yang_dnode_get_entry(dnode, true);
        if (offset->direct[direct].alist_name) {
                free(offset->direct[direct].alist_name);
                offset->direct[direct].alist_name = NULL;
@@ -426,7 +426,7 @@ ripd_instance_offset_list_access_list_modify(enum nb_event event,
        direct = yang_dnode_get_enum(dnode, "../direction");
        alist_name = yang_dnode_get_string(dnode, NULL);
 
-       offset = yang_dnode_get_entry(dnode);
+       offset = yang_dnode_get_entry(dnode, true);
        if (offset->direct[direct].alist_name)
                free(offset->direct[direct].alist_name);
        offset->direct[direct].alist_name = strdup(alist_name);
@@ -451,7 +451,7 @@ static int ripd_instance_offset_list_metric_modify(enum nb_event event,
        direct = yang_dnode_get_enum(dnode, "../direction");
        metric = yang_dnode_get_uint8(dnode, NULL);
 
-       offset = yang_dnode_get_entry(dnode);
+       offset = yang_dnode_get_entry(dnode, true);
        offset->direct[direct].metric = metric;
 
        return NB_OK;
@@ -791,7 +791,7 @@ static int lib_interface_rip_split_horizon_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
 
@@ -811,7 +811,7 @@ static int lib_interface_rip_v2_broadcast_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        ri->v2_broadcast = yang_dnode_get_bool(dnode, NULL);
 
@@ -832,7 +832,7 @@ lib_interface_rip_version_receive_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        ri->ri_receive = yang_dnode_get_enum(dnode, NULL);
 
@@ -852,7 +852,7 @@ static int lib_interface_rip_version_send_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        ri->ri_send = yang_dnode_get_enum(dnode, NULL);
 
@@ -872,7 +872,7 @@ static int lib_interface_rip_authentication_scheme_mode_modify(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        ri->auth_type = yang_dnode_get_enum(dnode, NULL);
 
@@ -893,7 +893,7 @@ static int lib_interface_rip_authentication_scheme_md5_auth_length_modify(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        ri->md5_auth_len = yang_dnode_get_enum(dnode, NULL);
 
@@ -909,7 +909,7 @@ static int lib_interface_rip_authentication_scheme_md5_auth_length_delete(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        ri->md5_auth_len = yang_get_default_enum(
                "%s/authentication-scheme/md5-auth-length", RIP_IFACE);
@@ -931,7 +931,7 @@ lib_interface_rip_authentication_password_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        if (ri->auth_str)
                XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
@@ -951,7 +951,7 @@ lib_interface_rip_authentication_password_delete(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
 
@@ -972,7 +972,7 @@ lib_interface_rip_authentication_key_chain_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        if (ri->key_chain)
                XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
@@ -992,7 +992,7 @@ lib_interface_rip_authentication_key_chain_delete(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode);
+       ifp = yang_dnode_get_entry(dnode, true);
        ri = ifp->info;
        XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);