]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/northbound_cli.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / lib / northbound_cli.c
index a3006264f1945020606533342fc5d8fe1257ef11..acde0ead025ac47d62750a6baff0480a06995cd0 100644 (file)
@@ -36,6 +36,7 @@
 
 int debug_northbound;
 struct nb_config *vty_shared_candidate_config;
+static struct thread_master *master;
 
 static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx)
 {
@@ -70,7 +71,7 @@ void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
        }
 
        change = &vty->cfg_changes[vty->num_cfg_changes++];
-       change->xpath = xpath;
+       strlcpy(change->xpath, xpath, sizeof(change->xpath));
        change->operation = operation;
        change->value = value;
 }
@@ -213,16 +214,80 @@ int nb_cli_rpc(const char *xpath, struct list *input, struct list *output)
        }
 }
 
-static int nb_cli_commit(struct vty *vty, bool force, char *comment)
+void nb_cli_confirmed_commit_clean(struct vty *vty)
+{
+       THREAD_TIMER_OFF(vty->t_confirmed_commit_timeout);
+       nb_config_free(vty->confirmed_commit_rollback);
+       vty->confirmed_commit_rollback = NULL;
+}
+
+int nb_cli_confirmed_commit_rollback(struct vty *vty)
 {
        uint32_t transaction_id;
        int ret;
 
+       /* Perform the rollback. */
+       ret = nb_candidate_commit(
+               vty->confirmed_commit_rollback, NB_CLIENT_CLI, true,
+               "Rollback to previous configuration - confirmed commit has timed out",
+               &transaction_id);
+       if (ret == NB_OK)
+               vty_out(vty,
+                       "Rollback performed successfully (Transaction ID #%u).\n",
+                       transaction_id);
+       else
+               vty_out(vty, "Failed to rollback to previous configuration.\n");
+
+       return ret;
+}
+
+static int nb_cli_confirmed_commit_timeout(struct thread *thread)
+{
+       struct vty *vty = THREAD_ARG(thread);
+
+       /* XXX: broadcast this message to all logged-in users? */
+       vty_out(vty,
+               "\nConfirmed commit has timed out, rolling back to previous configuration.\n\n");
+
+       nb_cli_confirmed_commit_rollback(vty);
+       nb_cli_confirmed_commit_clean(vty);
+
+       return 0;
+}
+
+static int nb_cli_commit(struct vty *vty, bool force,
+                        unsigned int confirmed_timeout, char *comment)
+{
+       uint32_t transaction_id;
+       int ret;
+
+       /* Check if there's a pending confirmed commit. */
+       if (vty->t_confirmed_commit_timeout) {
+               if (confirmed_timeout) {
+                       /* Reset timeout if "commit confirmed" is used again. */
+                       vty_out(vty,
+                               "%% Resetting confirmed-commit timeout to %u minute(s)\n\n",
+                               confirmed_timeout);
+
+                       THREAD_TIMER_OFF(vty->t_confirmed_commit_timeout);
+                       thread_add_timer(master,
+                                        nb_cli_confirmed_commit_timeout, vty,
+                                        confirmed_timeout * 60,
+                                        &vty->t_confirmed_commit_timeout);
+               } else {
+                       /* Accept commit confirmation. */
+                       vty_out(vty, "%% Commit complete.\n\n");
+                       nb_cli_confirmed_commit_clean(vty);
+               }
+               return CMD_SUCCESS;
+       }
+
        if (vty_exclusive_lock != NULL && vty_exclusive_lock != vty) {
                vty_out(vty, "%% Configuration is locked by another VTY.\n\n");
                return CMD_WARNING;
        }
 
+       /* "force" parameter. */
        if (!force && nb_candidate_needs_update(vty->candidate_config)) {
                vty_out(vty,
                        "%% Candidate configuration needs to be updated before commit.\n\n");
@@ -231,6 +296,16 @@ static int nb_cli_commit(struct vty *vty, bool force, char *comment)
                return CMD_WARNING;
        }
 
+       /* "confirm" parameter. */
+       if (confirmed_timeout) {
+               vty->confirmed_commit_rollback = nb_config_dup(running_config);
+
+               vty->t_confirmed_commit_timeout = NULL;
+               thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
+                                confirmed_timeout * 60,
+                                &vty->t_confirmed_commit_timeout);
+       }
+
        ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, true,
                                  comment, &transaction_id);
 
