summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_aspath.c1
-rw-r--r--bgpd/bgp_attr.c1
-rw-r--r--bgpd/bgp_bfd.c1
-rw-r--r--bgpd/bgp_encap_tlv.c1
-rw-r--r--bgpd/bgp_fsm.c1
-rw-r--r--bgpd/bgp_main.c1
-rw-r--r--bgpd/bgp_route.c112
-rw-r--r--bgpd/bgp_routemap.c1
-rw-r--r--bgpd/bgp_table.c1
-rw-r--r--bgpd/bgp_vty.c50
-rw-r--r--bgpd/bgp_vty.h4
-rw-r--r--bgpd/bgpd.h1
-rw-r--r--doc/cli.md356
-rw-r--r--lib/plist.c1
-rw-r--r--lib/plist.h5
-rw-r--r--pimd/pim_cmd.c156
-rw-r--r--pimd/pim_iface.c32
-rw-r--r--pimd/pim_mroute.c30
-rw-r--r--pimd/pim_vty.c5
-rw-r--r--pimd/pimd.c2
-rw-r--r--pimd/pimd.h3
-rwxr-xr-xtools/frr-reload.py2
22 files changed, 479 insertions, 288 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 2e78c9a3bf..006631c1f0 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -24,7 +24,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "hash.h"
#include "memory.h"
#include "vector.h"
-#include "vty.h"
#include "log.h"
#include "stream.h"
#include "command.h"
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 153187fd43..1fccd25c8a 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -24,7 +24,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "prefix.h"
#include "memory.h"
#include "vector.h"
-#include "vty.h"
#include "stream.h"
#include "log.h"
#include "hash.h"
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index b8158dc31e..0a06a57fe5 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -31,7 +31,6 @@
#include "buffer.h"
#include "stream.h"
#include "zclient.h"
-#include "vty.h"
#include "bfd.h"
#include "lib/json.h"
#include "filter.h"
diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c
index 8c5ab8d6f6..7acd23b9ae 100644
--- a/bgpd/bgp_encap_tlv.c
+++ b/bgpd/bgp_encap_tlv.c
@@ -22,7 +22,6 @@
#include "command.h"
#include "memory.h"
#include "prefix.h"
-#include "vty.h"
#include "filter.h"
#include "bgpd.h"
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index a71364381e..7dc7f053d6 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -23,7 +23,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "linklist.h"
#include "prefix.h"
-#include "vty.h"
#include "sockunion.h"
#include "thread.h"
#include "log.h"
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index fbbcda5915..2598d66656 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -21,7 +21,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include <zebra.h>
#include "vector.h"
-#include "vty.h"
#include "command.h"
#include "getopt.h"
#include "thread.h"
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 55823a272f..ced587e738 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5267,7 +5267,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
struct bgp_table *table;
/* MPLS-VPN aggregation is not yet supported. */
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi = SAFI_EVPN))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
return;
table = bgp->aggregate[afi][safi];
@@ -5304,7 +5304,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
struct bgp_table *table;
/* MPLS-VPN aggregation is not yet supported. */
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi = SAFI_EVPN))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
return;
table = bgp->aggregate[afi][safi];
@@ -6097,7 +6097,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
* neccessarily the same as the prefix address family.
* Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field
*/
- if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN))
+ if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
{
if (attr->extra)
{
@@ -6129,7 +6129,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
{
json_nexthop_global = json_object_new_object();
- if ((safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in));
else
json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop));
@@ -6139,7 +6139,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
}
else
{
- if ((safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
vty_out (vty, "%-16s",
inet_ntoa (attr->extra->mp_nexthop_global_in));
else
@@ -8358,7 +8358,6 @@ DEFUN (show_ip_bgp,
"Display route and more specific routes\n"
JSON_STR)
{
- vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
int exact_match = 0;
@@ -8366,23 +8365,13 @@ DEFUN (show_ip_bgp,
struct bgp *bgp = NULL;
int idx = 0;
- bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
if (!idx)
return CMD_WARNING;
int uj = use_json (argc, argv);
if (uj) argc--;
- bgp = bgp_lookup_by_vrf_id (vrf);
- if (bgp == NULL)
- {
- if (vrf == VRF_DEFAULT)
- vty_out (vty, "Can't find BGP instance (default)%s", VTY_NEWLINE);
- else
- vty_out (vty, "Can't find BGP instance %d%s", vrf, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
if (argv_find(argv, argc, "cidr-only", &idx))
return bgp_show (vty, bgp, afi, safi, bgp_show_type_cidr_only, NULL, uj);
@@ -8465,7 +8454,6 @@ DEFUN (show_ip_bgp_route,
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
- vrf_id_t vrf = VRF_DEFAULT;;
char *prefix = NULL;
struct bgp *bgp = NULL;
enum bgp_path_type path_type;
@@ -8473,20 +8461,11 @@ DEFUN (show_ip_bgp_route,
int idx = 0;
- bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
if (!idx)
return CMD_WARNING;
- if (vrf != VRF_ALL)
- {
- bgp = bgp_lookup_by_vrf_id (vrf);
- if (bgp == NULL)
- {
- vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
- else
+ if (!bgp)
{
vty_out (vty, "Specified 'all' vrf's but this command currently only works per view/vrf%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8534,12 +8513,12 @@ DEFUN (show_ip_bgp_regexp,
"Display routes matching the AS path regular expression\n"
"A regular-expression to match the BGP AS paths\n")
{
- vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
+ struct bgp *bgp = NULL;
int idx = 0;
- bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
if (!idx)
return CMD_WARNING;
@@ -8564,12 +8543,12 @@ DEFUN (show_ip_bgp_instance_all,
BGP_SAFI_HELP_STR
JSON_STR)
{
- vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP;
safi_t safi = SAFI_UNICAST;
+ struct bgp *bgp = NULL;
int idx = 0;
- bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
if (!idx)
return CMD_WARNING;
@@ -9253,41 +9232,19 @@ DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
"Display detailed prefix count information\n"
JSON_STR)
{
- vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
struct peer *peer;
int idx = 0;
struct bgp *bgp = NULL;
- bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
if (!idx)
return CMD_WARNING;
int uj = use_json (argc, argv);
if (uj) argc--;
- if (vrf != VRF_ALL)
- {
- bgp = bgp_lookup_by_vrf_id (vrf);
- if (bgp == NULL)
- {
- if (uj)
- {
- json_object *json_no = NULL;
- json_no = json_object_new_object();
- json_object_string_add(json_no, "warning", "Can't find BGP view");
- vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
- json_object_free(json_no);
- }
- else
- vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
- else
- bgp = NULL;
-
argv_find (argv, argc, "neighbors", &idx);
peer = peer_lookup_in_view (vty, bgp, argv[idx+1]->arg, uj);
if (! peer)
@@ -9629,7 +9586,6 @@ DEFUN (show_ip_bgp_instance_neighbor_advertised_route,
"Name of the route map\n"
JSON_STR)
{
- vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
char *rmap_name = NULL;
@@ -9640,29 +9596,13 @@ DEFUN (show_ip_bgp_instance_neighbor_advertised_route,
int idx = 0;
- bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
if (!idx)
return CMD_WARNING;
int uj = use_json (argc, argv);
if (uj) argc--;
- bgp = bgp_lookup_by_vrf_id (vrf);
- if (bgp == NULL)
- {
- if (uj)
- {
- json_object *json_no = NULL;
- json_no = json_object_new_object();
- json_object_string_add(json_no, "warning", "Can't find BGP view");
- vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
- json_object_free(json_no);
- }
- else
- vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
/* neighbors <A.B.C.D|X:X::X:X|WORD> */
argv_find (argv, argc, "neighbors", &idx);
peerstr = argv[++idx]->arg;
@@ -9809,7 +9749,6 @@ DEFUN (show_ip_bgp_neighbor_routes,
"Display routes learned from neighbor\n"
JSON_STR)
{
- vrf_id_t vrf = VRF_DEFAULT;
char *peerstr = NULL;
struct bgp *bgp = NULL;
afi_t afi = AFI_IP6;
@@ -9819,34 +9758,13 @@ DEFUN (show_ip_bgp_neighbor_routes,
int idx = 0;
- bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ bgp_vty_find_and_parse_afi_safi_bgp (vty, argv, argc, &idx, &afi, &safi, &bgp);
if (!idx)
return CMD_WARNING;
int uj = use_json (argc, argv);
if (uj) argc--;
- if (vrf != VRF_ALL)
- {
- bgp = bgp_lookup_by_vrf_id (vrf);
- if (bgp == NULL)
- {
- if (uj)
- {
- json_object *json_no = NULL;
- json_no = json_object_new_object();
- json_object_string_add(json_no, "warning", "Can't find BGP view");
- vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
- json_object_free(json_no);
- }
- else
- vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
- else
- bgp = NULL;
-
/* neighbors <A.B.C.D|X:X::X:X|WORD> */
argv_find (argv, argc, "neighbors", &idx);
peerstr = argv[++idx]->arg;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index c7bcfe25f9..bafc81eaf8 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -22,7 +22,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "prefix.h"
#include "filter.h"
-#include "vty.h"
#include "routemap.h"
#include "command.h"
#include "linklist.h"
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 884523919e..06e443b25a 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -23,7 +23,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "prefix.h"
#include "memory.h"
#include "sockunion.h"
-#include "vty.h"
#include "queue.h"
#include "filter.h"
#include "command.h"
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index ae3571e83d..34c7691c26 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -214,10 +214,10 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
}
/*
- * bgp_vty_find_and_parse_afi_safi_vrf
+ * bgp_vty_find_and_parse_afi_safi_bgp
*
- * For a given 'show ...' command, correctly parse the afi/safi/vrf out from it
- * This function *assumes* that the calling function pre-sets the afi/safi/vrf
+ * For a given 'show ...' command, correctly parse the afi/safi/bgp out from it
+ * This function *assumes* that the calling function pre-sets the afi/safi/bgp
* to appropriate values for the calling function. This is to allow the
* calling function to make decisions appropriate for the show command
* that is being parsed.
@@ -238,7 +238,7 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
* idx -> The current place in the command, generally should be 0 for this function
* afi -> The parsed afi if it was included in the show command, returned here
* safi -> The parsed safi if it was included in the show command, returned here
- * vrf -> The parsed vrf id if it was included in the show command, returned here
+ * bgp -> Pointer to the bgp data structure we need to fill in.
*
* The function returns the correct location in the parse tree for the
* last token found.
@@ -247,14 +247,14 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
* it found the last token.
*/
int
-bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
- afi_t *afi, safi_t *safi, vrf_id_t *vrf)
+bgp_vty_find_and_parse_afi_safi_bgp (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
+ afi_t *afi, safi_t *safi, struct bgp **bgp)
{
char *vrf_name = NULL;
assert (afi);
assert (safi);
- assert (vrf && *vrf != VRF_UNKNOWN);
+ assert (bgp);
if (argv_find (argv, argc, "ip", idx))
*afi = AFI_IP;
@@ -263,26 +263,34 @@ bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, i
{
vrf_name = argv[*idx + 1]->arg;
*idx += 2;
- }
-
- if (argv_find_and_parse_afi (argv, argc, idx, afi))
- argv_find_and_parse_safi (argv, argc, idx, safi);
- if (vrf_name)
- {
- if (strmatch(vrf_name, "all"))
- *vrf = VRF_ALL;
+ if (strmatch (vrf_name, "all"))
+ *bgp = NULL;
else
- *vrf = vrf_name_to_id (vrf_name);
+ {
+ *bgp = bgp_lookup_by_name (vrf_name);
+ if (!*bgp)
+ {
+ vty_out (vty, "View/Vrf specified is unknown: %s%s", vrf_name, VTY_NEWLINE);
+ *idx = 0;
+ return 0;
+ }
+ }
}
-
- if (*vrf == VRF_UNKNOWN)
+ else
{
- vty_out (vty, "View/Vrf specified is unknown: %s", vrf_name);
- *idx = 0;
- return 0;
+ *bgp = bgp_get_default ();
+ if (!*bgp)
+ {
+ vty_out (vty, "Unable to find default BGP instance%s", VTY_NEWLINE);
+ *idx = 0;
+ return 0;
+ }
}
+ if (argv_find_and_parse_afi (argv, argc, idx, afi))
+ argv_find_and_parse_safi (argv, argc, idx, safi);
+
*idx += 1;
return *idx;
}
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 13e67d112e..33d24d530e 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -64,6 +64,6 @@ extern int
argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi);
extern int
-bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
- afi_t *afi, safi_t *safi, vrf_id_t *vrf);
+bgp_vty_find_and_parse_afi_safi_bgp (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
+ afi_t *afi, safi_t *safi, struct bgp **bgp);
#endif /* _QUAGGA_BGP_VTY_H */
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index f0f2ed87bd..eba030e6f9 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "qobj.h"
#include "lib/json.h"
#include "vrf.h"
+#include "vty.h"
/* For union sockunion. */
#include "queue.h"
diff --git a/doc/cli.md b/doc/cli.md
new file mode 100644
index 0000000000..559f75a740
--- /dev/null
+++ b/doc/cli.md
@@ -0,0 +1,356 @@
+FRR Command Line Interface
+==========================
+
+Definition Grammar
+------------------
+
+This is a reference for the syntax used when defining new CLI commands. An
+example definition is:
+
+DEFUN (command_name,
+ command_name_cmd,
+--> "example <command|line [interface]> DEFINITION...",
+ <..doc strings..>)
+
+The arrowed part is the definition string.
+
+Explicit syntax rules in Flex and Bison may be found in lib/command_lex.l and
+lib/command_parse.y, respectively. If you can read BNF and regex those will be
+more useful than this document.
+
+If the parser is throwing syntax or other errors and you can't figure out why,
+it's unlikely to be a bug in the parser. If the error message is not useful,
+please file a bug for a better error message. If all else fails, read the token
+definitions in the lexer source and the Bison BNF in the parser source.
+
+Characters allowed in each token type:
+
+Tokens
+------
+* WORD -- A token that begins with +, -, or a lowercase letter. It is
+ an unchanging part of the command and will only match itself.
+ Example: "show ip bgp", every token is a WORD.
+* IPV4 -- 'A.B.C.D', matches an IPv4 address.
+* IPV6 -- 'X:X::X:X', matches an IPv6 address.
+* IPV4_PREFIX -- 'A.B.C.D/M', matches an IPv4 prefix in CIDR notation.
+* IPV6_PREFIX -- 'X:X::X:X/M', matches an IPv6 prefix in CIDR notation.
+* VARIABLE -- Begins with a capital letter. Matches any input.
+* RANGE -- Numeric range delimited by parentheses, e.g. (-100 - 100) or
+ (10-20). Will only match numbers in the range.
+
+Rules
+-----
+* <angle|brackets> -- Contain sequences of tokens separated by pipes and
+ provide mutual exclusion. Sequences may contain
+ <mutual|exclusion> but not as the first token.
+ Disallowed: "example <<a|b> c|d>"
+ Allowed: "example <a c|b c|d>
+* [square brackets] -- Contains sequences of tokens that are optional (can be
+ omitted).
+* {curly|braces} -- similar to angle brackets, but instead of mutual
+ exclusion, curly braces indicate that one or more of the
+ pipe-separated sequences may be provided in any order.
+* VARIADICS... -- Any token which accepts input (so anything except WORD)
+ and that occurs as the last token of a line may be
+ followed by an ellipsis, which indicates that input
+ matching the token may be repeated an unlimited number
+ of times.
+
+Some general notes:
+
+* Options are allowed at the beginning of the command. The developer is
+ entreated to use these extremely sparingly. They are most useful for
+ implementing the 'no' form of configuration commands. Please think carefully
+ before using them for anything else. There is usually a better solution, even
+ if it is just separating out the command definition into separate ones.
+
+* The developer should judiciously apply separation of concerns when defining
+ CLI. CLI definitions for two unrelated or vaguely related commands or
+ configuration items should be defined in separate commands. Clarity is
+ preferred over LOC (within reason).
+
+Doc Strings
+-----------
+Each token in a command definition should be documented with a brief doc
+string that informs a user of the meaning and/or purpose of the subsequent
+command tree. These strings are provided as the last parameter to DEFUN macros,
+concatenated together and separated by an escaped newline ('\n'). These are
+best explained by example.
+
+DEFUN (config_terminal,
+ config_terminal_cmd,
+ "configure terminal",
+ "Configuration from vty interface\n"
+ "Configuration terminal\n")
+
+The last parameter is split into two lines for readability. Two newline
+delimited doc strings are present, one for each token in the command. The
+second string documents the functionality of the 'terminal' command in the
+'configure' tree.
+
+Note that the first string, for 'configure' does not contain documentation for
+'terminal'. This is because the CLI is best envisioned as a tree, with tokens
+defining branches. An imaginary 'start' token is the root of every command in a
+CLI node. Each subsequent written token descends into a subtree, so the
+documentation for that token ideally summarizes all the functionality contained
+in the subtree.
+
+A consequence of this structure is that the developer must be careful to use
+the same doc strings when defining multiple commands that are part of the same
+tree. Commands which share prefixes must share the same doc strings for those
+prefixes. On startup the parser will generate warnings if it notices
+inconsistent doc strings. Behavior is undefined; the same token may show up
+twice in completions, with different doc strings, or it may show up once with a
+random doc string. Parser warnings should be heeded and fixed to avoid
+confusing users.
+
+The number of doc strings provided must be equal to the amount of tokens
+present in the command definition, read left to right, ignoring any special
+constructs.
+
+In the examples below, each arrowed token needs a doc string.
+
+ "show ip bgp"
+ ^ ^ ^
+
+ "command <foo|bar> [example]"
+ ^ ^ ^ ^
+
+Data Structures
+---------------
+On startup, the CLI parser sequentially parses each command string definition
+and constructs a directed graph with each token forming a node. This graph is
+the basis of the entire CLI system. It is used to match user input in order to
+generate command completions and match commands to functions.
+
+There is one graph per CLI node (not the same as a graph node in the CLI
+graph). The CLI node struct keeps a reference to its graph (see lib/command.h).
+
+While most of the graph maintains the form of a tree, special constructs
+outlined in the Rules section introduce some quirks. <>, [] and {} form
+self-contained 'subgraphs'. Each subgraph is a tree except that all of the
+'leaves' actually share a child node. This helps with minimizing graph size and
+debugging.
+
+As an example, the subgraph generated by <foo|bar> looks like this:
+
+ .
+ .
+ |
+ +----+---+
+ +--- -+ FORK +----+
+ | +--------+ |
+ +--v---+ +--v---+
+ | foo | | bar |
+ +--+---+ +--+---+
+ | +------+ |
+ +------> JOIN <-----+
+ +---+--+
+ |
+ .
+ .
+
+FORK and JOIN nodes are plumbing nodes that don't correspond to user input.
+They're necessary in order to deduplicate these constructs where applicable.
+
+Options follow the same form, except that there is an edge from the FORK node
+to the JOIN node.
+
+Keywords follow the same form, except that there is an edge from JOIN to FORK.
+Because of this the CLI graph cannot be called acyclic. There is special logic
+in the input matching code that keeps a stack of paths already taken through
+the node in order to disallow following the same path more than once.
+
+Variadics are a bit special; they have an edge back to themselves, which allows
+repeating the same input indefinitely.
+
+The leaves of the graph are nodes that have no out edges. These nodes are
+special; their data section does not contain a token, as most nodes do, or
+NULL, as in FORK/JOIN nodes, but instead has a pointer to a cmd_element. All
+paths through the graph that terminate on a leaf are guaranteed to be defined
+by that command. When a user enters a complete command, the command matcher
+tokenizes the input and executes a DFS on the CLI graph. If it is
+simultaneously able to exhaust all input (one input token per graph node), and
+then find exactly one leaf connected to the last node it reaches, then the
+input has matched the corresponding command and the command is executed. If it
+finds more than one node, then the command is ambiguous (more on this in
+deduplication). If it cannot exhaust all input, the command is unknown. If it
+exhausts all input but does not find an edge node, the command is incomplete.
+
+The parser uses an incremental strategy to build the CLI graph for a node. Each
+command is parsed into its own graph, and then this graph is merged into the
+overall graph. During this merge step, the parser makes a best-effort attempt
+to remove duplicate nodes. If it finds a node in the overall graph that is
+equal to a node in the corresponding position in the command graph, it will
+intelligently merge the properties from the node in the command graph into the
+already-existing node. Subgraphs are also checked for isomorphism and merged
+where possible. The definition of whether two nodes are 'equal' is based on the
+equality of some set of token properties; read the parser source for the most
+up-to-date definition of equality.
+
+When the parser is unable to deduplicate some complicated constructs, this
+can result in two identical paths through separate parts of the graph. If
+this occurs and the user enters input that matches these paths, they will
+receive an 'ambiguous command' error and will be unable to execute the command.
+Most of the time the parser can detect and warn about duplicate commands, but
+it will not always be able to do this. Hence care should be taken before
+defining a new command to ensure it is not defined elsewhere.
+
+
+Command handlers
+----------------
+The block that follows a CLI definition is executed when a user enters input
+that matches the definition. Its function signature looks like this:
+
+int (*func) (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
+
+The first argument is the command definition struct. The last argument is an
+ordered array of tokens that correspond to the path taken through the graph,
+and the argument just prior to that is the length of the array.
+
+The arrangement of the token array has changed from the prior incarnation of
+the CLI system. In the old system, missing arguments were padded with NULLs so
+that the same parts of a command would show up at the same indices regardless
+of what was entered. The new system does not perform such padding and therefore
+it is generally _incorrect_ to assume consistent indices in this array. As a
+simple example:
+
+Command definition:
+ command [foo] <bar|baz>
+
+User enters:
+ command foo bar
+
+Array:
+ [0] -> command
+ [1] -> foo
+ [2] -> bar
+
+User enters:
+ command baz
+
+Array:
+ [0] -> command
+ [1] -> baz
+
+
+
+Command abbreviation & matching priority
+----------------------------------------
+As in the prior implementation, it is possible for users to elide parts of
+tokens when the CLI matcher does not need them to make an unambiguous match.
+This is best explained by example.
+
+Command definitions:
+ command dog cow
+ command dog crow
+
+User input:
+ c d c -> ambiguous command
+ c d co -> match "command dog cow"
+
+In the new implementation, this functionality has improved. Where previously
+the parser would stop at the first ambiguous token, it will now look ahead and
+attempt to disambiguate based on tokens later on in the input string.
+
+Command definitions:
+ show ip bgp A.B.C.D
+ show ipv6 bgp X:X::X:X
+
+User enters:
+ s i b 4.3.2.1 -> match "show ip bgp A.B.C.D"
+ s i b ::e0 -> match "show ipv6 bgp X:X::X:X"
+
+Previously both of these commands would be ambiguous since 'i' does not
+explicitly select either 'ip' or 'ipv6'. However, since the user later provides
+a token that matches only one of the commands (an IPv4 or IPv6 address) the
+parser is able to look ahead and select the appropriate command. This has some
+implications for parsing the argv*[] that is passed to the command handler.
+
+Now consider a command definition such as:
+ command <foo|VAR>
+
+'foo' only matches the string 'foo', but 'VAR' matches any input, including
+'foo'. Who wins? In situations like this the matcher will always choose the
+'better' match, so 'foo' will win.
+
+Consider also:
+ show <ip|ipv6> foo
+
+User input:
+ show ip foo
+
+'ip' partially matches 'ipv6' but exactly matches 'ip', so 'ip' will win.
+
+
+struct cmd_token
+----------------
+
+/* Command token struct. */
+struct cmd_token
+{
+ enum cmd_token_type type; // token type
+ u_char attr; // token attributes
+ bool allowrepeat; // matcher allowed to match token repetitively?
+
+ char *text; // token text
+ char *desc; // token description
+ long long min, max; // for ranges
+ char *arg; // user input that matches this token
+};
+
+This struct is used in the CLI graph to match input against. It is also used to
+pass user input to command handler functions, as it is frequently useful for
+handlers to have access to that information. When a command is matched, the
+sequence of cmd_tokens that form the matching path are duplicated and placed in
+order into argv*[]. Before this happens the ->arg field is set to point at the
+snippet of user input that matched it.
+
+For most nontrivial commands the handler function will need to determine which
+of the possible matching inputs was entered. Previously this was done by
+looking at the first few characters of input. This is now considered an
+anti-pattern and should be avoided. Instead, the ->type or ->text fields for
+this logic. The ->type field can be used when the possible inputs differ in
+type. When the possible types are the same, use the ->text field. This field
+has the full text of the corresponding token in the definition string and using
+it makes for much more readable code. An example is helpful.
+
+Command definition:
+ command <(1-10)|foo|BAR>
+
+In this example, the user may enter any one of:
+ * an integer between 1 and 10
+ * "foo"
+ * anything at all
+
+If the user enters "command f", then:
+
+argv[1]->type == WORD_TKN
+argv[1]->arg == "f"
+argv[1]->text == "foo"
+
+Range tokens have some special treatment; a token with ->type == RANGE_TKN will
+have the ->min and ->max fields set to the bounding values of the range.
+
+
+Permutations
+------------
+Finally, it is sometimes useful to check all the possible combinations of input
+that would match an arbitrary definition string. There is a tool in tools/
+called 'permutations' that reads CLI definition strings on stdin and prints out
+all matching input permutations. It also dumps a text representation of the
+graph, which is more useful for debugging than anything else. It looks like
+this:
+
+$ ./permutations "show [ip] bgp [<view|vrf> WORD]"
+
+show ip bgp view WORD
+show ip bgp vrf WORD
+show ip bgp
+show bgp view WORD
+show bgp vrf WORD
+show bgp
+
+This functionality is also built into VTY/VTYSH; the 'list permutations'
+command will list all possible matching input permutations in the current CLI
+node.
diff --git a/lib/plist.c b/lib/plist.c
index 9a2fc4af09..3ed5c8fc5c 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -27,7 +27,6 @@
#include "plist.h"
#include "sockunion.h"
#include "buffer.h"
-#include "stream.h"
#include "log.h"
#include "routemap.h"
#include "lib/json.h"
diff --git a/lib/plist.h b/lib/plist.h
index 2c6f13a5c4..89d9a874f0 100644
--- a/lib/plist.h
+++ b/lib/plist.h
@@ -23,6 +23,11 @@
#ifndef _QUAGGA_PLIST_H
#define _QUAGGA_PLIST_H
+#include <zebra.h>
+
+#include "stream.h"
+#include "vty.h"
+
enum prefix_list_type
{
PREFIX_DENY,
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 62d8ad8e07..3236eb07b6 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -2342,44 +2342,6 @@ static void mroute_del_all()
}
}
-static void static_mroute_add_all()
-{
- struct listnode *node;
- struct static_route *s_route;
-
- for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
- if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
- /* just log warning */
- char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC",
- __FILE__, __PRETTY_FUNCTION__,
- source_str, group_str);
- }
- }
-}
-
-static void static_mroute_del_all()
-{
- struct listnode *node;
- struct static_route *s_route;
-
- for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
- if (pim_mroute_del(&s_route->c_oil, __PRETTY_FUNCTION__)) {
- /* just log warning */
- char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC",
- __FILE__, __PRETTY_FUNCTION__,
- source_str, group_str);
- }
- }
-}
-
DEFUN (clear_ip_mroute,
clear_ip_mroute_cmd,
"clear ip mroute",
@@ -2670,12 +2632,12 @@ DEFUN (show_ip_pim_state,
if (uj)
argc--;
- if (argc == 5)
+ if (argc == 6)
{
src_or_group = argv[4]->arg;
group = argv[5]->arg;
}
- else if (argc == 4)
+ else if (argc == 5)
src_or_group = argv[4]->arg;
pim_show_state(vty, src_or_group, group, uj);
@@ -2815,22 +2777,16 @@ DEFUN (show_ip_multicast,
{
time_t now = pim_time_monotonic_sec();
- if (PIM_MROUTE_IS_ENABLED) {
- char uptime[10];
+ char uptime[10];
- vty_out(vty, "Mroute socket descriptor: %d%s",
- qpim_mroute_socket_fd,
- VTY_NEWLINE);
+ vty_out(vty, "Mroute socket descriptor: %d%s",
+ qpim_mroute_socket_fd,
+ VTY_NEWLINE);
- pim_time_uptime(uptime, sizeof(uptime), now - qpim_mroute_socket_creation);
- vty_out(vty, "Mroute socket uptime: %s%s",
- uptime,
- VTY_NEWLINE);
- }
- else {
- vty_out(vty, "Multicast disabled%s",
- VTY_NEWLINE);
- }
+ pim_time_uptime(uptime, sizeof(uptime), now - qpim_mroute_socket_creation);
+ vty_out(vty, "Mroute socket uptime: %s%s",
+ uptime,
+ VTY_NEWLINE);
vty_out(vty, "%s", VTY_NEWLINE);
@@ -3570,31 +3526,24 @@ DEFUN (no_ip_pim_rp_prefix_list,
return pim_no_rp_cmd_worker (vty, argv[4]->arg, NULL, argv[6]->arg);
}
-DEFUN (ip_multicast_routing,
- ip_multicast_routing_cmd,
- "ip multicast-routing",
- IP_STR
- "Enable IP multicast forwarding\n")
+DEFUN_HIDDEN (ip_multicast_routing,
+ ip_multicast_routing_cmd,
+ "ip multicast-routing",
+ IP_STR
+ "Enable IP multicast forwarding\n")
{
- pim_mroute_socket_enable();
- pim_if_add_vif_all();
- mroute_add_all();
- static_mroute_add_all();
return CMD_SUCCESS;
}
-DEFUN (no_ip_multicast_routing,
- no_ip_multicast_routing_cmd,
- "no ip multicast-routing",
- NO_STR
- IP_STR
- "Global IP configuration subcommands\n"
- "Enable IP multicast forwarding\n")
+DEFUN_HIDDEN (no_ip_multicast_routing,
+ no_ip_multicast_routing_cmd,
+ "no ip multicast-routing",
+ NO_STR
+ IP_STR
+ "Global IP configuration subcommands\n"
+ "Enable IP multicast forwarding\n")
{
- mroute_del_all();
- static_mroute_del_all();
- pim_if_del_vif_all();
- pim_mroute_socket_disable();
+ vty_out (vty, "Command is Disabled and will be removed in a future version%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -3657,13 +3606,9 @@ DEFUN (no_ip_ssmpingd,
return CMD_SUCCESS;
}
-DEFUN (interface_ip_igmp,
- interface_ip_igmp_cmd,
- "ip igmp",
- IP_STR
- IFACE_IGMP_STR)
+static int
+pim_cmd_igmp_start (struct vty *vty, struct interface *ifp)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
pim_ifp = ifp->info;
@@ -3686,6 +3631,17 @@ DEFUN (interface_ip_igmp,
return CMD_SUCCESS;
}
+DEFUN (interface_ip_igmp,
+ interface_ip_igmp_cmd,
+ "ip igmp",
+ IP_STR
+ IFACE_IGMP_STR)
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+
+ return pim_cmd_igmp_start(vty, ifp);
+}
+
DEFUN (interface_no_ip_igmp,
interface_no_ip_igmp_cmd,
"no ip igmp",
@@ -3949,15 +3905,15 @@ DEFUN (interface_ip_igmp_query_interval,
struct pim_interface *pim_ifp;
int query_interval;
int query_interval_dsec;
+ int ret;
pim_ifp = ifp->info;
if (!pim_ifp) {
- vty_out(vty,
- "IGMP not enabled on interface %s. Please enable IGMP first.%s",
- ifp->name,
- VTY_NEWLINE);
- return CMD_WARNING;
+ ret = pim_cmd_igmp_start(vty, ifp);
+ if (ret != CMD_SUCCESS)
+ return ret;
+ pim_ifp = ifp->info;
}
query_interval = atoi(argv[3]->arg);
@@ -4038,15 +3994,15 @@ DEFUN (interface_ip_igmp_version,
VTY_DECLVAR_CONTEXT(interface,ifp);
struct pim_interface *pim_ifp;
int igmp_version;
+ int ret;
pim_ifp = ifp->info;
if (!pim_ifp) {
- vty_out(vty,
- "IGMP not enabled on interface %s. Please enable IGMP first.%s",
- ifp->name,
- VTY_NEWLINE);
- return CMD_WARNING;
+ ret = pim_cmd_igmp_start(vty, ifp);
+ if (ret != CMD_SUCCESS)
+ return ret;
+ pim_ifp = ifp->info;
}
igmp_version = atoi(argv[3]->arg);
@@ -4091,15 +4047,15 @@ DEFUN (interface_ip_igmp_query_max_response_time,
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
int query_max_response_time;
+ int ret;
pim_ifp = ifp->info;
if (!pim_ifp) {
- vty_out(vty,
- "IGMP not enabled on interface %s. Please enable IGMP first.%s",
- ifp->name,
- VTY_NEWLINE);
- return CMD_WARNING;
+ ret = pim_cmd_igmp_start(vty, ifp);
+ if (ret != CMD_SUCCESS)
+ return ret;
+ pim_ifp = ifp->info;
}
query_max_response_time = atoi(argv[3]->arg);
@@ -4154,15 +4110,15 @@ DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
struct pim_interface *pim_ifp;
int query_max_response_time_dsec;
int default_query_interval_dsec;
+ int ret;
pim_ifp = ifp->info;
if (!pim_ifp) {
- vty_out(vty,
- "IGMP not enabled on interface %s. Please enable IGMP first.%s",
- ifp->name,
- VTY_NEWLINE);
- return CMD_WARNING;
+ ret = pim_cmd_igmp_start(vty, ifp);
+ if (ret != CMD_SUCCESS)
+ return ret;
+ pim_ifp = ifp->info;
}
query_max_response_time_dsec = atoi(argv[4]->arg);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 8f7d40bb36..c545b56330 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -173,9 +173,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
pim_sock_reset(ifp);
- if (PIM_MROUTE_IS_ENABLED) {
- pim_if_add_vif(ifp);
- }
+ pim_if_add_vif(ifp);
return pim_ifp;
}
@@ -197,9 +195,7 @@ void pim_if_delete(struct interface *ifp)
pim_neighbor_delete_all (ifp, "Interface removed from configuration");
- if (PIM_MROUTE_IS_ENABLED) {
- pim_if_del_vif(ifp);
- }
+ pim_if_del_vif(ifp);
list_delete(pim_ifp->igmp_socket_list);
list_delete(pim_ifp->pim_neighbor_list);
@@ -591,16 +587,14 @@ void pim_if_addr_add(struct connected *ifc)
}
} /* pim */
- if (PIM_MROUTE_IS_ENABLED) {
/*
PIM or IGMP is enabled on interface, and there is at least one
address assigned, then try to create a vif_index.
*/
- if (pim_ifp->mroute_vif_index < 0) {
- pim_if_add_vif(ifp);
- }
- pim_ifchannel_scan_forward_start (ifp);
+ if (pim_ifp->mroute_vif_index < 0) {
+ pim_if_add_vif(ifp);
}
+ pim_ifchannel_scan_forward_start (ifp);
}
static void pim_if_addr_del_igmp(struct connected *ifc)
@@ -730,16 +724,14 @@ void pim_if_addr_add_all(struct interface *ifp)
}
} /* pim */
}
- if (PIM_MROUTE_IS_ENABLED) {
- /*
- * PIM or IGMP is enabled on interface, and there is at least one
- * address assigned, then try to create a vif_index.
- */
- if (pim_ifp->mroute_vif_index < 0) {
- pim_if_add_vif(ifp);
- }
- pim_ifchannel_scan_forward_start (ifp);
+ /*
+ * PIM or IGMP is enabled on interface, and there is at least one
+ * address assigned, then try to create a vif_index.
+ */
+ if (pim_ifp->mroute_vif_index < 0) {
+ pim_if_add_vif(ifp);
}
+ pim_ifchannel_scan_forward_start (ifp);
pim_rp_setup();
pim_rp_check_on_if_add(pim_ifp);
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index ae5d0e9891..334e0ce06e 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -608,7 +608,6 @@ static int mroute_read(struct thread *t)
static void mroute_read_on()
{
zassert(!qpim_mroute_socket_reader);
- zassert(PIM_MROUTE_IS_ENABLED);
THREAD_READ_ON(master, qpim_mroute_socket_reader,
mroute_read, 0, qpim_mroute_socket_fd);
@@ -623,9 +622,6 @@ int pim_mroute_socket_enable()
{
int fd;
- if (PIM_MROUTE_IS_ENABLED)
- return -1;
-
if ( pimd_privs.change (ZPRIVS_RAISE) )
zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
safe_strerror (errno) );
@@ -659,9 +655,6 @@ int pim_mroute_socket_enable()
int pim_mroute_socket_disable()
{
- if (PIM_MROUTE_IS_DISABLED)
- return -1;
-
if (pim_mroute_set(qpim_mroute_socket_fd, 0)) {
zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
qpim_mroute_socket_fd, errno, safe_strerror(errno));
@@ -691,12 +684,6 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned ch
struct vifctl vc;
int err;
- if (PIM_MROUTE_IS_DISABLED) {
- zlog_warn("%s: global multicast is disabled",
- __PRETTY_FUNCTION__);
- return -1;
- }
-
memset(&vc, 0, sizeof(vc));
vc.vifc_vifi = pim_ifp->mroute_vif_index;
#ifdef VIFF_USE_IFINDEX
@@ -740,12 +727,6 @@ int pim_mroute_del_vif(int vif_index)
struct vifctl vc;
int err;
- if (PIM_MROUTE_IS_DISABLED) {
- zlog_warn("%s: global multicast is disabled",
- __PRETTY_FUNCTION__);
- return -1;
- }
-
if (PIM_DEBUG_MROUTE)
{
struct interface *ifp = pim_if_find_by_vif_index (vif_index);
@@ -777,11 +758,6 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
qpim_mroute_add_last = pim_time_monotonic_sec();
++qpim_mroute_add_events;
- if (PIM_MROUTE_IS_DISABLED) {
- zlog_warn("%s: global multicast is disabled",
- __PRETTY_FUNCTION__);
- return -1;
- }
/* Do not install route if incoming interface is undefined. */
if (c_oil->oil.mfcc_parent == MAXVIFS)
{
@@ -858,12 +834,6 @@ int pim_mroute_del (struct channel_oil *c_oil, const char *name)
qpim_mroute_del_last = pim_time_monotonic_sec();
++qpim_mroute_del_events;
- if (PIM_MROUTE_IS_DISABLED) {
- zlog_warn("%s: global multicast is disabled",
- __PRETTY_FUNCTION__);
- return -1;
- }
-
if (!c_oil->installed)
{
if (PIM_DEBUG_MROUTE)
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 03ee7e92ec..5b6a79b95a 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -148,11 +148,6 @@ int pim_global_config_write(struct vty *vty)
writes += pim_msdp_config_write (vty);
- if (PIM_MROUTE_IS_ENABLED) {
- vty_out(vty, "ip multicast-routing%s", VTY_NEWLINE);
- ++writes;
- }
-
writes += pim_rp_config_write (vty);
if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT)
diff --git a/pimd/pimd.c b/pimd/pimd.c
index 2316cd08f5..aa863fd47f 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -124,7 +124,7 @@ void pim_init()
}
qpim_static_route_list->del = (void (*)(void *)) pim_static_route_free;
- qpim_mroute_socket_fd = -1; /* mark mroute as disabled */
+ pim_mroute_socket_enable();
qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY;
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 0da8452ab5..0906016300 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -154,9 +154,6 @@ extern int qpim_packet_process;
#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)
-#define PIM_MROUTE_IS_ENABLED (qpim_mroute_socket_fd >= 0)
-#define PIM_MROUTE_IS_DISABLED (qpim_mroute_socket_fd < 0)
-
/*
* Register-Stop Timer (RST(S,G))
* Default values
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index bf2b006963..4c26300099 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -350,6 +350,8 @@ end
"ip ",
"ipv6 ",
"log ",
+ "mpls",
+ "no ",
"password ",
"ptm-enable",
"router-id ",