diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/command.c | 7 | ||||
| -rw-r--r-- | lib/command.h | 21 | ||||
| -rw-r--r-- | lib/command_graph.h | 1 | ||||
| -rw-r--r-- | lib/defun_lex.l | 2 | ||||
| -rw-r--r-- | lib/filter_cli.c | 62 | ||||
| -rw-r--r-- | lib/if.c | 9 | ||||
| -rw-r--r-- | lib/ipaddr.h | 7 | ||||
| -rw-r--r-- | lib/northbound_cli.c | 132 | ||||
| -rw-r--r-- | lib/northbound_cli.h | 8 | ||||
| -rw-r--r-- | lib/routemap_cli.c | 87 | ||||
| -rw-r--r-- | lib/vrf.c | 5 | ||||
| -rw-r--r-- | lib/vty.c | 3 | ||||
| -rw-r--r-- | lib/vty.h | 8 |
13 files changed, 253 insertions, 99 deletions
diff --git a/lib/command.c b/lib/command.c index 80b75d9b23..159ed07b38 100644 --- a/lib/command.c +++ b/lib/command.c @@ -904,6 +904,13 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, > vty->candidate_config->version) nb_config_replace(vty->candidate_config, running_config, true); + + /* + * Perform pending commit (if any) before executing + * non-YANG command. + */ + if (matched_element->attr != CMD_ATTR_YANG) + nb_cli_pending_commit_check(vty); } ret = matched_element->func(matched_element, vty, argc, argv); diff --git a/lib/command.h b/lib/command.h index 1acca90665..a7a2eaf868 100644 --- a/lib/command.h +++ b/lib/command.h @@ -257,6 +257,12 @@ struct cmd_node { #define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) +#define DEFPY_YANG(funcname, cmdname, cmdstr, helpstr) \ + DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) + +#define DEFPY_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFPY_YANG(funcname, cmdname, cmdstr, helpstr) + #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ @@ -270,10 +276,16 @@ struct cmd_node { #define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) +#define DEFUN_YANG(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) + /* DEFUN_NOSH for commands that vtysh should ignore */ #define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ DEFUN(funcname, cmdname, cmdstr, helpstr) +#define DEFUN_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_YANG(funcname, cmdname, cmdstr, helpstr) + /* DEFSH for vtysh. */ #define DEFSH(daemon, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) @@ -282,6 +294,9 @@ struct cmd_node { DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, \ daemon) +#define DEFSH_YANG(daemon, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, daemon) + /* DEFUN + DEFSH */ #define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_FUNC_DECL(funcname) \ @@ -302,6 +317,9 @@ struct cmd_node { DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, \ CMD_ATTR_DEPRECATED) +#define DEFUNSH_YANG(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) + /* ALIAS macro which define existing command's alias. */ #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) @@ -317,6 +335,9 @@ struct cmd_node { DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \ CMD_ATTR_DEPRECATED, 0) +#define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, 0) + #define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) diff --git a/lib/command_graph.h b/lib/command_graph.h index 1efe8b1803..179e104a57 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -74,6 +74,7 @@ enum cmd_token_type { enum { CMD_ATTR_NORMAL, CMD_ATTR_DEPRECATED, CMD_ATTR_HIDDEN, + CMD_ATTR_YANG, }; /* Comamand token struct. */ diff --git a/lib/defun_lex.l b/lib/defun_lex.l index 19b06f51b8..bc5fbd24d9 100644 --- a/lib/defun_lex.l +++ b/lib/defun_lex.l @@ -140,6 +140,8 @@ SPECIAL [(),] "DEFPY_NOSH" value = strdup(yytext); return DEFUNNY; "DEFPY_ATTR" value = strdup(yytext); return DEFUNNY; "DEFPY_HIDDEN" value = strdup(yytext); return DEFUNNY; +"DEFPY_YANG" value = strdup(yytext); return DEFUNNY; +"DEFPY_YANG_NOSH" value = strdup(yytext); return DEFUNNY; "ALIAS" value = strdup(yytext); return DEFUNNY; "ALIAS_HIDDEN" value = strdup(yytext); return DEFUNNY; "install_element" value = strdup(yytext); return INSTALL; diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 030039b3fe..8c7a515dc5 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -169,7 +169,7 @@ static long acl_get_seq(struct vty *vty, const char *xpath) /* * Cisco (legacy) access lists. */ -DEFPY( +DEFPY_YANG( access_list_std, access_list_std_cmd, "access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>", ACCESS_LIST_STR @@ -220,7 +220,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_access_list_std, no_access_list_std_cmd, "no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>", NO_STR @@ -280,7 +280,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( access_list_ext, access_list_ext_cmd, "access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", ACCESS_LIST_STR @@ -351,7 +351,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_access_list_ext, no_access_list_ext_cmd, "no access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", NO_STR @@ -436,7 +436,7 @@ DEFPY( /* * Zebra access lists. */ -DEFPY( +DEFPY_YANG( access_list, access_list_cmd, "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>", ACCESS_LIST_STR @@ -482,7 +482,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_access_list, no_access_list_cmd, "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>", NO_STR @@ -539,7 +539,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_access_list_all, no_access_list_all_cmd, "no access-list WORD$name", NO_STR @@ -555,7 +555,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( access_list_remark, access_list_remark_cmd, "access-list WORD$name remark LINE...", ACCESS_LIST_STR @@ -579,7 +579,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_access_list_remark, no_access_list_remark_cmd, "no access-list WORD$name remark", NO_STR @@ -606,7 +606,7 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -DEFPY( +DEFPY_YANG( ipv6_access_list, ipv6_access_list_cmd, "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>", IPV6_STR @@ -653,7 +653,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_ipv6_access_list, no_ipv6_access_list_cmd, "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>", NO_STR @@ -711,7 +711,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_ipv6_access_list_all, no_ipv6_access_list_all_cmd, "no ipv6 access-list WORD$name", NO_STR @@ -728,7 +728,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( ipv6_access_list_remark, ipv6_access_list_remark_cmd, "ipv6 access-list WORD$name remark LINE...", IPV6_STR @@ -753,7 +753,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_ipv6_access_list_remark, no_ipv6_access_list_remark_cmd, "no ipv6 access-list WORD$name remark", NO_STR @@ -782,7 +782,7 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -DEFPY( +DEFPY_YANG( mac_access_list, mac_access_list_cmd, "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", MAC_STR @@ -825,7 +825,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_mac_access_list, no_mac_access_list_cmd, "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$prefix|any>", NO_STR @@ -882,7 +882,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_mac_access_list_all, no_mac_access_list_all_cmd, "no mac access-list WORD$name", NO_STR @@ -899,7 +899,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( mac_access_list_remark, mac_access_list_remark_cmd, "mac access-list WORD$name remark LINE...", MAC_STR @@ -924,7 +924,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_mac_access_list_remark, no_mac_access_list_remark_cmd, "no mac access-list WORD$name remark", NO_STR @@ -1182,7 +1182,7 @@ static int plist_remove(struct vty *vty, const char *iptype, const char *name, return rv; } -DEFPY( +DEFPY_YANG( ip_prefix_list, ip_prefix_list_cmd, "ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)$ge|le (0-32)$le}]>", IP_STR @@ -1239,7 +1239,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_ip_prefix_list, no_ip_prefix_list_cmd, "no ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)|le (0-32)}]>", NO_STR @@ -1259,7 +1259,7 @@ DEFPY( (struct prefix *)prefix, ge, le); } -DEFPY( +DEFPY_YANG( no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd, "no ip prefix-list WORD$name seq (1-4294967295)$seq", NO_STR @@ -1271,7 +1271,7 @@ DEFPY( return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0); } -DEFPY( +DEFPY_YANG( no_ip_prefix_list_all, no_ip_prefix_list_all_cmd, "no ip prefix-list WORD$name", NO_STR @@ -1288,7 +1288,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( ip_prefix_list_remark, ip_prefix_list_remark_cmd, "ip prefix-list WORD$name description LINE...", IP_STR @@ -1313,7 +1313,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd, "no ip prefix-list WORD$name description", NO_STR @@ -1342,7 +1342,7 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -DEFPY( +DEFPY_YANG( ipv6_prefix_list, ipv6_prefix_list_cmd, "ipv6 prefix-list WORD$name [seq (1-4294967295)] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>", IPV6_STR @@ -1399,7 +1399,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list, no_ipv6_prefix_list_cmd, "no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>", NO_STR @@ -1419,7 +1419,7 @@ DEFPY( (struct prefix *)prefix, ge, le); } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list_seq, no_ipv6_prefix_list_seq_cmd, "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq", NO_STR @@ -1431,7 +1431,7 @@ DEFPY( return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0); } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list_all, no_ipv6_prefix_list_all_cmd, "no ipv6 prefix-list WORD$name", NO_STR @@ -1448,7 +1448,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( ipv6_prefix_list_remark, ipv6_prefix_list_remark_cmd, "ipv6 prefix-list WORD$name description LINE...", IPV6_STR @@ -1473,7 +1473,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd, "no ipv6 prefix-list WORD$name description", NO_STR @@ -1321,7 +1321,7 @@ void if_link_params_free(struct interface *ifp) /* * XPath: /frr-interface:lib/interface */ -DEFPY_NOSH (interface, +DEFPY_YANG_NOSH (interface, interface_cmd, "interface IFNAME [vrf NAME$vrf_name]", "Select an interface to configure\n" @@ -1384,6 +1384,7 @@ DEFPY_NOSH (interface, * all interface-level commands are converted to the new * northbound model. */ + nb_cli_pending_commit_check(vty); ifp = if_lookup_by_name(ifname, vrf_id); if (ifp) VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp); @@ -1392,7 +1393,7 @@ DEFPY_NOSH (interface, return ret; } -DEFPY (no_interface, +DEFPY_YANG (no_interface, no_interface_cmd, "no interface IFNAME [vrf NAME$vrf_name]", NO_STR @@ -1427,7 +1428,7 @@ static void cli_show_interface(struct vty *vty, struct lyd_node *dnode, /* * XPath: /frr-interface:lib/interface/description */ -DEFPY (interface_desc, +DEFPY_YANG (interface_desc, interface_desc_cmd, "description LINE...", "Interface specific description\n" @@ -1444,7 +1445,7 @@ DEFPY (interface_desc, return ret; } -DEFPY (no_interface_desc, +DEFPY_YANG (no_interface_desc, no_interface_desc_cmd, "no description", NO_STR diff --git a/lib/ipaddr.h b/lib/ipaddr.h index a96c9788bc..f2b75c1306 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -89,6 +89,13 @@ static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size) return buf; } +#define IS_MAPPED_IPV6(A) \ + ((A)->s6_addr32[0] == 0x00000000 \ + ? ((A)->s6_addr32[1] == 0x00000000 \ + ? (ntohl((A)->s6_addr32[2]) == 0xFFFF ? 1 : 0) \ + : 0) \ + : 0) + /* * Convert IPv4 address to IPv4-mapped IPv6 address which is of the * form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 105fc83cef..534b5128ee 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -53,6 +53,106 @@ static void vty_show_nb_errors(struct vty *vty, int error, const char *errmsg) vty_out(vty, "Error description: %s\n", errmsg); } +static int nb_cli_classic_commit(struct vty *vty) +{ + struct nb_context context = {}; + char errmsg[BUFSIZ] = {0}; + int ret; + + context.client = NB_CLIENT_CLI; + context.user = vty; + ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL, + NULL, errmsg, sizeof(errmsg)); + if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { + vty_out(vty, "%% Configuration failed.\n\n"); + vty_show_nb_errors(vty, ret, errmsg); + if (vty->t_pending_commit) + vty_out(vty, + "The following commands were dynamically grouped into the same transaction and rejected:\n%s", + vty->pending_cmds_buf); + + /* Regenerate candidate for consistency. */ + nb_config_replace(vty->candidate_config, running_config, true); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +static void nb_cli_pending_commit_clear(struct vty *vty) +{ + THREAD_TIMER_OFF(vty->t_pending_commit); + vty->backoff_cmd_count = 0; + XFREE(MTYPE_TMP, vty->pending_cmds_buf); + vty->pending_cmds_buflen = 0; + vty->pending_cmds_bufpos = 0; +} + +static int nb_cli_pending_commit_cb(struct thread *thread) +{ + struct vty *vty = THREAD_ARG(thread); + + (void)nb_cli_classic_commit(vty); + nb_cli_pending_commit_clear(vty); + + return 0; +} + +void nb_cli_pending_commit_check(struct vty *vty) +{ + if (vty->t_pending_commit) { + (void)nb_cli_classic_commit(vty); + nb_cli_pending_commit_clear(vty); + } +} + +static bool nb_cli_backoff_start(struct vty *vty) +{ + struct timeval now, delta; + + /* + * Start the configuration backoff timer only if 100 YANG-modeled + * commands or more were entered within the last second. + */ + monotime(&now); + if (monotime_since(&vty->backoff_start, &delta) >= 1000000) { + vty->backoff_start = now; + vty->backoff_cmd_count = 1; + return false; + } + if (++vty->backoff_cmd_count < 100) + return false; + + return true; +} + +static int nb_cli_schedule_command(struct vty *vty) +{ + /* Append command to dynamically sized buffer of scheduled commands. */ + if (!vty->pending_cmds_buf) { + vty->pending_cmds_buflen = 4096; + vty->pending_cmds_buf = + XCALLOC(MTYPE_TMP, vty->pending_cmds_buflen); + } + if ((strlen(vty->buf) + 3) + > (vty->pending_cmds_buflen - vty->pending_cmds_bufpos)) { + vty->pending_cmds_buflen *= 2; + vty->pending_cmds_buf = + XREALLOC(MTYPE_TMP, vty->pending_cmds_buf, + vty->pending_cmds_buflen); + } + strlcat(vty->pending_cmds_buf, "- ", vty->pending_cmds_buflen); + vty->pending_cmds_bufpos = strlcat(vty->pending_cmds_buf, vty->buf, + vty->pending_cmds_buflen); + + /* Schedule the commit operation. */ + THREAD_TIMER_OFF(vty->t_pending_commit); + thread_add_timer_msec(master, nb_cli_pending_commit_cb, vty, 100, + &vty->t_pending_commit); + + return CMD_SUCCESS; +} + void nb_cli_enqueue_change(struct vty *vty, const char *xpath, enum nb_operation operation, const char *value) { @@ -76,7 +176,6 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) { char xpath_base[XPATH_MAXLEN] = {}; bool error = false; - int ret; VTY_CHECK_XPATH; @@ -95,6 +194,7 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) struct nb_node *nb_node; char xpath[XPATH_MAXLEN]; struct yang_data *data; + int ret; /* Handle relative XPaths. */ memset(xpath, 0, sizeof(xpath)); @@ -158,25 +258,19 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) yang_print_errors(ly_native_ctx, buf, sizeof(buf))); } - /* Do an implicit "commit" when using the classic CLI mode. */ + /* + * Do an implicit commit when using the classic CLI mode. + * + * NOTE: the implicit commit might be scheduled to run later when + * too many commands are being sent at the same time. This is a + * protection mechanism where multiple commands are grouped into the + * same configuration transaction, allowing them to be processed much + * faster. + */ if (frr_get_cli_mode() == FRR_CLI_CLASSIC) { - struct nb_context context = {}; - char errmsg[BUFSIZ] = {0}; - - context.client = NB_CLIENT_CLI; - context.user = vty; - ret = nb_candidate_commit(&context, vty->candidate_config, - false, NULL, NULL, errmsg, - sizeof(errmsg)); - if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { - vty_out(vty, "%% Configuration failed.\n\n"); - vty_show_nb_errors(vty, ret, errmsg); - - /* Regenerate candidate for consistency. */ - nb_config_replace(vty->candidate_config, running_config, - true); - return CMD_WARNING_CONFIG_FAILED; - } + if (vty->t_pending_commit || nb_cli_backoff_start(vty)) + return nb_cli_schedule_command(vty); + return nb_cli_classic_commit(vty); } return CMD_SUCCESS; diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index b2d8c8f035..112d62efda 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -108,6 +108,14 @@ extern int nb_cli_rpc(const char *xpath, struct list *input, extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +/* + * Perform pending commit, if any. + * + * vty + * The vty context. + */ +extern void nb_cli_pending_commit_check(struct vty *vty); + /* Prototypes of internal functions. */ extern void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults); diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 10a958abed..7fa759252b 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -39,7 +39,7 @@ #define ROUTE_MAP_SEQUENCE_CMD_STR \ "Sequence to insert to/delete from existing route-map entry\n" -DEFPY_NOSH( +DEFPY_YANG_NOSH( route_map, route_map_cmd, "route-map WORD$name <deny|permit>$action (1-65535)$sequence", ROUTE_MAP_CMD_STR @@ -70,6 +70,7 @@ DEFPY_NOSH( VTY_PUSH_XPATH(RMAP_NODE, xpath_index); /* Add support for non-migrated route map users. */ + nb_cli_pending_commit_check(vty); rm = route_map_get(name); action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY; rmi = route_map_index_get(rm, action_type, sequence); @@ -79,7 +80,7 @@ DEFPY_NOSH( return rv; } -DEFPY( +DEFPY_YANG( no_route_map_all, no_route_map_all_cmd, "no route-map WORD$name", NO_STR @@ -94,7 +95,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_route_map, no_route_map_cmd, "no route-map WORD$name <deny|permit>$action (1-65535)$sequence", NO_STR @@ -179,7 +180,7 @@ void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) vty_out(vty, "!\n"); } -DEFPY( +DEFPY_YANG( match_interface, match_interface_cmd, "match interface IFNAME", MATCH_STR @@ -196,7 +197,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_interface, no_match_interface_cmd, "no match interface [IFNAME]", NO_STR @@ -211,7 +212,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_address, match_ip_address_cmd, "match ip address <(1-199)|(1300-2699)|WORD>$name", MATCH_STR @@ -231,7 +232,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_address, no_match_ip_address_cmd, "no match ip address [<(1-199)|(1300-2699)|WORD>]", NO_STR @@ -249,7 +250,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, "match ip address prefix-list WORD$name", @@ -269,7 +270,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, "no match ip address prefix-list [WORD]", NO_STR @@ -286,7 +287,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_next_hop, match_ip_next_hop_cmd, "match ip next-hop <(1-199)|(1300-2699)|WORD>$name", MATCH_STR @@ -306,7 +307,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_next_hop, no_match_ip_next_hop_cmd, "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]", NO_STR @@ -324,7 +325,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, "match ip next-hop prefix-list WORD$name", @@ -345,7 +346,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, "no match ip next-hop prefix-list [WORD]", @@ -364,7 +365,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_next_hop_type, match_ip_next_hop_type_cmd, "match ip next-hop type <blackhole>$type", MATCH_STR @@ -384,7 +385,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd, "no match ip next-hop type [<blackhole>]", NO_STR MATCH_STR IP_STR @@ -399,7 +400,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ipv6_address, match_ipv6_address_cmd, "match ipv6 address WORD$name", MATCH_STR @@ -417,7 +418,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ipv6_address, no_match_ipv6_address_cmd, "no match ipv6 address [WORD]", NO_STR @@ -433,7 +434,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, "match ipv6 address prefix-list WORD$name", MATCH_STR @@ -452,7 +453,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ipv6_address_prefix_list, no_match_ipv6_address_prefix_list_cmd, "no match ipv6 address prefix-list [WORD]", @@ -470,7 +471,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, "match ipv6 next-hop type <blackhole>$type", MATCH_STR IPV6_STR @@ -489,7 +490,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd, "no match ipv6 next-hop type [<blackhole>]", NO_STR MATCH_STR IPV6_STR @@ -504,7 +505,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_metric, match_metric_cmd, "match metric (0-4294967295)$metric", MATCH_STR @@ -521,7 +522,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_metric, no_match_metric_cmd, "no match metric [(0-4294967295)]", NO_STR @@ -536,7 +537,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_tag, match_tag_cmd, "match tag (1-4294967295)$tag", MATCH_STR @@ -553,7 +554,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_tag, no_match_tag_cmd, "no match tag [(1-4294967295)]", NO_STR @@ -646,7 +647,7 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, } } -DEFPY( +DEFPY_YANG( set_ip_nexthop, set_ip_nexthop_cmd, "set ip next-hop A.B.C.D$addr", SET_STR @@ -664,7 +665,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_ip_nexthop, no_set_ip_nexthop_cmd, "no set ip next-hop [A.B.C.D]", NO_STR @@ -680,7 +681,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd, "set ipv6 next-hop local X:X::X:X$addr", SET_STR @@ -699,7 +700,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd, "no set ipv6 next-hop local [X:X::X:X]", NO_STR @@ -716,7 +717,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( set_metric, set_metric_cmd, "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>", SET_STR @@ -762,7 +763,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_metric, no_set_metric_cmd, "no set metric [(0-4294967295)]", NO_STR @@ -776,7 +777,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( set_tag, set_tag_cmd, "set tag (1-4294967295)$tag", SET_STR @@ -793,7 +794,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_tag, no_set_tag_cmd, "no set tag [(1-4294967295)]", NO_STR @@ -853,7 +854,7 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode, } } -DEFPY( +DEFPY_YANG( rmap_onmatch_next, rmap_onmatch_next_cmd, "on-match next", "Exit policy on matches\n" @@ -864,7 +865,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_rmap_onmatch_next, no_rmap_onmatch_next_cmd, "no on-match next", @@ -877,7 +878,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( rmap_onmatch_goto, rmap_onmatch_goto_cmd, "on-match goto (1-65535)$rm_num", "Exit policy on matches\n" @@ -890,7 +891,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd, "no on-match goto", NO_STR @@ -903,13 +904,13 @@ DEFPY( } /* Cisco/GNU Zebra compatibility aliases */ -ALIAS( +ALIAS_YANG( rmap_onmatch_goto, rmap_continue_cmd, "continue (1-65535)$rm_num", "Continue on a different entry within the route-map\n" "Route-map entry sequence number\n") -ALIAS( +ALIAS_YANG( no_rmap_onmatch_goto, no_rmap_continue_cmd, "no continue [(1-65535)]", NO_STR @@ -935,7 +936,7 @@ void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, } } -DEFPY( +DEFPY_YANG( rmap_call, rmap_call_cmd, "call WORD$name", "Jump to another Route-Map after match+set\n" @@ -946,7 +947,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_rmap_call, no_rmap_call_cmd, "no call [NAME]", NO_STR @@ -963,7 +964,7 @@ void route_map_call_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL)); } -DEFPY( +DEFPY_YANG( rmap_description, rmap_description_cmd, "description LINE...", "Route-map comment\n" @@ -980,7 +981,7 @@ DEFPY( return rv; } -DEFUN (no_rmap_description, +DEFUN_YANG (no_rmap_description, no_rmap_description_cmd, "no description", NO_STR @@ -638,6 +638,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname, ret = nb_cli_apply_changes(vty, xpath_list); if (ret == CMD_SUCCESS) { VTY_PUSH_XPATH(VRF_NODE, xpath_list); + nb_cli_pending_commit_check(vty); vrfp = vrf_lookup_by_name(vrfname); if (vrfp) VTY_PUSH_CONTEXT(VRF_NODE, vrfp); @@ -731,7 +732,7 @@ DEFUN_NOSH(vrf_exit, return CMD_SUCCESS; } -DEFUN_NOSH (vrf, +DEFUN_YANG_NOSH (vrf, vrf_cmd, "vrf NAME", "Select a VRF to configure\n" @@ -743,7 +744,7 @@ DEFUN_NOSH (vrf, return vrf_handler_create(vty, vrfname, NULL); } -DEFUN (no_vrf, +DEFUN_YANG (no_vrf, no_vrf_cmd, "no vrf NAME", NO_STR @@ -2631,6 +2631,9 @@ int vty_config_node_exit(struct vty *vty) { vty->xpath_index = 0; + /* Perform pending commit if any. */ + nb_cli_pending_commit_check(vty); + /* Check if there's a pending confirmed commit. */ if (vty->t_confirmed_commit_timeout) { vty_out(vty, @@ -134,6 +134,14 @@ struct vty { /* Base candidate configuration. */ struct nb_config *candidate_config_base; + /* Dynamic transaction information. */ + struct timeval backoff_start; + size_t backoff_cmd_count; + struct thread *t_pending_commit; + char *pending_cmds_buf; + size_t pending_cmds_buflen; + size_t pending_cmds_bufpos; + /* Confirmed-commit timeout and rollback configuration. */ struct thread *t_confirmed_commit_timeout; struct nb_config *confirmed_commit_rollback; |