@@ -519,20 +594,7 @@ DEFUN (config_exclusive,
        "Configuration from vty interface\n"
        "Configure exclusively from this terminal\n")
 {
-       if (vty_config_exclusive_lock(vty))
-               vty->node = CONFIG_NODE;
-       else {
-               vty_out(vty, "VTY configuration is locked by other VTY\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       vty->private_config = true;
-       vty->candidate_config = nb_config_dup(running_config);
-       vty->candidate_config_base = nb_config_dup(running_config);
-       vty_out(vty,
-               "Warning: uncommitted changes will be discarded on exit.\n\n");
-
-       return CMD_SUCCESS;
+       return vty_config_enter(vty, true, true);
 }
 
 /* Configure using a private candidate configuration. */
@@ -542,36 +604,27 @@ DEFUN (config_private,
        "Configuration from vty interface\n"
        "Configure using a private candidate configuration\n")
 {
-       if (vty_config_lock(vty))
-               vty->node = CONFIG_NODE;
-       else {
-               vty_out(vty, "VTY configuration is locked by other VTY\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       vty->private_config = true;
-       vty->candidate_config = nb_config_dup(running_config);
-       vty->candidate_config_base = nb_config_dup(running_config);
-       vty_out(vty,
-               "Warning: uncommitted changes will be discarded on exit.\n\n");
-
-       return CMD_SUCCESS;
+       return vty_config_enter(vty, true, false);
 }
 
 DEFPY (config_commit,
        config_commit_cmd,
-       "commit [force$force]",
+       "commit [{force$force|confirmed (1-60)}]",
        "Commit changes into the running configuration\n"
-       "Force commit even if the candidate is outdated\n")
+       "Force commit even if the candidate is outdated\n"
+       "Rollback this commit unless there is a confirming commit\n"
+       "Timeout in minutes for the commit to be confirmed\n")
 {
-       return nb_cli_commit(vty, !!force, NULL);
+       return nb_cli_commit(vty, !!force, confirmed, NULL);
 }
 
 DEFPY (config_commit_comment,
        config_commit_comment_cmd,
-       "commit [force$force] comment LINE...",
+       "commit [{force$force|confirmed (1-60)}] comment LINE...",
        "Commit changes into the running configuration\n"
        "Force commit even if the candidate is outdated\n"
+       "Rollback this commit unless there is a confirming commit\n"
+       "Timeout in minutes for the commit to be confirmed\n"
        "Assign a comment to this commit\n"
        "Comment for this commit (Max 80 characters)\n")
 {
@@ -581,7 +634,7 @@ DEFPY (config_commit_comment,
 
        argv_find(argv, argc, "LINE", &idx);
        comment = argv_concat(argv, argc, idx);
-       ret = nb_cli_commit(vty, !!force, comment);
+       ret = nb_cli_commit(vty, !!force, confirmed, comment);
        XFREE(MTYPE_TMP, comment);
 
        return ret;
@@ -780,6 +833,30 @@ DEFPY (show_config_candidate,
        return CMD_SUCCESS;
 }
 
+DEFPY (show_config_candidate_section,
+       show_config_candidate_section_cmd,
+       "show",
+       SHOW_STR)
+{
+       struct lyd_node *dnode;
+
+       /* Top-level configuration node, display everything. */
+       if (vty->xpath_index == 0)
+               return nb_cli_show_config(vty, vty->candidate_config,
+                                         NB_CFG_FMT_CMDS, NULL, false);
+
+       /* Display only the current section of the candidate configuration. */
+       dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+       if (!dnode)
+               /* Shouldn't happen. */
+               return CMD_WARNING;
+
+       nb_cli_show_dnode_cmds(vty, dnode, 0);
+       vty_out(vty, "!\n");
+
+       return CMD_SUCCESS;
+}
+
 DEFPY (show_config_compare,
        show_config_compare_cmd,
        "show configuration compare\
@@ -1494,6 +1571,8 @@ static struct cmd_node nb_debug_node = {NORTHBOUND_DEBUG_NODE, "", 1};
 
 void nb_cli_install_default(int node)
 {
+       install_element(node, &show_config_candidate_section_cmd);
+
        if (frr_get_cli_mode() != FRR_CLI_TRANSACTIONAL)
                return;
 
@@ -1543,8 +1622,10 @@ static const struct cmd_variable_handler yang_var_handlers[] = {
         .completions = yang_translator_autocomplete},
        {.completions = NULL}};
 
-void nb_cli_init(void)
+void nb_cli_init(struct thread_master *tm)
 {
+       master = tm;
+
        /* Initialize the shared candidate configuration. */
        vty_shared_candidate_config = nb_config_new(NULL);