mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 11:25:41 +00:00
Merge pull request #3442 from opensourcerouting/confirmed-commits
lib: add support for confirmed commits
This commit is contained in:
commit
64b81b3a64
@ -653,7 +653,7 @@ struct thread_master *frr_init(void)
|
|||||||
lib_error_init();
|
lib_error_init();
|
||||||
|
|
||||||
yang_init();
|
yang_init();
|
||||||
nb_init(di->yang_modules, di->n_yang_modules);
|
nb_init(master, di->yang_modules, di->n_yang_modules);
|
||||||
|
|
||||||
return master;
|
return master;
|
||||||
}
|
}
|
||||||
|
@ -1539,7 +1539,8 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nb_init(const struct frr_yang_module_info *modules[], size_t nmodules)
|
void nb_init(struct thread_master *tm,
|
||||||
|
const struct frr_yang_module_info *modules[], size_t nmodules)
|
||||||
{
|
{
|
||||||
unsigned int errors = 0;
|
unsigned int errors = 0;
|
||||||
|
|
||||||
@ -1574,7 +1575,7 @@ void nb_init(const struct frr_yang_module_info *modules[], size_t nmodules)
|
|||||||
running_config = nb_config_new(NULL);
|
running_config = nb_config_new(NULL);
|
||||||
|
|
||||||
/* Initialize the northbound CLI. */
|
/* Initialize the northbound CLI. */
|
||||||
nb_cli_init();
|
nb_cli_init(tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nb_terminate(void)
|
void nb_terminate(void)
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#ifndef _FRR_NORTHBOUND_H_
|
#ifndef _FRR_NORTHBOUND_H_
|
||||||
#define _FRR_NORTHBOUND_H_
|
#define _FRR_NORTHBOUND_H_
|
||||||
|
|
||||||
|
#include "thread.h"
|
||||||
#include "hook.h"
|
#include "hook.h"
|
||||||
#include "linklist.h"
|
#include "linklist.h"
|
||||||
#include "openbsd-tree.h"
|
#include "openbsd-tree.h"
|
||||||
@ -825,7 +826,7 @@ extern const char *nb_client_name(enum nb_client client);
|
|||||||
* nmodules
|
* nmodules
|
||||||
* Size of the modules array.
|
* Size of the modules array.
|
||||||
*/
|
*/
|
||||||
extern void nb_init(const struct frr_yang_module_info *modules[],
|
extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info *modules[],
|
||||||
size_t nmodules);
|
size_t nmodules);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
int debug_northbound;
|
int debug_northbound;
|
||||||
struct nb_config *vty_shared_candidate_config;
|
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)
|
static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx)
|
||||||
{
|
{
|
||||||
@ -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;
|
uint32_t transaction_id;
|
||||||
int ret;
|
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) {
|
if (vty_exclusive_lock != NULL && vty_exclusive_lock != vty) {
|
||||||
vty_out(vty, "%% Configuration is locked by another VTY.\n\n");
|
vty_out(vty, "%% Configuration is locked by another VTY.\n\n");
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* "force" parameter. */
|
||||||
if (!force && nb_candidate_needs_update(vty->candidate_config)) {
|
if (!force && nb_candidate_needs_update(vty->candidate_config)) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"%% Candidate configuration needs to be updated before commit.\n\n");
|
"%% 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;
|
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,
|
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, true,
|
||||||
comment, &transaction_id);
|
comment, &transaction_id);
|
||||||
|
|
||||||
@ -534,18 +609,22 @@ DEFUN (config_private,
|
|||||||
|
|
||||||
DEFPY (config_commit,
|
DEFPY (config_commit,
|
||||||
config_commit_cmd,
|
config_commit_cmd,
|
||||||
"commit [force$force]",
|
"commit [{force$force|confirmed (1-60)}]",
|
||||||
"Commit changes into the running configuration\n"
|
"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,
|
DEFPY (config_commit_comment,
|
||||||
config_commit_comment_cmd,
|
config_commit_comment_cmd,
|
||||||
"commit [force$force] comment LINE...",
|
"commit [{force$force|confirmed (1-60)}] comment LINE...",
|
||||||
"Commit changes into the running configuration\n"
|
"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"
|
||||||
"Assign a comment to this commit\n"
|
"Assign a comment to this commit\n"
|
||||||
"Comment for this commit (Max 80 characters)\n")
|
"Comment for this commit (Max 80 characters)\n")
|
||||||
{
|
{
|
||||||
@ -555,7 +634,7 @@ DEFPY (config_commit_comment,
|
|||||||
|
|
||||||
argv_find(argv, argc, "LINE", &idx);
|
argv_find(argv, argc, "LINE", &idx);
|
||||||
comment = argv_concat(argv, argc, 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);
|
XFREE(MTYPE_TMP, comment);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1543,8 +1622,10 @@ static const struct cmd_variable_handler yang_var_handlers[] = {
|
|||||||
.completions = yang_translator_autocomplete},
|
.completions = yang_translator_autocomplete},
|
||||||
{.completions = NULL}};
|
{.completions = NULL}};
|
||||||
|
|
||||||
void nb_cli_init(void)
|
void nb_cli_init(struct thread_master *tm)
|
||||||
{
|
{
|
||||||
|
master = tm;
|
||||||
|
|
||||||
/* Initialize the shared candidate configuration. */
|
/* Initialize the shared candidate configuration. */
|
||||||
vty_shared_candidate_config = nb_config_new(NULL);
|
vty_shared_candidate_config = nb_config_new(NULL);
|
||||||
|
|
||||||
|
@ -105,8 +105,10 @@ extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode,
|
|||||||
bool show_defaults);
|
bool show_defaults);
|
||||||
|
|
||||||
/* Prototypes of internal functions. */
|
/* Prototypes of internal functions. */
|
||||||
|
extern void nb_cli_confirmed_commit_clean(struct vty *vty);
|
||||||
|
extern int nb_cli_confirmed_commit_rollback(struct vty *vty);
|
||||||
extern void nb_cli_install_default(int node);
|
extern void nb_cli_install_default(int node);
|
||||||
extern void nb_cli_init(void);
|
extern void nb_cli_init(struct thread_master *tm);
|
||||||
extern void nb_cli_terminate(void);
|
extern void nb_cli_terminate(void);
|
||||||
|
|
||||||
#endif /* _FRR_NORTHBOUND_CLI_H_ */
|
#endif /* _FRR_NORTHBOUND_CLI_H_ */
|
||||||
|
@ -2714,6 +2714,14 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
|
|||||||
|
|
||||||
void vty_config_exit(struct vty *vty)
|
void vty_config_exit(struct vty *vty)
|
||||||
{
|
{
|
||||||
|
/* Check if there's a pending confirmed commit. */
|
||||||
|
if (vty->t_confirmed_commit_timeout) {
|
||||||
|
vty_out(vty,
|
||||||
|
"WARNING: exiting with a pending confirmed commit. Rolling back to previous configuration.\n\n");
|
||||||
|
nb_cli_confirmed_commit_rollback(vty);
|
||||||
|
nb_cli_confirmed_commit_clean(vty);
|
||||||
|
}
|
||||||
|
|
||||||
vty_config_exclusive_unlock(vty);
|
vty_config_exclusive_unlock(vty);
|
||||||
|
|
||||||
if (vty->candidate_config) {
|
if (vty->candidate_config) {
|
||||||
|
@ -126,6 +126,10 @@ struct vty {
|
|||||||
/* Base candidate configuration. */
|
/* Base candidate configuration. */
|
||||||
struct nb_config *candidate_config_base;
|
struct nb_config *candidate_config_base;
|
||||||
|
|
||||||
|
/* Confirmed-commit timeout and rollback configuration. */
|
||||||
|
struct thread *t_confirmed_commit_timeout;
|
||||||
|
struct nb_config *confirmed_commit_rollback;
|
||||||
|
|
||||||
/* qobj object ID (replacement for "index") */
|
/* qobj object ID (replacement for "index") */
|
||||||
uint64_t qobj_index;
|
uint64_t qobj_index;
|
||||||
|
|
||||||
|
@ -1384,10 +1384,10 @@ static void bgp_startup(void)
|
|||||||
LOG_DAEMON);
|
LOG_DAEMON);
|
||||||
zprivs_preinit(&bgpd_privs);
|
zprivs_preinit(&bgpd_privs);
|
||||||
zprivs_init(&bgpd_privs);
|
zprivs_init(&bgpd_privs);
|
||||||
yang_init();
|
|
||||||
nb_init(NULL, 0);
|
|
||||||
|
|
||||||
master = thread_master_create(NULL);
|
master = thread_master_create(NULL);
|
||||||
|
yang_init();
|
||||||
|
nb_init(master, NULL, 0);
|
||||||
bgp_master_init(master);
|
bgp_master_init(master);
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
||||||
|
@ -156,7 +156,7 @@ int main(int argc, char **argv)
|
|||||||
vty_init(master);
|
vty_init(master);
|
||||||
memory_init();
|
memory_init();
|
||||||
yang_init();
|
yang_init();
|
||||||
nb_init(NULL, 0);
|
nb_init(master, NULL, 0);
|
||||||
|
|
||||||
/* OSPF vty inits. */
|
/* OSPF vty inits. */
|
||||||
test_vty_init();
|
test_vty_init();
|
||||||
|
@ -84,7 +84,7 @@ int main(int argc, char **argv)
|
|||||||
vty_init(master);
|
vty_init(master);
|
||||||
memory_init();
|
memory_init();
|
||||||
yang_init();
|
yang_init();
|
||||||
nb_init(NULL, 0);
|
nb_init(master, NULL, 0);
|
||||||
|
|
||||||
test_init(argc, argv);
|
test_init(argc, argv);
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ static void test_init(void)
|
|||||||
|
|
||||||
cmd_init(1);
|
cmd_init(1);
|
||||||
yang_init();
|
yang_init();
|
||||||
nb_init(NULL, 0);
|
nb_init(master, NULL, 0);
|
||||||
|
|
||||||
install_node(&bgp_node, NULL);
|
install_node(&bgp_node, NULL);
|
||||||
install_node(&rip_node, NULL);
|
install_node(&rip_node, NULL);
|
||||||
|
@ -449,7 +449,7 @@ int main(int argc, char **argv)
|
|||||||
vty_init(master);
|
vty_init(master);
|
||||||
memory_init();
|
memory_init();
|
||||||
yang_init();
|
yang_init();
|
||||||
nb_init(modules, array_size(modules));
|
nb_init(master, modules, array_size(modules));
|
||||||
|
|
||||||
/* Create artificial data. */
|
/* Create artificial data. */
|
||||||
create_data(num_vrfs, num_interfaces, num_routes);
|
create_data(num_vrfs, num_interfaces, num_routes);
|
||||||
|
Loading…
Reference in New Issue
Block a user