summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Hopps <chopps@labn.net>2021-08-26 17:57:33 +0200
committerGitHub <noreply@github.com>2021-08-26 17:57:33 +0200
commitd448e2c5f96b3430fd643f52b9264ca87a45c291 (patch)
treed38574fb0ce8c936a003287d107eebf6eb718a8c
parentMerge pull request #9492 from Jafaral/pim-cov (diff)
parent*: explicitly print "exit" at the end of every node config (diff)
downloadfrr-d448e2c5f96b3430fd643f52b9264ca87a45c291.tar.xz
frr-d448e2c5f96b3430fd643f52b9264ca87a45c291.zip
Merge pull request #9331 from idryzhov/explicit-exit
*: explicitly print "exit" at the end of every node config
-rw-r--r--babeld/babel_interface.c2
-rw-r--r--babeld/babeld.c2
-rw-r--r--bfdd/bfdd_cli.c2
-rw-r--r--bgpd/bgp_bmp.c2
-rw-r--r--bgpd/bgp_rpki.c2
-rw-r--r--bgpd/bgp_vty.c1
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c8
-rw-r--r--eigrpd/eigrp_cli.c1
-rw-r--r--isisd/isis_circuit.c2
-rw-r--r--isisd/isis_cli.c5
-rw-r--r--isisd/isis_nb.c1
-rw-r--r--isisd/isis_nb.h1
-rw-r--r--isisd/isisd.c2
-rw-r--r--ldpd/ldp_vty_conf.c6
-rw-r--r--lib/if.c6
-rw-r--r--lib/keychain.c1
-rw-r--r--lib/nexthop_group.c1
-rw-r--r--lib/routemap_cli.c1
-rw-r--r--lib/vty.c4
-rw-r--r--nhrpd/nhrp_vty.c2
-rw-r--r--ospf6d/ospf6_interface.c2
-rw-r--r--ospf6d/ospf6_top.c2
-rw-r--r--ospfd/ospf_vty.c4
-rw-r--r--pathd/path_cli.c48
-rw-r--r--pathd/path_nb.c3
-rw-r--r--pathd/path_nb.h4
-rw-r--r--pathd/path_pcep_cli.c17
-rw-r--r--pathd/pathd.h2
-rw-r--r--pbrd/pbr_vty.c3
-rw-r--r--pimd/pim_instance.c2
-rw-r--r--pimd/pim_vty.c2
-rw-r--r--ripd/ripd.c2
-rw-r--r--ripngd/ripngd.c2
-rw-r--r--staticd/static_vrf.c2
-rw-r--r--tests/lib/cli/test_cli.refout.in2
-rwxr-xr-xtools/frr-reload.py500
-rw-r--r--vtysh/vtysh_config.c18
-rw-r--r--zebra/interface.c4
-rw-r--r--zebra/zebra_pw.c1
-rw-r--r--zebra/zebra_srv6_vty.c4
-rw-r--r--zebra/zebra_vrf.c2
41 files changed, 250 insertions, 428 deletions
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c
index c1e5ffde3..615ed9fee 100644
--- a/babeld/babel_interface.c
+++ b/babeld/babel_interface.c
@@ -1362,7 +1362,7 @@ interface_config_write (struct vty *vty)
write++;
}
}
- vty_endframe (vty, "!\n");
+ vty_endframe (vty, "exit\n!\n");
write++;
}
return write;
diff --git a/babeld/babeld.c b/babeld/babeld.c
index b9623b64b..b9037423b 100644
--- a/babeld/babeld.c
+++ b/babeld/babeld.c
@@ -132,6 +132,8 @@ babel_config_write (struct vty *vty)
lines += config_write_distribute (vty, babel_routing_process->distribute_ctx);
+ vty_out (vty, "exit\n");
+
return lines;
}
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 26ff4a758..384bb26fd 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -101,6 +101,7 @@ void bfd_cli_show_header(struct vty *vty,
void bfd_cli_show_header_end(struct vty *vty,
struct lyd_node *dnode __attribute__((__unused__)))
{
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
@@ -275,6 +276,7 @@ void bfd_cli_show_multi_hop_peer(struct vty *vty,
void bfd_cli_show_peer_end(struct vty *vty,
struct lyd_node *dnode __attribute__((__unused__)))
{
+ vty_out(vty, " exit\n");
vty_out(vty, " !\n");
}
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index dbc35de80..1bc3fd0db 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -2400,6 +2400,8 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
frr_each (bmp_actives, &bt->actives, ba)
vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u\n",
ba->hostname, ba->port, ba->minretry, ba->maxretry);
+
+ vty_out(vty, " exit\n");
}
return 0;
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 286612da1..ca3f93899 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -932,7 +932,7 @@ static int config_write(struct vty *vty)
vty_out(vty, "preference %hhu\n", cache->preference);
}
- vty_out(vty, " exit\n");
+ vty_out(vty, "exit\n");
return 1;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 27f147a4a..dd4a776a2 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -17213,6 +17213,7 @@ int bgp_config_write(struct vty *vty)
bgp_rfapi_cfg_write(vty, bgp);
#endif
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
return 0;
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index cc6426138..2437bd8cf 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -4043,7 +4043,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
rfg->routemap_redist_name
[ZEBRA_ROUTE_BGP_DIRECT_EXT]);
}
- vty_out(vty, " exit-vrf-policy\n");
+ vty_out(vty, " exit-vrf-policy\n");
vty_out(vty, "!\n");
}
if (hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP) {
@@ -4121,7 +4121,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty, bgp->rfapi->rfp,
RFAPI_RFP_CFG_GROUP_L2,
rfgc->name, rfgc->rfp_cfg);
- vty_out(vty, " exit-vnc\n");
+ vty_out(vty, " exit-vnc\n");
vty_out(vty, "!\n");
}
}
@@ -4199,7 +4199,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty, bgp->rfapi->rfp,
RFAPI_RFP_CFG_GROUP_DEFAULT, NULL,
bgp->rfapi_cfg->default_rfp_cfg);
- vty_out(vty, " exit-vnc\n");
+ vty_out(vty, " exit-vnc\n");
vty_out(vty, "!\n");
}
@@ -4364,7 +4364,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty, bgp->rfapi->rfp,
RFAPI_RFP_CFG_GROUP_NVE,
rfg->name, rfg->rfp_cfg);
- vty_out(vty, " exit-vnc\n");
+ vty_out(vty, " exit-vnc\n");
vty_out(vty, "!\n");
}
} /* have listen ports */
diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c
index 35536979e..d61f43586 100644
--- a/eigrpd/eigrp_cli.c
+++ b/eigrpd/eigrp_cli.c
@@ -96,6 +96,7 @@ void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode)
{
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index a78e4996b..6f4a91be6 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -1290,7 +1290,7 @@ static int isis_interface_config_write(struct vty *vty)
write += hook_call(isis_circuit_config_write,
circuit, vty);
}
- vty_endframe(vty, "!\n");
+ vty_endframe(vty, "exit\n!\n");
}
return write;
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index ef86d47b2..70ec66fd7 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -146,6 +146,11 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, "\n");
}
+void cli_show_router_isis_end(struct vty *vty, struct lyd_node *dnode)
+{
+ vty_out(vty, "exit\n");
+}
+
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/
* XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv4-routing
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index ecad16229..f62a8d481 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -32,6 +32,7 @@ const struct frr_yang_module_info frr_isisd_info = {
.xpath = "/frr-isisd:isis/instance",
.cbs = {
.cli_show = cli_show_router_isis,
+ .cli_show_end = cli_show_router_isis_end,
.create = isis_instance_create,
.destroy = isis_instance_destroy,
},
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index 0c2f7b6b7..4680dd5de 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -415,6 +415,7 @@ void isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish(
/* Optional 'cli_show' callbacks. */
void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+void cli_show_router_isis_end(struct vty *vty, struct lyd_node *dnode);
void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 43efa0164..ebcc9985b 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -3011,6 +3011,8 @@ static int isis_config_write(struct vty *vty)
write += area_write_mt_settings(area, vty);
write += fabricd_write_settings(area, vty);
+
+ vty_out(vty, "exit\n");
}
}
diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
index b35d3dfa0..fbd718bb0 100644
--- a/ldpd/ldp_vty_conf.c
+++ b/ldpd/ldp_vty_conf.c
@@ -133,6 +133,8 @@ ldp_af_iface_config_write(struct vty *vty, int af)
ia->hello_interval != 0)
vty_out (vty, " discovery hello interval %u\n",
ia->hello_interval);
+
+ vty_out (vty, " exit\n");
}
}
@@ -314,6 +316,7 @@ ldp_config_write(struct vty *vty)
ldp_af_config_write(vty, AF_INET, ldpd_conf, &ldpd_conf->ipv4);
ldp_af_config_write(vty, AF_INET6, ldpd_conf, &ldpd_conf->ipv6);
vty_out (vty, " !\n");
+ vty_out (vty, "exit\n");
vty_out (vty, "!\n");
return (1);
@@ -353,6 +356,8 @@ ldp_l2vpn_pw_config_write(struct vty *vty, struct l2vpn_pw *pw)
" ! Incomplete config, specify a neighbor lsr-id\n");
if (missing_pwid)
vty_out (vty," ! Incomplete config, specify a pw-id\n");
+
+ vty_out (vty, " exit\n");
}
static int
@@ -383,6 +388,7 @@ ldp_l2vpn_config_write(struct vty *vty)
ldp_l2vpn_pw_config_write(vty, pw);
vty_out (vty, " !\n");
+ vty_out (vty, "exit\n");
vty_out (vty, "!\n");
}
diff --git a/lib/if.c b/lib/if.c
index 6c57855ca..424880ff4 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -1291,6 +1291,11 @@ static void cli_show_interface(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, "\n");
}
+static void cli_show_interface_end(struct vty *vty, struct lyd_node *dnode)
+{
+ vty_out(vty, "exit\n");
+}
+
/*
* XPath: /frr-interface:lib/interface/description
*/
@@ -1652,6 +1657,7 @@ const struct frr_yang_module_info frr_interface_info = {
.create = lib_interface_create,
.destroy = lib_interface_destroy,
.cli_show = cli_show_interface,
+ .cli_show_end = cli_show_interface_end,
.get_next = lib_interface_get_next,
.get_keys = lib_interface_get_keys,
.lookup_entry = lib_interface_lookup_entry,
diff --git a/lib/keychain.c b/lib/keychain.c
index db5c23b1b..02f83ef0a 100644
--- a/lib/keychain.c
+++ b/lib/keychain.c
@@ -1044,6 +1044,7 @@ static int keychain_config_write(struct vty *vty)
vty_out(vty, " exit\n");
}
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 4fee9bde3..97d70189f 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -1156,6 +1156,7 @@ static int nexthop_group_write(struct vty *vty)
nexthop_group_write_nexthop_internal(vty, nh);
}
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 58c62e614..045a8cddd 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -124,6 +124,7 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
{
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
diff --git a/lib/vty.c b/lib/vty.c
index f64ab8384..fef16f1ee 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -3040,7 +3040,7 @@ DEFPY (log_commands,
/* Display current configuration. */
static int vty_config_write(struct vty *vty)
{
- vty_out(vty, "line vty\n");
+ vty_frame(vty, "line vty\n");
if (vty_accesslist_name)
vty_out(vty, " access-class %s\n", vty_accesslist_name);
@@ -3058,6 +3058,8 @@ static int vty_config_write(struct vty *vty)
if (no_password_check)
vty_out(vty, " no login\n");
+ vty_endframe(vty, "exit\n");
+
if (do_log_commands)
vty_out(vty, "log commands\n");
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
index 60ce1e652..a77121448 100644
--- a/nhrpd/nhrp_vty.c
+++ b/nhrpd/nhrp_vty.c
@@ -1225,7 +1225,7 @@ static int interface_config_write(struct vty *vty)
}
}
- vty_endframe(vty, "!\n");
+ vty_endframe(vty, "exit\n!\n");
}
return 0;
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index bbb474ba1..b427a0c9b 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -2593,7 +2593,7 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
ospf6_bfd_write_config(vty, oi);
- vty_endframe(vty, "!\n");
+ vty_endframe(vty, "exit\n!\n");
}
return 0;
}
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index fc181a6d1..b159f1139 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -2237,6 +2237,8 @@ static int config_write_ospf6(struct vty *vty)
ospf6_distribute_config_write(vty, ospf6);
ospf6_asbr_summary_config_write(vty, ospf6);
config_write_ospf6_gr_helper(vty, ospf6);
+
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
return 0;
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 4c248c0df..1843947db 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -11970,7 +11970,7 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
ospf_opaque_config_write_if(vty, ifp);
- vty_endframe(vty, NULL);
+ vty_endframe(vty, "exit\n!\n");
}
return write;
@@ -12546,6 +12546,8 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
/* LDP-Sync print */
ospf_ldp_sync_write_config(vty, ospf);
+ vty_out(vty, "exit\n");
+
write++;
return write;
}
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
index d517d75e4..bd629a2b7 100644
--- a/pathd/path_cli.c
+++ b/pathd/path_cli.c
@@ -45,9 +45,6 @@
static int config_write_segment_routing(struct vty *vty);
-static int config_write_traffic_eng(struct vty *vty);
-static int config_write_segment_lists(struct vty *vty);
-static int config_write_sr_policies(struct vty *vty);
static int segment_list_has_src_dst(
struct vty *vty, char *xpath, long index, const char *index_str,
struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4,
@@ -63,6 +60,8 @@ static int segment_list_has_prefix(
DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client");
+DEFINE_HOOK(pathd_srte_config_write, (struct vty *vty), (vty));
+
/* Vty node structures. */
static struct cmd_node segment_routing_node = {
.name = "segment-routing",
@@ -77,7 +76,6 @@ static struct cmd_node sr_traffic_eng_node = {
.node = SR_TRAFFIC_ENG_NODE,
.parent_node = SEGMENT_ROUTING_NODE,
.prompt = "%s(config-sr-te)# ",
- .config_write = config_write_traffic_eng,
};
static struct cmd_node srte_segment_list_node = {
@@ -85,7 +83,6 @@ static struct cmd_node srte_segment_list_node = {
.node = SR_SEGMENT_LIST_NODE,
.parent_node = SR_TRAFFIC_ENG_NODE,
.prompt = "%s(config-sr-te-segment-list)# ",
- .config_write = config_write_segment_lists,
};
static struct cmd_node srte_policy_node = {
@@ -93,7 +90,6 @@ static struct cmd_node srte_policy_node = {
.node = SR_POLICY_NODE,
.parent_node = SR_TRAFFIC_ENG_NODE,
.prompt = "%s(config-sr-te-policy)# ",
- .config_write = config_write_sr_policies,
};
static struct cmd_node srte_candidate_dyn_node = {
@@ -309,6 +305,11 @@ void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode,
yang_dnode_get_string(dnode, "./name"));
}
+void cli_show_srte_segment_list_end(struct vty *vty, struct lyd_node *dnode)
+{
+ vty_out(vty, " exit\n");
+}
+
static int segment_list_has_src_dst(
struct vty *vty, char *xpath, long index, const char *index_str,
struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4,
@@ -666,6 +667,11 @@ void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode,
yang_dnode_get_string(dnode, "./endpoint"));
}
+void cli_show_srte_policy_end(struct vty *vty, struct lyd_node *dnode)
+{
+ vty_out(vty, " exit\n");
+}
+
/*
* XPath: /frr-pathd:pathd/srte/policy/name
*/
@@ -1237,6 +1243,15 @@ void cli_show_srte_policy_candidate_path(struct vty *vty,
}
}
+void cli_show_srte_policy_candidate_path_end(struct vty *vty,
+ struct lyd_node *dnode)
+{
+ const char *type = yang_dnode_get_string(dnode, "./type");
+
+ if (strmatch(type, "dynamic"))
+ vty_out(vty, " exit\n");
+}
+
static int config_write_dnode(const struct lyd_node *dnode, void *arg)
{
struct vty *vty = arg;
@@ -1249,29 +1264,20 @@ static int config_write_dnode(const struct lyd_node *dnode, void *arg)
int config_write_segment_routing(struct vty *vty)
{
vty_out(vty, "segment-routing\n");
- return 1;
-}
-
-int config_write_traffic_eng(struct vty *vty)
-{
vty_out(vty, " traffic-eng\n");
+
path_ted_config_write(vty);
- return 1;
-}
-int config_write_segment_lists(struct vty *vty)
-{
yang_dnode_iterate(config_write_dnode, vty, running_config->dnode,
"/frr-pathd:pathd/srte/segment-list");
-
- return 1;
-}
-
-int config_write_sr_policies(struct vty *vty)
-{
yang_dnode_iterate(config_write_dnode, vty, running_config->dnode,
"/frr-pathd:pathd/srte/policy");
+ hook_call(pathd_srte_config_write, vty);
+
+ vty_out(vty, " exit\n");
+ vty_out(vty, "exit\n");
+
return 1;
}
diff --git a/pathd/path_nb.c b/pathd/path_nb.c
index 9c622883b..1ab8b7f39 100644
--- a/pathd/path_nb.c
+++ b/pathd/path_nb.c
@@ -56,6 +56,7 @@ const struct frr_yang_module_info frr_pathd_info = {
.cbs = {
.create = pathd_srte_segment_list_create,
.cli_show = cli_show_srte_segment_list,
+ .cli_show_end = cli_show_srte_segment_list_end,
.destroy = pathd_srte_segment_list_destroy,
.get_next = pathd_srte_segment_list_get_next,
.get_keys = pathd_srte_segment_list_get_keys,
@@ -136,6 +137,7 @@ const struct frr_yang_module_info frr_pathd_info = {
.cbs = {
.create = pathd_srte_policy_create,
.cli_show = cli_show_srte_policy,
+ .cli_show_end = cli_show_srte_policy_end,
.destroy = pathd_srte_policy_destroy,
.get_next = pathd_srte_policy_get_next,
.get_keys = pathd_srte_policy_get_keys,
@@ -169,6 +171,7 @@ const struct frr_yang_module_info frr_pathd_info = {
.cbs = {
.create = pathd_srte_policy_candidate_path_create,
.cli_show = cli_show_srte_policy_candidate_path,
+ .cli_show_end = cli_show_srte_policy_candidate_path_end,
.destroy = pathd_srte_policy_candidate_path_destroy,
.get_next = pathd_srte_policy_candidate_path_get_next,
.get_keys = pathd_srte_policy_candidate_path_get_keys,
diff --git a/pathd/path_nb.h b/pathd/path_nb.h
index caeadd9cc..6a918b8b8 100644
--- a/pathd/path_nb.h
+++ b/pathd/path_nb.h
@@ -112,10 +112,12 @@ void pathd_apply_finish(struct nb_cb_apply_finish_args *args);
/* Optional 'cli_show' callbacks. */
void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+void cli_show_srte_segment_list_end(struct vty *vty, struct lyd_node *dnode);
void cli_show_srte_segment_list_segment(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+void cli_show_srte_policy_end(struct vty *vty, struct lyd_node *dnode);
void cli_show_srte_policy_name(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_srte_policy_binding_sid(struct vty *vty, struct lyd_node *dnode,
@@ -123,6 +125,8 @@ void cli_show_srte_policy_binding_sid(struct vty *vty, struct lyd_node *dnode,
void cli_show_srte_policy_candidate_path(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults);
+void cli_show_srte_policy_candidate_path_end(struct vty *vty,
+ struct lyd_node *dnode);
/* Utility functions */
typedef void (*of_pref_cp_t)(enum objfun_type type, void *arg);
diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c
index db5f256a8..829df3179 100644
--- a/pathd/path_pcep_cli.c
+++ b/pathd/path_pcep_cli.c
@@ -175,7 +175,6 @@ static struct cmd_node pcep_node = {
.name = "srte pcep",
.node = PCEP_NODE,
.parent_node = SR_TRAFFIC_ENG_NODE,
- .config_write = pcep_cli_pcep_config_write,
.prompt = "%s(config-sr-te-pcep)# "
};
@@ -183,7 +182,6 @@ static struct cmd_node pcep_pcc_node = {
.name = "srte pcep pcc",
.node = PCEP_PCC_NODE,
.parent_node = PCEP_NODE,
- .config_write = pcep_cli_pcc_config_write,
.prompt = "%s(config-sr-te-pcep-pcc)# "
};
@@ -191,7 +189,6 @@ static struct cmd_node pcep_pce_node = {
.name = "srte pcep pce",
.node = PCEP_PCE_NODE,
.parent_node = PCEP_NODE,
- .config_write = pcep_cli_pce_config_write,
.prompt = "%s(config-sr-te-pcep-pce)# "
};
@@ -199,7 +196,6 @@ static struct cmd_node pcep_pce_config_node = {
.name = "srte pcep pce-config",
.node = PCEP_PCE_CONFIG_NODE,
.parent_node = PCEP_NODE,
- .config_write = pcep_cli_pcep_pce_config_write,
.prompt = "%s(pce-sr-te-pcep-pce-config)# "
};
@@ -1444,6 +1440,10 @@ int pcep_cli_debug_set_all(uint32_t flags, bool set)
int pcep_cli_pcep_config_write(struct vty *vty)
{
vty_out(vty, " pcep\n");
+ pcep_cli_pcep_pce_config_write(vty);
+ pcep_cli_pce_config_write(vty);
+ pcep_cli_pcc_config_write(vty);
+ vty_out(vty, " exit\n");
return 1;
}
@@ -1468,7 +1468,7 @@ int pcep_cli_pcc_config_write(struct vty *vty)
}
if (pce_connections_g.num_connections == 0) {
- return lines;
+ goto exit;
}
buf[0] = 0;
@@ -1495,6 +1495,8 @@ int pcep_cli_pcc_config_write(struct vty *vty)
lines++;
buf[0] = 0;
}
+exit:
+ vty_out(vty, " exit\n");
return lines;
}
@@ -1655,6 +1657,8 @@ int pcep_cli_pce_config_write(struct vty *vty)
vty_out(vty, "%s", buf);
buf[0] = '\0';
+
+ vty_out(vty, " exit\n");
}
return lines;
@@ -1679,6 +1683,8 @@ int pcep_cli_pcep_pce_config_write(struct vty *vty)
pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
vty_out(vty, "%s", buf);
buf[0] = 0;
+
+ vty_out(vty, " exit\n");
}
return lines;
@@ -1999,6 +2005,7 @@ DEFPY(pcep_cli_clear_srte_pcep_session,
void pcep_cli_init(void)
{
+ hook_register(pathd_srte_config_write, pcep_cli_pcep_config_write);
hook_register(nb_client_debug_config_write,
pcep_cli_debug_config_write);
hook_register(nb_client_debug_set_all, pcep_cli_debug_set_all);
diff --git a/pathd/pathd.h b/pathd/pathd.h
index f790a0e3c..81d7aa910 100644
--- a/pathd/pathd.h
+++ b/pathd/pathd.h
@@ -34,6 +34,8 @@
DECLARE_MGROUP(PATHD);
+DECLARE_HOOK(pathd_srte_config_write, (struct vty *vty), (vty));
+
enum srte_protocol_origin {
SRTE_ORIGIN_UNDEFINED = 0,
SRTE_ORIGIN_PCEP = 1,
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 2936d1e34..6c007acb5 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -1118,7 +1118,7 @@ static int pbr_interface_config_write(struct vty *vty)
pbr_map_write_interfaces(vty, ifp);
- vty_endframe(vty, "!\n");
+ vty_endframe(vty, "exit\n!\n");
}
}
@@ -1184,6 +1184,7 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
}
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
return 1;
}
diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c
index 6dda66b79..8a9527d7c 100644
--- a/pimd/pim_instance.c
+++ b/pimd/pim_instance.c
@@ -220,7 +220,7 @@ static int pim_vrf_config_write(struct vty *vty)
pim_global_config_write_worker(pim, vty);
if (vrf->vrf_id != VRF_DEFAULT)
- vty_endframe(vty, " exit-vrf\n!\n");
+ vty_endframe(vty, "exit-vrf\n!\n");
}
return 0;
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 95882cf58..e4dec9ee8 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -451,7 +451,7 @@ int pim_interface_config_write(struct vty *vty)
pim_bfd_write_config(vty, ifp);
++writes;
}
- vty_endframe(vty, "!\n");
+ vty_endframe(vty, "exit\n!\n");
++writes;
}
}
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 3d1427c3b..97edd1c38 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3281,6 +3281,8 @@ static int config_write_rip(struct vty *vty)
/* Interface routemap configuration */
config_write_if_rmap(vty, rip->if_rmap_ctx);
+ vty_out(vty, "exit\n");
+
write = 1;
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index cbd2c2289..1f52abd0b 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2270,6 +2270,8 @@ static int ripng_config_write(struct vty *vty)
config_write_distribute(vty, ripng->distribute_ctx);
config_write_if_rmap(vty, ripng->if_rmap_ctx);
+ vty_out(vty, "exit\n");
+
write = 1;
}
diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c
index 96e5d37d6..0b3efd0b4 100644
--- a/staticd/static_vrf.c
+++ b/staticd/static_vrf.c
@@ -164,7 +164,7 @@ static int static_vrf_config_write(struct vty *vty)
SAFI_UNICAST, "ipv6 route");
if (vrf->vrf_id != VRF_DEFAULT)
- vty_endframe(vty, " exit-vrf\n!\n");
+ vty_endframe(vty, "exit-vrf\n!\n");
}
return 0;
diff --git a/tests/lib/cli/test_cli.refout.in b/tests/lib/cli/test_cli.refout.in
index 8f9959cc4..1f38e08b2 100644
--- a/tests/lib/cli/test_cli.refout.in
+++ b/tests/lib/cli/test_cli.refout.in
@@ -315,7 +315,6 @@ domainname test.domain
!
!
!
-line vty
!
end
test# conf t
@@ -332,7 +331,6 @@ domainname test.domain
!
!
!
-line vty
!
end
foohost(config)#
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index a326ecc0f..7c6a83a51 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -513,9 +513,6 @@ class Config(object):
Parse the configuration and create contexts for each appropriate block
"""
- current_context_lines = []
- ctx_keys = []
-
"""
The end of a context is flagged via the 'end' keyword:
@@ -574,43 +571,80 @@ end
# key of the context. So "router bgp 10" is the key for the non-address
# family part of bgp, "router bgp 10, address-family ipv6 unicast" is
# the key for the subcontext and so on.
+
+ # This dictionary contains a tree of all commands that we know start a
+ # new multi-line context. All other commands are treated either as
+ # commands inside a multi-line context or as single-line contexts. This
+ # dictionary should be updated whenever a new node is added to FRR.
+ ctx_keywords = {
+ "router bgp ": {
+ "address-family ": {
+ "vni ": {},
+ },
+ "vnc ": {},
+ "vrf-policy ": {},
+ "bmp ": {},
+ "segment-routing srv6": {},
+ },
+ "router rip": {},
+ "router ripng": {},
+ "router isis ": {},
+ "router openfabric ": {},
+ "router ospf": {},
+ "router ospf6": {},
+ "router eigrp ": {},
+ "router babel": {},
+ "mpls ldp": {
+ "address-family ": {
+ "interface ": {}
+ }
+ },
+ "l2vpn ": {
+ "member pseudowire ": {}
+ },
+ "key chain ": {
+ "key ": {}
+ },
+ "vrf ": {},
+ "interface ": {
+ "link-params": {}
+ },
+ "pseudowire ": {},
+ "segment-routing": {
+ "traffic-eng": {
+ "segment-list ": {},
+ "policy ": {
+ "candidate-path ": {}
+ },
+ "pcep": {
+ "pcc": {},
+ "pce ": {},
+ "pce-config ": {}
+ }
+ },
+ "srv6": {
+ "locators": {
+ "locator ": {}
+ }
+ }
+ },
+ "nexthop-group ": {},
+ "route-map ": {},
+ "pbr-map ": {},
+ "rpki": {},
+ "bfd": {
+ "peer ": {},
+ "profile ": {}
+ },
+ "line vty": {}
+ }
+
+ # stack of context keys
ctx_keys = []
- main_ctx_key = []
- new_ctx = True
-
- # the keywords that we know are single line contexts. bgp in this case
- # is not the main router bgp block, but enabling multi-instance
- oneline_ctx_keywords = (
- "access-list ",
- "agentx",
- "allow-external-route-update",
- "bgp ",
- "debug ",
- "domainname ",
- "dump ",
- "enable ",
- "evpn mh",
- "frr ",
- "fpm ",
- "hostname ",
- "ip ",
- "ipv6 ",
- "log ",
- "mac access-list ",
- "mpls lsp",
- "mpls label",
- "no ",
- "password ",
- "pbr ",
- "ptm-enable",
- "router-id ",
- "service ",
- "table ",
- "username ",
- "vni ",
- "vrrp autoconfigure",
- "zebra "
- )
+ # stack of context keywords
+ cur_ctx_keywords = [ctx_keywords]
+ # list of stored commands
+ cur_ctx_lines = []
for line in self.lines:
@@ -620,357 +654,77 @@ end
if line.startswith("!") or line.startswith("#"):
continue
- if (
- len(ctx_keys) == 2
- and ctx_keys[0].startswith("bfd")
- and ctx_keys[1].startswith("profile ")
- and line == "end"
- ):
- log.debug("LINE %-50s: popping from sub context, %-50s", line, ctx_keys)
-
- if main_ctx_key:
- self.save_contexts(ctx_keys, current_context_lines)
- ctx_keys = copy.deepcopy(main_ctx_key)
- current_context_lines = []
+ if line.startswith("exit"):
+ # ignore on top level
+ if len(ctx_keys) == 0:
continue
- # one line contexts
- # there is one exception though: ldpd accepts a 'router-id' clause
- # as part of its 'mpls ldp' config context. If we are processing
- # ldp configuration and encounter a router-id we should NOT switch
- # to a new context
- if (
- new_ctx is True
- and any(line.startswith(keyword) for keyword in oneline_ctx_keywords)
- and not (
- ctx_keys
- and ctx_keys[0].startswith("mpls ldp")
- and line.startswith("router-id ")
- )
- ):
- self.save_contexts(ctx_keys, current_context_lines)
-
- # Start a new context
- main_ctx_key = []
- ctx_keys = [
- line,
- ]
- current_context_lines = []
-
- log.debug("LINE %-50s: entering new context, %-50s", line, ctx_keys)
- self.save_contexts(ctx_keys, current_context_lines)
- new_ctx = True
-
- elif line == "end":
- self.save_contexts(ctx_keys, current_context_lines)
- log.debug("LINE %-50s: exiting old context, %-50s", line, ctx_keys)
-
- # Start a new context
- new_ctx = True
- main_ctx_key = []
- ctx_keys = []
- current_context_lines = []
-
- elif line == "exit" and ctx_keys[0].startswith("rpki"):
- self.save_contexts(ctx_keys, current_context_lines)
- log.debug("LINE %-50s: exiting old context, %-50s", line, ctx_keys)
-
- # Start a new context
- new_ctx = True
- main_ctx_key = []
- ctx_keys = []
- current_context_lines = []
-
- elif line == "exit-vrf":
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines.append(line)
- log.debug(
- "LINE %-50s: append to current_context_lines, %-50s", line, ctx_keys
- )
+ # save current context
+ self.save_contexts(ctx_keys, cur_ctx_lines)
- # Start a new context
- new_ctx = True
- main_ctx_key = []
- ctx_keys = []
- current_context_lines = []
+ # exit current context
+ log.debug("LINE %-50s: exit context %-50s", line, ctx_keys)
- elif (
- line == "exit"
- and len(ctx_keys) > 1
- and ctx_keys[0].startswith("segment-routing")
- ):
- self.save_contexts(ctx_keys, current_context_lines)
-
- # Start a new context
- ctx_keys = ctx_keys[:-1]
- current_context_lines = []
- log.debug(
- "LINE %-50s: popping segment routing sub-context to ctx%-50s",
- line,
- ctx_keys,
- )
-
- elif line in ["exit-address-family", "exit", "exit-vnc"]:
- # if this exit is for address-family ipv4 unicast, ignore the pop
- if main_ctx_key:
- self.save_contexts(ctx_keys, current_context_lines)
-
- # Start a new context
- ctx_keys = copy.deepcopy(main_ctx_key)
- current_context_lines = []
- log.debug(
- "LINE %-50s: popping from subcontext to ctx%-50s",
- line,
- ctx_keys,
- )
+ ctx_keys.pop()
+ cur_ctx_keywords.pop()
+ cur_ctx_lines = []
- elif line in ["exit-vni", "exit-ldp-if"]:
- if sub_main_ctx_key:
- self.save_contexts(ctx_keys, current_context_lines)
-
- # Start a new context
- ctx_keys = copy.deepcopy(sub_main_ctx_key)
- current_context_lines = []
- log.debug(
- "LINE %-50s: popping from sub-subcontext to ctx%-50s",
- line,
- ctx_keys,
- )
+ continue
- elif new_ctx is True:
- if not main_ctx_key:
- ctx_keys = [
- line,
- ]
- else:
- ctx_keys = copy.deepcopy(main_ctx_key)
- main_ctx_key = []
+ if line.startswith("end"):
+ # exit all contexts
+ while len(ctx_keys) > 0:
+ # save current context
+ self.save_contexts(ctx_keys, cur_ctx_lines)
- current_context_lines = []
- new_ctx = False
- log.debug("LINE %-50s: entering new context, %-50s", line, ctx_keys)
+ # exit current context
+ log.debug("LINE %-50s: exit context %-50s", line, ctx_keys)
- elif (
- line.startswith("address-family ")
- or line.startswith("vnc defaults")
- or line.startswith("vnc l2-group")
- or line.startswith("vnc nve-group")
- or line.startswith("peer")
- or line.startswith("key ")
- or line.startswith("member pseudowire")
- ):
- main_ctx_key = []
+ ctx_keys.pop()
+ cur_ctx_keywords.pop()
+ cur_ctx_lines = []
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug("LINE %-50s: entering sub-context, append to ctx_keys", line)
+ continue
- if line == "address-family ipv6" and not ctx_keys[0].startswith(
- "mpls ldp"
- ):
- ctx_keys.append("address-family ipv6 unicast")
- elif line == "address-family ipv4" and not ctx_keys[0].startswith(
- "mpls ldp"
- ):
- ctx_keys.append("address-family ipv4 unicast")
- elif line == "address-family evpn":
- ctx_keys.append("address-family l2vpn evpn")
- else:
+ new_ctx = False
+
+ # check if the line is a context-entering keyword
+ for k, v in cur_ctx_keywords[-1].items():
+ if line.startswith(k):
+ # candidate-path is a special case. It may be a node and
+ # may be a single-line command. The distinguisher is the
+ # word "dynamic" or "explicit" at the middle of the line.
+ # It was perhaps not the best choice by the pathd authors
+ # but we have what we have.
+ if k == "candidate-path " and "explicit" in line:
+ # this is a single-line command
+ break
+
+ # save current context
+ self.save_contexts(ctx_keys, cur_ctx_lines)
+
+ # enter new context
+ new_ctx = True
ctx_keys.append(line)
+ cur_ctx_keywords.append(v)
+ cur_ctx_lines = []
- elif (
- line.startswith("vni ")
- and len(ctx_keys) == 2
- and ctx_keys[0].startswith("router bgp")
- and ctx_keys[1] == "address-family l2vpn evpn"
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- sub_main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering sub-sub-context, append to ctx_keys", line
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("interface ")
- and len(ctx_keys) == 2
- and ctx_keys[0].startswith("mpls ldp")
- and ctx_keys[1].startswith("address-family")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- sub_main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering sub-sub-context, append to ctx_keys", line
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("traffic-eng")
- and len(ctx_keys) == 1
- and ctx_keys[0].startswith("segment-routing")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- log.debug(
- "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
- line,
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("segment-list ")
- and len(ctx_keys) == 2
- and ctx_keys[0].startswith("segment-routing")
- and ctx_keys[1].startswith("traffic-eng")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- log.debug(
- "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
- line,
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("policy ")
- and len(ctx_keys) == 2
- and ctx_keys[0].startswith("segment-routing")
- and ctx_keys[1].startswith("traffic-eng")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- log.debug(
- "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
- line,
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("candidate-path ")
- and line.endswith(" dynamic")
- and len(ctx_keys) == 3
- and ctx_keys[0].startswith("segment-routing")
- and ctx_keys[1].startswith("traffic-eng")
- and ctx_keys[2].startswith("policy")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering candidate-path sub-context, append to ctx_keys",
- line,
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("pcep")
- and len(ctx_keys) == 2
- and ctx_keys[0].startswith("segment-routing")
- and ctx_keys[1].startswith("traffic-eng")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering pcep sub-context, append to ctx_keys", line
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("pce-config ")
- and len(ctx_keys) == 3
- and ctx_keys[0].startswith("segment-routing")
- and ctx_keys[1].startswith("traffic-eng")
- and ctx_keys[2].startswith("pcep")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering pce-config sub-context, append to ctx_keys",
- line,
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("pce ")
- and len(ctx_keys) == 3
- and ctx_keys[0].startswith("segment-routing")
- and ctx_keys[1].startswith("traffic-eng")
- and ctx_keys[2].startswith("pcep")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering pce sub-context, append to ctx_keys", line
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("pcc")
- and len(ctx_keys) == 3
- and ctx_keys[0].startswith("segment-routing")
- and ctx_keys[1].startswith("traffic-eng")
- and ctx_keys[2].startswith("pcep")
- ):
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering pcc sub-context, append to ctx_keys", line
- )
- ctx_keys.append(line)
-
- elif (
- line.startswith("profile ")
- and len(ctx_keys) == 1
- and ctx_keys[0].startswith("bfd")
- ):
+ log.debug("LINE %-50s: enter context %-50s", line, ctx_keys)
+ break
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug(
- "LINE %-50s: entering BFD profile sub-context, append to ctx_keys",
- line,
- )
- ctx_keys.append(line)
+ if new_ctx:
+ continue
+ if len(ctx_keys) == 0:
+ log.debug("LINE %-50s: single-line context", line)
+ self.save_contexts([line], [])
else:
- # Continuing in an existing context, add non-commented lines to it
- current_context_lines.append(line)
- log.debug(
- "LINE %-50s: append to current_context_lines, %-50s", line, ctx_keys
- )
+ log.debug("LINE %-50s: add to current context %-50s", line, ctx_keys)
+ cur_ctx_lines.append(line)
# Save the context of the last one
- self.save_contexts(ctx_keys, current_context_lines)
+ if len(ctx_keys) > 0:
+ self.save_contexts(ctx_keys, cur_ctx_lines)
def lines_to_config(ctx_keys, line, delete):
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index d22ec3113..2e1d7c5ba 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -272,16 +272,11 @@ void vtysh_config_parse_line(void *arg, const char *line)
strlen(" ip igmp query-interval")) == 0) {
config_add_line_uniq_end(config->line, line);
} else if (config->index == LINK_PARAMS_NODE
- && strncmp(line, " exit-link-params",
- strlen(" exit"))
+ && strncmp(line, " exit-link-params",
+ strlen(" exit"))
== 0) {
config_add_line(config->line, line);
config->index = INTERFACE_NODE;
- } else if (config->index == VRF_NODE
- && strncmp(line, " exit-vrf",
- strlen(" exit-vrf"))
- == 0) {
- config_add_line_uniq_end(config->line, line);
} else if (!strncmp(line, " vrrp", strlen(" vrrp"))
|| !strncmp(line, " no vrrp",
strlen(" no vrrp"))) {
@@ -300,7 +295,10 @@ void vtysh_config_parse_line(void *arg, const char *line)
config_add_line(config_top, line);
break;
default:
- if (strncmp(line, "interface", strlen("interface")) == 0)
+ if (strncmp(line, "exit", strlen("exit")) == 0) {
+ if (config)
+ config_add_line_uniq_end(config->line, line);
+ } else if (strncmp(line, "interface", strlen("interface")) == 0)
config = config_get(INTERFACE_NODE, line);
else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
config = config_get(PW_NODE, line);
@@ -496,7 +494,9 @@ void vtysh_config_dump(void)
* are not under the VRF node.
*/
if (config->index == INTERFACE_NODE
- && list_isempty(config->line)) {
+ && (listcount(config->line) == 1)
+ && (line = listnode_head(config->line))
+ && strmatch(line, "exit")) {
config_del(config);
continue;
}
diff --git a/zebra/interface.c b/zebra/interface.c
index 21eeb2054..18f7503f8 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -4096,7 +4096,7 @@ static int link_params_config_write(struct vty *vty, struct interface *ifp)
if (IS_PARAM_SET(iflp, LP_RMT_AS))
vty_out(vty, " neighbor %pI4 as %u\n", &iflp->rmt_ip,
iflp->rmt_as);
- vty_out(vty, " exit-link-params\n");
+ vty_out(vty, " exit-link-params\n");
return 0;
}
@@ -4188,7 +4188,7 @@ static int if_config_write(struct vty *vty)
zebra_evpn_mh_if_write(vty, ifp);
link_params_config_write(vty, ifp);
- vty_endframe(vty, "!\n");
+ vty_endframe(vty, "exit\n!\n");
}
return 0;
}
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index 6b4a81515..d5083d4cb 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -836,6 +836,7 @@ static int zebra_pw_config(struct vty *vty)
if (!(pw->flags & F_PSEUDOWIRE_CWORD))
vty_out(vty, " control-word exclude\n");
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
write = 1;
}
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index 97935f126..d2b91b6c0 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -320,10 +320,14 @@ static int zebra_sr_config(struct vty *vty)
vty_out(vty, " locator %s\n", locator->name);
vty_out(vty, " prefix %s/%u\n", str,
locator->prefix.prefixlen);
+ vty_out(vty, " exit\n");
vty_out(vty, " !\n");
}
+ vty_out(vty, " exit\n");
vty_out(vty, " !\n");
+ vty_out(vty, " exit\n");
vty_out(vty, " !\n");
+ vty_out(vty, "exit\n");
vty_out(vty, "!\n");
}
return 0;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index a2a671e95..1c5fddae0 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -524,7 +524,7 @@ static int vrf_config_write(struct vty *vty)
router_id_write(vty, zvrf);
if (zvrf_id(zvrf) != VRF_DEFAULT)
- vty_endframe(vty, " exit-vrf\n!\n");
+ vty_endframe(vty, "exit-vrf\n!\n");
else
vty_out(vty, "!\n");
}