/*
- PIM for Quagga
- Copyright (C) 2008 Everton da Silva Marques
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING; if not, write to the
- Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- MA 02110-1301 USA
-*/
+ * PIM for Quagga
+ * Copyright (C) 2008 Everton da Silva Marques
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
#include <zebra.h>
#include "prefix.h"
#include "zclient.h"
#include "plist.h"
+#include "hash.h"
+#include "nexthop.h"
#include "pimd.h"
#include "pim_mroute.h"
#include "pim_zlookup.h"
#include "pim_msdp.h"
#include "pim_ssm.h"
+#include "pim_nht.h"
static struct cmd_node pim_global_node = {
PIM_NODE,
mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
if (uj) {
+ char pbuf[PREFIX2STR_BUFFER];
json_row = json_object_new_object();
json_object_pim_ifp_add(json_row, ifp);
sec_list = json_object_new_array();
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
- json_object_array_add(sec_list, json_object_new_string(inet_ntoa(sec_addr->addr)));
+ json_object_array_add(sec_list,
+ json_object_new_string(prefix2str(&sec_addr->addr,
+ pbuf,
+ sizeof(pbuf))));
}
json_object_object_add(json_row, "secondaryAddressList", sec_list);
}
vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE);
}
if (pim_ifp->sec_addr_list) {
+ char pbuf[PREFIX2STR_BUFFER];
vty_out(vty, "Address : %s (primary)%s",
- inet_ntoa(ifaddr), VTY_NEWLINE);
+ inet_ntoa(ifaddr), VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
vty_out(vty, " %s%s",
- inet_ntoa(sec_addr->addr), VTY_NEWLINE);
+ prefix2str(&sec_addr->addr,
+ pbuf,
+ sizeof(pbuf)), VTY_NEWLINE);
}
} else {
vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
json_object_free(json);
}
+static void pim_show_interface_traffic (struct vty *vty, u_char uj)
+{
+ struct interface *ifp = NULL;
+ struct pim_interface *pim_ifp = NULL;
+ struct listnode *node = NULL;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
+ if (uj)
+ json = json_object_new_object ();
+ else
+ {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s%s", "Interface",
+ " HELLO", " JOIN", " PRUNE", " REGISTER",
+ " REGISTER-STOP", " ASSERT", VTY_NEWLINE);
+ vty_out (vty,
+ "%-10s%-18s%-17s%-17s%-17s%-17s%-17s%s",
+ "", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
+ " Rx/Tx", " Rx/Tx", VTY_NEWLINE);
+ vty_out (vty,
+ "---------------------------------------------------------------------------------------------------------------%s",
+ VTY_NEWLINE);
+ }
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
+ {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (pim_ifp->pim_sock_fd < 0)
+ continue;
+ if (uj)
+ {
+ json_row = json_object_new_object ();
+ json_object_pim_ifp_add (json_row, ifp);
+ json_object_int_add (json_row, "helloRx", pim_ifp->pim_ifstat_hello_recv);
+ json_object_int_add (json_row, "helloTx", pim_ifp->pim_ifstat_hello_sent);
+ json_object_int_add (json_row, "joinRx", pim_ifp->pim_ifstat_join_recv);
+ json_object_int_add (json_row, "joinTx", pim_ifp->pim_ifstat_join_send);
+ json_object_int_add (json_row, "registerRx", pim_ifp->pim_ifstat_reg_recv);
+ json_object_int_add (json_row, "registerTx", pim_ifp->pim_ifstat_reg_recv);
+ json_object_int_add (json_row, "registerStopRx", pim_ifp->pim_ifstat_reg_stop_recv);
+ json_object_int_add (json_row, "registerStopTx", pim_ifp->pim_ifstat_reg_stop_send);
+ json_object_int_add (json_row, "assertRx", pim_ifp->pim_ifstat_assert_recv);
+ json_object_int_add (json_row, "assertTx", pim_ifp->pim_ifstat_assert_send);
+
+ json_object_object_add (json, ifp->name, json_row);
+ }
+ else
+ {
+ vty_out (vty,
+ "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %s",
+ ifp->name, pim_ifp->pim_ifstat_hello_recv,
+ pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv,
+ pim_ifp->pim_ifstat_join_send, pim_ifp->pim_ifstat_prune_recv,
+ pim_ifp->pim_ifstat_prune_send, pim_ifp->pim_ifstat_reg_recv,
+ pim_ifp->pim_ifstat_reg_send,
+ pim_ifp->pim_ifstat_reg_stop_recv,
+ pim_ifp->pim_ifstat_reg_stop_send,
+ pim_ifp->pim_ifstat_assert_recv,
+ pim_ifp->pim_ifstat_assert_send, VTY_NEWLINE);
+ }
+ }
+ if (uj)
+ {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext (json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free (json);
+ }
+}
+
+static void pim_show_interface_traffic_single (struct vty *vty, const char *ifname, u_char uj)
+{
+ struct interface *ifp = NULL;
+ struct pim_interface *pim_ifp = NULL;
+ struct listnode *node = NULL;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+ uint8_t found_ifname = 0;
+
+ if (uj)
+ json = json_object_new_object ();
+ else
+ {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s%s", "Interface",
+ " HELLO", " JOIN", " PRUNE", " REGISTER",
+ " REGISTER-STOP", " ASSERT", VTY_NEWLINE);
+ vty_out (vty,
+ "%-10s%-18s%-17s%-17s%-17s%-17s%-17s%s",
+ "", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
+ " Rx/Tx", " Rx/Tx", VTY_NEWLINE);
+ vty_out (vty,
+ "---------------------------------------------------------------------------------------------------------------%s",
+ VTY_NEWLINE);
+ }
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
+ {
+ if (strcmp (ifname, ifp->name))
+ continue;
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (pim_ifp->pim_sock_fd < 0)
+ continue;
+
+ found_ifname = 1;
+ if (uj)
+ {
+ json_row = json_object_new_object ();
+ json_object_pim_ifp_add (json_row, ifp);
+ json_object_int_add (json_row, "helloRx", pim_ifp->pim_ifstat_hello_recv);
+ json_object_int_add (json_row, "helloTx", pim_ifp->pim_ifstat_hello_sent);
+ json_object_int_add (json_row, "joinRx", pim_ifp->pim_ifstat_join_recv);
+ json_object_int_add (json_row, "joinTx", pim_ifp->pim_ifstat_join_send);
+ json_object_int_add (json_row, "registerRx", pim_ifp->pim_ifstat_reg_recv);
+ json_object_int_add (json_row, "registerTx", pim_ifp->pim_ifstat_reg_recv);
+ json_object_int_add (json_row, "registerStopRx", pim_ifp->pim_ifstat_reg_stop_recv);
+ json_object_int_add (json_row, "registerStopTx", pim_ifp->pim_ifstat_reg_stop_send);
+ json_object_int_add (json_row, "assertRx", pim_ifp->pim_ifstat_assert_recv);
+ json_object_int_add (json_row, "assertTx", pim_ifp->pim_ifstat_assert_send);
+
+ json_object_object_add (json, ifp->name, json_row);
+ }
+ else
+ {
+ vty_out (vty,
+ "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %s",
+ ifp->name, pim_ifp->pim_ifstat_hello_recv,
+ pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv,
+ pim_ifp->pim_ifstat_join_send, pim_ifp->pim_ifstat_prune_recv,
+ pim_ifp->pim_ifstat_prune_send, pim_ifp->pim_ifstat_reg_recv,
+ pim_ifp->pim_ifstat_reg_send,
+ pim_ifp->pim_ifstat_reg_stop_recv,
+ pim_ifp->pim_ifstat_reg_stop_send,
+ pim_ifp->pim_ifstat_assert_recv,
+ pim_ifp->pim_ifstat_assert_send, VTY_NEWLINE);
+ }
+ }
+ if (uj)
+ {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext (json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free (json);
+ }
+ else
+ {
+ if (!found_ifname)
+ vty_out (vty, "%% No such interface%s", VTY_NEWLINE);
+ }
+}
+
static void pim_show_join(struct vty *vty, u_char uj)
{
struct pim_interface *pim_ifp;
neigh_src_str, sizeof(neigh_src_str));
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) {
- char neigh_sec_str[INET_ADDRSTRLEN];
+ char neigh_sec_str[PREFIX2STR_BUFFER];
- if (p->family != AF_INET)
- continue;
-
- pim_inet4_dump("<src?>", p->u.prefix4,
- neigh_sec_str, sizeof(neigh_sec_str));
+ prefix2str(p, neigh_sec_str, sizeof(neigh_sec_str));
vty_out(vty, "%-9s %-15s %-15s %-15s%s",
ifp->name,
}
}
+static int
+pim_print_pnc_cache_walkcb (struct hash_backet *backet, void *arg)
+{
+ struct pim_nexthop_cache *pnc = backet->data;
+ struct vty *vty = arg;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+
+ if (!pnc)
+ return CMD_SUCCESS;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next)
+ {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT);
+
+ vty_out (vty, "%-15s ", inet_ntoa (pnc->rpf.rpf_addr.u.prefix4));
+ vty_out (vty, "%-14s ", ifp ? ifp->name : "NULL");
+ vty_out (vty, "%s ", inet_ntoa (nh_node->gate.ipv4));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+static void
+pim_show_nexthop (struct vty *vty)
+{
+
+ if (pimg && !pimg->rpf_hash)
+ {
+ vty_out (vty, "no nexthop cache %s", VTY_NEWLINE);
+ return;
+ }
+
+ vty_out (vty, "Number of registered addresses: %lu %s",
+ pimg->rpf_hash->count, VTY_NEWLINE);
+ vty_out (vty, "Address Interface Nexthop%s", VTY_NEWLINE);
+ vty_out (vty, "-------------------------------------------%s", VTY_NEWLINE);
+
+ hash_walk (pimg->rpf_hash, pim_print_pnc_cache_walkcb, vty);
+
+}
+
static void igmp_show_groups(struct vty *vty, u_char uj)
{
struct listnode *ifnode;
return CMD_SUCCESS;
}
+DEFUN (clear_ip_pim_interface_traffic,
+ clear_ip_pim_interface_traffic_cmd,
+ "clear ip pim interface traffic",
+ "Reset functions\n"
+ "IP information\n"
+ "PIM clear commands\n"
+ "Reset PIM interfaces\n"
+ "Reset Protocol Packet counters\n")
+{
+ struct listnode *ifnode = NULL;
+ struct listnode *ifnextnode = NULL;
+ struct interface *ifp = NULL;
+ struct pim_interface *pim_ifp = NULL;
+
+ for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp))
+ {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ pim_ifp->pim_ifstat_hello_recv = 0;
+ pim_ifp->pim_ifstat_hello_sent = 0;
+ pim_ifp->pim_ifstat_join_recv = 0;
+ pim_ifp->pim_ifstat_join_send = 0;
+ pim_ifp->pim_ifstat_prune_recv = 0;
+ pim_ifp->pim_ifstat_prune_send = 0;
+ pim_ifp->pim_ifstat_reg_recv = 0;
+ pim_ifp->pim_ifstat_reg_send = 0;
+ pim_ifp->pim_ifstat_reg_stop_recv = 0;
+ pim_ifp->pim_ifstat_reg_stop_send = 0;
+ pim_ifp->pim_ifstat_assert_recv = 0;
+ pim_ifp->pim_ifstat_assert_send = 0;
+
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (clear_ip_pim_oil,
clear_ip_pim_oil_cmd,
"clear ip pim oil",
return CMD_SUCCESS;
}
+DEFUN (show_ip_pim_nexthop,
+ show_ip_pim_nexthop_cmd,
+ "show ip pim nexthop",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM cached nexthop rpf information\n")
+{
+ pim_show_nexthop (vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_nexthop_lookup,
+ show_ip_pim_nexthop_lookup_cmd,
+ "show ip pim nexthop-lookup A.B.C.D A.B.C.D",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM cached nexthop rpf lookup\n"
+ "Source/RP address\n"
+ "Multicast Group address\n")
+{
+ struct pim_nexthop_cache pnc;
+ struct prefix nht_p;
+ int result = 0;
+ struct in_addr src_addr, grp_addr;
+ struct in_addr vif_source;
+ const char *addr_str, *addr_str1;
+ struct prefix grp;
+ struct pim_nexthop nexthop;
+ char nexthop_addr_str[PREFIX_STRLEN];
+ char grp_str[PREFIX_STRLEN];
+
+ addr_str = argv[4]->arg;
+ result = inet_pton (AF_INET, addr_str, &src_addr);
+ if (result <= 0)
+ {
+ vty_out (vty, "Bad unicast address %s: errno=%d: %s%s",
+ addr_str, errno, safe_strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (pim_is_group_224_4 (src_addr))
+ {
+ vty_out (vty, "Invalid argument. Expected Valid Source Address.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ addr_str1 = argv[5]->arg;
+ result = inet_pton (AF_INET, addr_str1, &grp_addr);
+ if (result <= 0)
+ {
+ vty_out (vty, "Bad unicast address %s: errno=%d: %s%s",
+ addr_str, errno, safe_strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!pim_is_group_224_4 (grp_addr))
+ {
+ vty_out (vty, "Invalid argument. Expected Valid Multicast Group Address.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!pim_rp_set_upstream_addr (&vif_source, src_addr, grp_addr))
+ return CMD_SUCCESS;
+
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = vif_source;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = grp_addr;
+ memset (&nexthop, 0, sizeof (nexthop));
+
+ if ((pim_find_or_track_nexthop (&nht_p, NULL, NULL, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &nexthop, &nht_p, &grp, 0);
+ }
+ else
+ pim_ecmp_nexthop_lookup (&nexthop, vif_source, &nht_p, &grp, 0);
+
+ pim_addr_dump ("<grp?>", &grp, grp_str, sizeof (grp_str));
+ pim_addr_dump ("<nexthop?>", &nexthop.mrib_nexthop_addr,
+ nexthop_addr_str, sizeof (nexthop_addr_str));
+ vty_out (vty, "Group %s --- Nexthop %s Interface %s %s", grp_str,
+ nexthop_addr_str, nexthop.interface->name, VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_interface_traffic,
+ show_ip_pim_interface_traffic_cmd,
+ "show ip pim interface traffic [WORD] [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM interface information\n"
+ "Protocol Packet counters\n"
+ "Interface name\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json (argc, argv);
+ int idx = 0;
+
+ if (argv_find(argv, argc, "WORD", &idx))
+ pim_show_interface_traffic_single (vty, argv[idx]->arg, uj);
+ else
+ pim_show_interface_traffic (vty, uj);
+
+ return CMD_SUCCESS;
+}
+
static void show_multicast_interfaces(struct vty *vty)
{
struct listnode *node;
PIM_MAX_USABLE_VIFS,
VTY_NEWLINE);
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, "Upstream Join Timer: %d secs%s",
- qpim_t_periodic,
- VTY_NEWLINE);
- vty_out(vty, "Join/Prune Holdtime: %d secs%s",
- PIM_JP_HOLDTIME,
- VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "Upstream Join Timer: %d secs%s",
+ qpim_t_periodic, VTY_NEWLINE);
+ vty_out (vty, "Join/Prune Holdtime: %d secs%s",
+ PIM_JP_HOLDTIME, VTY_NEWLINE);
+ vty_out (vty, "PIM ECMP: %s%s",
+ qpim_ecmp_enable ? "Enable" : "Disable", VTY_NEWLINE);
+ vty_out (vty, "PIM ECMP Rebalance: %s%s",
+ qpim_ecmp_rebalance_enable ? "Enable" : "Disable", VTY_NEWLINE);
- vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
show_rpf_refresh_stats(vty, now, NULL);
json_object_string_add(json_ifp_out, "group", grp_str);
json_object_boolean_true_add(json_ifp_out, "protocolStatic");
json_object_string_add(json_ifp_out, "inboundInterface", in_ifname);
- json_object_int_add(json_ifp_out, "iVifI", c_oil->oil.mfcc_parent);
+ json_object_int_add(json_ifp_out, "iVifI", s_route->c_oil.oil.mfcc_parent);
json_object_string_add(json_ifp_out, "outboundInterface", out_ifname);
json_object_int_add(json_ifp_out, "oVifI", oif_vif_index);
json_object_int_add(json_ifp_out, "ttl", ttl);
return CMD_SUCCESS;
}
+static int
+pim_cmd_spt_switchover (enum pim_spt_switchover spt, const char *plist)
+{
+ pimg->spt.switchover = spt;
+
+ switch (pimg->spt.switchover)
+ {
+ case PIM_SPT_IMMEDIATE:
+ if (pimg->spt.plist)
+ XFREE (MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist);
+
+ pim_upstream_add_lhr_star_pimreg ();
+ break;
+ case PIM_SPT_INFINITY:
+ pim_upstream_remove_lhr_star_pimreg (plist);
+
+ if (pimg->spt.plist)
+ XFREE (MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist);
+
+ if (plist)
+ pimg->spt.plist = XSTRDUP (MTYPE_PIM_SPT_PLIST_NAME, plist);
+ break;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_spt_switchover_infinity,
+ ip_pim_spt_switchover_infinity_cmd,
+ "ip pim spt-switchover infinity-and-beyond",
+ IP_STR
+ PIM_STR
+ "SPT-Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ return pim_cmd_spt_switchover (PIM_SPT_INFINITY, NULL);
+}
+
+DEFUN (ip_pim_spt_switchover_infinity_plist,
+ ip_pim_spt_switchover_infinity_plist_cmd,
+ "ip pim spt-switchover infinity-and-beyond prefix-list WORD",
+ IP_STR
+ PIM_STR
+ "SPT-Switchover\n"
+ "Never switch to SPT Tree\n"
+ "Prefix-List to control which groups to switch\n"
+ "Prefix-List name\n")
+{
+ return pim_cmd_spt_switchover (PIM_SPT_INFINITY, argv[5]->arg);
+}
+
+DEFUN (no_ip_pim_spt_switchover_infinity,
+ no_ip_pim_spt_switchover_infinity_cmd,
+ "no ip pim spt-switchover infinity-and-beyond",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "SPT_Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ return pim_cmd_spt_switchover (PIM_SPT_IMMEDIATE, NULL);
+}
+
+DEFUN (no_ip_pim_spt_switchover_infinity_plist,
+ no_ip_pim_spt_switchover_infinity_plist_cmd,
+ "no ip pim spt-switchover infinity-and-beyond prefix-list WORD",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "SPT_Switchover\n"
+ "Never switch to SPT Tree\n"
+ "Prefix-List to control which groups to switch\n"
+ "Prefix-List name\n")
+{
+ return pim_cmd_spt_switchover (PIM_SPT_IMMEDIATE, NULL);
+}
+
DEFUN (ip_pim_joinprune_time,
ip_pim_joinprune_time_cmd,
- "ip pim join-prune-interval <60-600>",
+ "ip pim join-prune-interval (60-600)",
IP_STR
"pim multicast routing\n"
"Join Prune Send Interval\n"
DEFUN (no_ip_pim_joinprune_time,
no_ip_pim_joinprune_time_cmd,
- "no ip pim join-prune-interval <60-600>",
+ "no ip pim join-prune-interval (60-600)",
NO_STR
IP_STR
"pim multicast routing\n"
DEFUN (ip_pim_register_suppress,
ip_pim_register_suppress_cmd,
- "ip pim register-suppress-time <5-60000>",
+ "ip pim register-suppress-time (5-60000)",
IP_STR
"pim multicast routing\n"
"Register Suppress Timer\n"
"Seconds\n")
{
- qpim_keep_alive_time = atoi (argv[3]->arg);
+ qpim_register_suppress_time = atoi (argv[3]->arg);
return CMD_SUCCESS;
}
DEFUN (no_ip_pim_register_suppress,
no_ip_pim_register_suppress_cmd,
- "no ip pim register-suppress-time <5-60000>",
+ "no ip pim register-suppress-time (5-60000)",
NO_STR
IP_STR
"pim multicast routing\n"
DEFUN (ip_pim_keep_alive,
ip_pim_keep_alive_cmd,
- "ip pim keep-alive-timer <31-60000>",
+ "ip pim keep-alive-timer (31-60000)",
IP_STR
"pim multicast routing\n"
"Keep alive Timer\n"
"Seconds\n")
{
- qpim_rp_keep_alive_time = atoi (argv[4]->arg);
+ qpim_keep_alive_time = atoi (argv[3]->arg);
return CMD_SUCCESS;
}
DEFUN (no_ip_pim_keep_alive,
no_ip_pim_keep_alive_cmd,
- "no ip pim keep-alive-timer <31-60000>",
+ "no ip pim keep-alive-timer (31-60000)",
NO_STR
IP_STR
"pim multicast routing\n"
DEFUN (ip_pim_packets,
ip_pim_packets_cmd,
- "ip pim packets <1-100>",
+ "ip pim packets (1-100)",
IP_STR
"pim multicast routing\n"
"packets to process at one time per fd\n"
DEFUN (no_ip_pim_packets,
no_ip_pim_packets_cmd,
- "no ip pim packets <1-100>",
+ "no ip pim packets (1-100)",
NO_STR
IP_STR
"pim multicast routing\n"
return CMD_SUCCESS;
}
+DEFUN (ip_pim_v6_secondary,
+ ip_pim_v6_secondary_cmd,
+ "ip pim send-v6-secondary",
+ IP_STR
+ "pim multicast routing\n"
+ "Send v6 secondary addresses\n")
+{
+ pimg->send_v6_secondary = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_v6_secondary,
+ no_ip_pim_v6_secondary_cmd,
+ "no ip pim send-v6-secondary",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Send v6 secondary addresses\n")
+{
+ pimg->send_v6_secondary = 0;
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ip_pim_rp,
ip_pim_rp_cmd,
"ip pim rp A.B.C.D [A.B.C.D/M]",
int idx_ipv4 = 3;
if (argc == (idx_ipv4 + 1))
- return pim_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
- else
return pim_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL);
+ else
+ return pim_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
+
}
DEFUN (ip_pim_rp_prefix_list,
"ip address of RP\n"
"Group Address range to cover\n")
{
- int idx_ipv4 = 4;
+ int idx_ipv4 = 4, idx_group = 0;
- if (argc == (idx_ipv4 + 1))
- return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
+ if (argv_find (argv, argc, "A.B.C.D/M", &idx_group))
+ return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_group]->arg, NULL);
else
return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL);
}
int idx_ipv4 = 2;
int result;
struct in_addr source_addr;
- const char *source_str = (argc == idx_ipv4) ? argv[idx_ipv4]->arg : "0.0.0.0";
+ const char *source_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0";
result = inet_pton(AF_INET, source_str, &source_addr);
if (result <= 0) {
int idx_ipv4 = 3;
int result;
struct in_addr source_addr;
- const char *source_str = (argc == idx_ipv4) ? argv[idx_ipv4]->arg : "0.0.0.0";
+ const char *source_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0";
result = inet_pton(AF_INET, source_str, &source_addr);
if (result <= 0) {
return CMD_SUCCESS;
}
+DEFUN (ip_pim_ecmp,
+ ip_pim_ecmp_cmd,
+ "ip pim ecmp",
+ IP_STR
+ "pim multicast routing\n"
+ "Enable PIM ECMP \n")
+{
+ qpim_ecmp_enable = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_ecmp,
+ no_ip_pim_ecmp_cmd,
+ "no ip pim ecmp",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Disable PIM ECMP \n")
+{
+ qpim_ecmp_enable = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_ecmp_rebalance,
+ ip_pim_ecmp_rebalance_cmd,
+ "ip pim ecmp rebalance",
+ IP_STR
+ "pim multicast routing\n"
+ "Enable PIM ECMP \n"
+ "Enable PIM ECMP Rebalance\n")
+{
+ qpim_ecmp_enable = 1;
+ qpim_ecmp_rebalance_enable = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_ecmp_rebalance,
+ no_ip_pim_ecmp_rebalance_cmd,
+ "no ip pim ecmp rebalance",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Disable PIM ECMP \n"
+ "Disable PIM ECMP Rebalance\n")
+{
+ qpim_ecmp_rebalance_enable = 0;
+
+ return CMD_SUCCESS;
+}
+
static int
pim_cmd_igmp_start (struct vty *vty, struct interface *ifp)
{
struct pim_interface *pim_ifp;
+ uint8_t need_startup = 0;
pim_ifp = ifp->info;
- if (!pim_ifp) {
- pim_ifp = pim_if_new(ifp, 1 /* igmp=true */, 0 /* pim=false */);
- if (!pim_ifp) {
- vty_out(vty, "Could not enable IGMP on interface %s%s",
+ if (!pim_ifp)
+ {
+ pim_ifp = pim_if_new(ifp, 1 /* igmp=true */, 0 /* pim=false */);
+ if (!pim_ifp)
+ {
+ vty_out(vty, "Could not enable IGMP on interface %s%s",
ifp->name, VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_WARNING;
+ }
+ need_startup = 1;
+ }
+ else
+ {
+ if (!PIM_IF_TEST_IGMP(pim_ifp->options))
+ {
+ PIM_IF_DO_IGMP(pim_ifp->options);
+ need_startup = 1;
+ }
}
- }
- else {
- PIM_IF_DO_IGMP(pim_ifp->options);
- }
- pim_if_addr_add_all(ifp);
- pim_if_membership_refresh(ifp);
+ /* 'ip igmp' executed multiple times, with need_startup
+ avoid multiple if add all and membership refresh */
+ if (need_startup)
+ {
+ pim_if_addr_add_all(ifp);
+ pim_if_membership_refresh(ifp);
+ }
return CMD_SUCCESS;
}
"IGMP version number\n")
{
VTY_DECLVAR_CONTEXT(interface,ifp);
- struct pim_interface *pim_ifp;
- int igmp_version;
+ struct pim_interface *pim_ifp = NULL;
+ int igmp_version, old_version = 0;
int ret;
pim_ifp = ifp->info;
- if (!pim_ifp) {
- ret = pim_cmd_igmp_start(vty, ifp);
- if (ret != CMD_SUCCESS)
- return ret;
- pim_ifp = ifp->info;
- }
+ if (!pim_ifp)
+ {
+ ret = pim_cmd_igmp_start(vty, ifp);
+ if (ret != CMD_SUCCESS)
+ return ret;
+ pim_ifp = ifp->info;
+ }
igmp_version = atoi(argv[3]->arg);
+ old_version = pim_ifp->igmp_version;
pim_ifp->igmp_version = igmp_version;
+ //Check if IGMP is Enabled otherwise, enable on interface
+ if (!PIM_IF_TEST_IGMP (pim_ifp->options))
+ {
+ PIM_IF_DO_IGMP(pim_ifp->options);
+ pim_if_addr_add_all(ifp);
+ pim_if_membership_refresh(ifp);
+ old_version = igmp_version; //avoid refreshing membership again.
+ }
+ /* Current and new version is different refresh existing
+ membership. Going from 3 -> 2 or 2 -> 3. */
+ if (old_version != igmp_version)
+ pim_if_membership_refresh(ifp);
+
return CMD_SUCCESS;
}
pim_ifp->pim_hello_period = strtol(argv[idx_time]->arg, NULL, 10);
- if (argc == idx_hold)
+ if (argc == idx_hold + 1)
pim_ifp->pim_default_holdtime = strtol(argv[idx_hold]->arg, NULL, 10);
return CMD_SUCCESS;
"mesh group source\n"
"mesh group local address\n")
{
- if (argc == 6)
+ if (argc == 7)
return ip_no_msdp_mesh_group_cmd_worker(vty, argv[6]->arg);
else
return ip_no_msdp_mesh_group_source_cmd_worker(vty, argv[4]->arg);
"JavaScript Object Notation\n")
{
u_char uj = use_json(argc, argv);
- if (uj)
- argc--;
- if (argc == 5)
- ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj);
- else if (argc == 4)
- ip_msdp_show_sa_addr(vty, argv[4]->arg, uj);
+ int idx = 0;
+ char *src_ip = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg : NULL;
+ char *grp_ip = idx < argc && argv_find (argv, argc, "A.B.C.D", &idx) ?
+ argv[idx]->arg : NULL;
+
+ if (src_ip && grp_ip)
+ ip_msdp_show_sa_sg(vty, src_ip, grp_ip, uj);
+ else if (src_ip)
+ ip_msdp_show_sa_addr(vty, src_ip, uj);
else
ip_msdp_show_sa(vty, uj);
install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd);
install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
+ install_element (CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd);
+ install_element (CONFIG_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd);
install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd);
install_element (CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
install_element (CONFIG_NODE, &ip_pim_keep_alive_cmd);
install_element (CONFIG_NODE, &no_ip_pim_keep_alive_cmd);
install_element (CONFIG_NODE, &ip_pim_packets_cmd);
install_element (CONFIG_NODE, &no_ip_pim_packets_cmd);
+ install_element (CONFIG_NODE, &ip_pim_v6_secondary_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_v6_secondary_cmd);
install_element (CONFIG_NODE, &ip_ssmpingd_cmd);
install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd);
install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd);
+ install_element (CONFIG_NODE, &ip_pim_ecmp_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ecmp_cmd);
+ install_element (CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
install_element (INTERFACE_NODE, &interface_ip_igmp_cmd);
install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd);
install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd);
install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd);
install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_interface_traffic_cmd);
install_element (VIEW_NODE, &show_ip_pim_interface_cmd);
install_element (VIEW_NODE, &show_ip_pim_join_cmd);
install_element (VIEW_NODE, &show_ip_pim_local_membership_cmd);
install_element (VIEW_NODE, &show_ip_rib_cmd);
install_element (VIEW_NODE, &show_ip_ssmpingd_cmd);
install_element (VIEW_NODE, &show_debugging_pim_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_nexthop_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
install_element (ENABLE_NODE, &clear_ip_interfaces_cmd);
install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
install_element (ENABLE_NODE, &clear_ip_mroute_cmd);
install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd);
+ install_element (ENABLE_NODE, &clear_ip_pim_interface_traffic_cmd);
install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd);
install_element (ENABLE_NODE, &debug_igmp_cmd);