]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_cmd.c
Merge remote-tracking branch 'origin/stable/3.0'
[mirror_frr.git] / pimd / pim_cmd.c
index 0478dc1b4815ef14f01b0e46e549519a75beb200..da07dcb4acbe769021e4045eceb8378ba00b21a6 100644 (file)
@@ -1,22 +1,21 @@
 /*
-  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>
 
@@ -26,6 +25,8 @@
 #include "prefix.h"
 #include "zclient.h"
 #include "plist.h"
+#include "hash.h"
+#include "nexthop.h"
 
 #include "pimd.h"
 #include "pim_mroute.h"
@@ -55,6 +56,7 @@
 #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,
@@ -1047,6 +1049,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
   struct pim_upstream *up;
   int fhr = 0;
   int pim_nbrs = 0;
+  int pim_ifchannels = 0;
   json_object *json = NULL;
   json_object *json_row = NULL;
   json_object *json_tmp;
@@ -1063,6 +1066,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
       continue;
 
     pim_nbrs = pim_ifp->pim_neighbor_list->count;
+    pim_ifchannels = pim_ifp->pim_ifchannel_list->count;
     fhr = 0;
 
     for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up))
@@ -1073,6 +1077,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
     json_row = json_object_new_object();
     json_object_pim_ifp_add(json_row, ifp);
     json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
+    json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
     json_object_int_add(json_row, "firstHopRouter", fhr);
     json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr));
 
@@ -1085,7 +1090,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
   if (uj) {
     vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
   } else {
-    vty_out(vty, "Interface  State          Address  PIM Nbrs           PIM DR  FHR%s", VTY_NEWLINE);
+    vty_out(vty, "Interface  State          Address  PIM Nbrs           PIM DR  FHR IfChannels%s", VTY_NEWLINE);
 
     json_object_object_foreach(json, key, val) {
       vty_out(vty, "%-9s  ", key);
@@ -1107,13 +1112,173 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
       }
 
       json_object_object_get_ex(val, "firstHopRouter", &json_tmp);
-      vty_out(vty, "%3d%s", json_object_get_int(json_tmp), VTY_NEWLINE);
+      vty_out(vty, "%3d  ", json_object_get_int(json_tmp));
+
+      json_object_object_get_ex(val, "pimIfChannels", &json_tmp);
+      vty_out(vty, "%9d%s", json_object_get_int(json_tmp), 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;
@@ -2062,6 +2227,50 @@ static void pim_show_rpf(struct vty *vty, u_char uj)
   }
 }
 
+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;
@@ -2444,6 +2653,45 @@ DEFUN (clear_ip_pim_interfaces,
   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",
@@ -2796,6 +3044,121 @@ DEFUN (show_ip_pim_rpf,
   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;
@@ -2874,15 +3237,17 @@ DEFUN (show_ip_multicast,
          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);
 
@@ -3129,7 +3494,7 @@ static void show_mroute(struct vty *vty, u_char uj)
         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);
@@ -3413,9 +3778,86 @@ pim_rp_cmd_worker (struct vty *vty, const char *rp, const char *group, const cha
   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"
@@ -3427,7 +3869,7 @@ DEFUN (ip_pim_joinprune_time,
 
 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"
@@ -3440,19 +3882,19 @@ DEFUN (no_ip_pim_joinprune_time,
 
 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"
@@ -3465,19 +3907,19 @@ DEFUN (no_ip_pim_register_suppress,
 
 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"
@@ -3490,7 +3932,7 @@ DEFUN (no_ip_pim_keep_alive,
 
 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"
@@ -3502,7 +3944,7 @@ DEFUN (ip_pim_packets,
 
 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"
@@ -3550,9 +3992,10 @@ DEFUN (ip_pim_rp,
   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,
@@ -3605,10 +4048,10 @@ DEFUN (no_ip_pim_rp,
        "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);
 }
@@ -3805,7 +4248,7 @@ DEFUN (ip_ssmpingd,
   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) {
@@ -3835,7 +4278,7 @@ DEFUN (no_ip_ssmpingd,
   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) {
@@ -3854,27 +4297,94 @@ DEFUN (no_ip_ssmpingd,
   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;
 }
@@ -4240,22 +4750,37 @@ DEFUN (interface_ip_igmp_version,
        "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;
 }
 
@@ -4802,7 +5327,7 @@ DEFUN (interface_ip_pim_hello,
 
   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;
@@ -5677,7 +6202,7 @@ DEFUN (no_ip_msdp_mesh_group_source,
        "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);
@@ -6177,13 +6702,16 @@ DEFUN (show_ip_msdp_sa_sg,
        "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);
 
@@ -6209,6 +6737,10 @@ void pim_cmd_init()
   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);
@@ -6221,6 +6753,10 @@ void pim_cmd_init()
   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); 
@@ -6259,6 +6795,7 @@ void pim_cmd_init()
   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);
@@ -6276,11 +6813,14 @@ void pim_cmd_init()
   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);