]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #4369 from patrasar/lmqc_lmqt
authorDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 31 May 2019 01:23:11 +0000 (21:23 -0400)
committerGitHub <noreply@github.com>
Fri, 31 May 2019 01:23:11 +0000 (21:23 -0400)
pimd: new cli to configure last-member-query-count & last-member-quer…

1  2 
doc/user/pim.rst
pimd/pim_cmd.c
pimd/pim_cmd.h
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_vty.c

diff --combined doc/user/pim.rst
index d05127059b4f4a8b319b1d4777451d05b55f9307,a89730f7ad60490619a00031cb6164fbf719fc59..8b0fba5f834e24a360c442a8494950fe48db4a1e
@@@ -166,20 -166,6 +166,20 @@@ is in a vrf, enter the interface comman
  
     Turns on BFD support for PIM for this interface.
  
 +.. index:: ip pim bsm
 +.. clicmd:: ip pim bsm
 +
 +   Tell pim that we would like to use this interface to process bootstrap
 +   messages. This is enabled by default. 'no' form of this command is used to
 +   restrict bsm messages on this interface.
 +
 +.. index:: ip pim unicast-bsm
 +.. clicmd:: ip pim unicast-bsm
 +
 +   Tell pim that we would like to allow interface to process unicast bootstrap
 +   messages. This is enabled by default. 'no' form of this command is used to
 +   restrict processing of unicast bsm messages on this interface.
 +
  .. index:: ip pim drpriority (1-4294967295)
  .. clicmd:: ip pim drpriority (1-4294967295)
  
     or IGMP report is received on this interface and the Group is denied by the
     prefix-list, PIM will ignore the join or report.
  
+ .. index:: ip igmp last-member-query-count (1-7)
+ .. clicmd:: ip igmp last-member-query-count (1-7)
+    Set the IGMP last member query count. The default value is 2. 'no' form of
+    this command is used to to configure back to the default value.
+ .. index:: ip igmp last-member-query-interval (1-255)
+ .. clicmd:: ip igmp last-member-query-interval (1-255)
+    Set the IGMP last member query interval in deciseconds. The default value is
+    10 deciseconds. 'no' form of this command is used to to configure back to the
+    default value.
  .. _pim-multicast-rib-insertion:
  
  PIM Multicast RIB insertion:
@@@ -322,12 -321,6 +335,12 @@@ cause great confusion
     Display information about installed into the kernel S,G mroutes and in
     addition display data about packet flow for the mroutes.
  
 +.. index:: show ip mroute summary
 +.. clicmd:: show ip mroute summary
 +
 +   Display total number of S,G mroutes and number of S,G mroutes installed
 +   into the kernel.
 +
  .. index:: show ip pim assert
  .. clicmd:: show ip pim assert
  
  
     Display upstream information for S,G's and the RPF data associated with them.
  
 +.. index:: show ip pim bsr
 +.. clicmd:: show ip pim bsr
 +
 +   Display current bsr, its uptime and last received bsm age.
 +
 +.. index:: show ip pim bsrp-info
 +.. clicmd:: show ip pim bsrp-info
 +
 +   Display group-to-rp mappings received from E-BSR.
 +
 +.. index:: show ip pim bsm-database
 +.. clicmd:: show ip pim bsm-database
 +
 +   Display all fragments ofstored bootstrap message in user readable format.
 +
  .. index:: show ip rpf
  .. clicmd:: show ip rpf
  
@@@ -505,11 -483,6 +518,11 @@@ the config was written out
  
     This traces pim code and how it is running.
  
 +.. index:: debug pim bsm
 +.. clicmd:: debug pim bsm
 +
 +   This turns on debugging for BSR message processing.
 +
  .. index:: debug pim zebra
  .. clicmd:: debug pim zebra
  
diff --combined pimd/pim_cmd.c
index e6e9c2d0c8c82d5b06ce372a36a6be40afb69900,cbbbe0234d2edd97809e62cd051da988b54d1b60..8cbacf53adf10b59082eca03057d724239465f65
@@@ -62,7 -62,6 +62,7 @@@
  #include "pim_bfd.h"
  #include "pim_vxlan.h"
  #include "bfd.h"
 +#include "pim_bsm.h"
  
  #ifndef VTYSH_EXTRACT_PL
  #include "pimd/pim_cmd_clippy.c"
@@@ -658,6 -657,7 +658,7 @@@ static void igmp_show_interfaces_single
        long oqpi_msec; /* Other Querier Present Interval */
        long qri_msec;
        time_t now;
+       int lmqc;
  
        json_object *json = NULL;
        json_object *json_row = NULL;
                                pim_ifp->igmp_query_max_response_time_dsec);
  
                        lmqt_msec = PIM_IGMP_LMQT_MSEC(
-                               pim_ifp->igmp_query_max_response_time_dsec,
-                               igmp->querier_robustness_variable);
+                               pim_ifp->igmp_specific_query_max_response_time_dsec,
+                               pim_ifp->igmp_last_member_query_count);
  
                        ohpi_msec =
                                PIM_IGMP_OHPI_DSEC(
                                        pim_ifp->pim_sock_fd);
                        else
                                mloop = 0;
+                       lmqc = pim_ifp->igmp_last_member_query_count;
  
                        if (uj) {
                                json_row = json_object_new_object();
                                        json_row,
                                        "timerGroupMembershipIntervalMsec",
                                        gmi_msec);
+                               json_object_int_add(json_row,
+                                                   "lastMemberQueryCount",
+                                                   lmqc);
                                json_object_int_add(json_row,
                                                    "timerLastMemberQueryMsec",
                                                    lmqt_msec);
                                vty_out(vty,
                                        "Group Membership Interval      : %lis\n",
                                        gmi_msec / 1000);
+                               vty_out(vty,
+                                       "Last Member Query Count        : %d\n",
+                                       lmqc);
                                vty_out(vty,
                                        "Last Member Query Time         : %lis\n",
                                        lmqt_msec / 1000);
@@@ -1478,14 -1485,13 +1486,14 @@@ static void pim_show_interface_traffic(
                json = json_object_new_object();
        else {
                vty_out(vty, "\n");
 -              vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n",
 +              vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
                        "Interface", "       HELLO", "       JOIN",
                        "      PRUNE", "   REGISTER", "REGISTER-STOP",
 -                      "  ASSERT");
 -              vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
 +                      "  ASSERT", "  BSM");
 +              vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
                        "       Rx/Tx", "       Rx/Tx", "      Rx/Tx",
 -                      "     Rx/Tx", "    Rx/Tx", "   Rx/Tx");
 +                      "      Rx/Tx", "     Rx/Tx", "    Rx/Tx",
 +                      "   Rx/Tx");
                vty_out(vty,
                        "---------------------------------------------------------------------------------------------------------------\n");
        }
                        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);
 -
 +                                      pim_ifp->pim_ifstat_assert_send);
 +                      json_object_int_add(json_row, "bsmRx",
 +                                      pim_ifp->pim_ifstat_bsm_rx);
 +                      json_object_int_add(json_row, "bsmTx",
 +                                      pim_ifp->pim_ifstat_bsm_tx);
                        json_object_object_add(json, ifp->name, json_row);
                } else {
                        vty_out(vty,
 -                              "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n",
 +                              "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7lu/%-7lu \n",
                                ifp->name, pim_ifp->pim_ifstat_hello_recv,
                                pim_ifp->pim_ifstat_hello_sent,
                                pim_ifp->pim_ifstat_join_recv,
                                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);
 +                              pim_ifp->pim_ifstat_assert_send,
 +                              pim_ifp->pim_ifstat_bsm_rx,
 +                              pim_ifp->pim_ifstat_bsm_tx);
                }
        }
        if (uj) {
@@@ -1566,15 -1567,14 +1574,15 @@@ static void pim_show_interface_traffic_
                json = json_object_new_object();
        else {
                vty_out(vty, "\n");
 -              vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n",
 +              vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
                        "Interface", "    HELLO", "    JOIN", "   PRUNE",
 -                      "   REGISTER", "  REGISTER-STOP", "  ASSERT");
 -              vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s\n", "",
 +                      "   REGISTER", "  REGISTER-STOP", "  ASSERT",
 +                      "    BSM");
 +              vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
                        "      Rx/Tx", "     Rx/Tx", "    Rx/Tx", "    Rx/Tx",
 -                      "     Rx/Tx", "    Rx/Tx");
 +                      "     Rx/Tx", "    Rx/Tx", "    Rx/Tx");
                vty_out(vty,
 -                      "---------------------------------------------------------------------------------------------------------------------\n");
 +                      "-------------------------------------------------------------------------------------------------------------------------------\n");
        }
  
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                                            pim_ifp->pim_ifstat_assert_recv);
                        json_object_int_add(json_row, "assertTx",
                                            pim_ifp->pim_ifstat_assert_send);
 +                      json_object_int_add(json_row, "bsmRx",
 +                                          pim_ifp->pim_ifstat_bsm_rx);
 +                      json_object_int_add(json_row, "bsmTx",
 +                                          pim_ifp->pim_ifstat_bsm_tx);
  
                        json_object_object_add(json, ifp->name, json_row);
                } else {
                        vty_out(vty,
 -                              "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n",
 +                              "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7lu/%-7lu \n",
                                ifp->name, pim_ifp->pim_ifstat_hello_recv,
                                pim_ifp->pim_ifstat_hello_sent,
                                pim_ifp->pim_ifstat_join_recv,
                                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);
 +                              pim_ifp->pim_ifstat_assert_send,
 +                              pim_ifp->pim_ifstat_bsm_rx,
 +                              pim_ifp->pim_ifstat_bsm_tx);
                }
        }
        if (uj) {
@@@ -2001,9 -1995,9 +2009,9 @@@ static void pim_show_state(struct pim_i
                ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
  
                if (ifp_in)
 -                      strcpy(in_ifname, ifp_in->name);
 +                      strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
                else
 -                      strcpy(in_ifname, "<iif?>");
 +                      strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
  
                if (src_or_group) {
                        if (strcmp(src_or_group, src_str)
                                now - c_oil->oif_creation[oif_vif_index]);
  
                        if (ifp_out)
 -                              strcpy(out_ifname, ifp_out->name);
 +                              strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
                        else
 -                              strcpy(out_ifname, "<oif?>");
 +                              strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
  
                        if (uj) {
                                json_ifp_out = json_object_new_object();
@@@ -2366,37 -2360,37 +2374,37 @@@ static void json_object_pim_upstream_ad
  
  static const char *
  pim_upstream_state2brief_str(enum pim_upstream_state join_state,
 -                           char *state_str)
 +                           char *state_str, size_t state_str_len)
  {
        switch (join_state) {
        case PIM_UPSTREAM_NOTJOINED:
 -              strcpy(state_str, "NotJ");
 +              strlcpy(state_str, "NotJ", state_str_len);
                break;
        case PIM_UPSTREAM_JOINED:
 -              strcpy(state_str, "J");
 +              strlcpy(state_str, "J", state_str_len);
                break;
        default:
 -              strcpy(state_str, "Unk");
 +              strlcpy(state_str, "Unk", state_str_len);
        }
        return state_str;
  }
  
  static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
 -                                         char *state_str)
 +                                         char *state_str, size_t state_str_len)
  {
        switch (reg_state) {
        case PIM_REG_NOINFO:
 -              strcpy(state_str, "RegNI");
 +              strlcpy(state_str, "RegNI", state_str_len);
                break;
        case PIM_REG_JOIN:
 -              strcpy(state_str, "RegJ");
 +              strlcpy(state_str, "RegJ", state_str_len);
                break;
        case PIM_REG_JOIN_PENDING:
        case PIM_REG_PRUNE:
 -              strcpy(state_str, "RegP");
 +              strlcpy(state_str, "RegP", state_str_len);
                break;
        default:
 -              strcpy(state_str, "Unk");
 +              strlcpy(state_str, "Unk", state_str_len);
        }
        return state_str;
  }
@@@ -2464,13 -2458,13 +2472,13 @@@ static void pim_show_upstream(struct pi
                pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
                                         up->t_msdp_reg_timer);
  
 -              pim_upstream_state2brief_str(up->join_state, state_str);
 +              pim_upstream_state2brief_str(up->join_state, state_str, sizeof(state_str));
                if (up->reg_state != PIM_REG_NOINFO) {
                        char tmp_str[PIM_REG_STATE_STR_LEN];
  
                        sprintf(state_str + strlen(state_str), ",%s",
 -                              pim_reg_state2brief_str(up->reg_state,
 -                                                      tmp_str));
 +                              pim_reg_state2brief_str(up->reg_state, tmp_str,
 +                                                      sizeof(tmp_str)));
                }
  
                if (uj) {
                                pim_upstream_state2str(up->join_state));
                        json_object_string_add(
                                json_row, "regState",
 -                              pim_reg_state2str(up->reg_state, state_str));
 +                              pim_reg_state2str(up->reg_state, state_str, sizeof(state_str)));
                        json_object_string_add(json_row, "upTime", uptime);
                        json_object_string_add(json_row, "joinTimer",
                                               join_timer);
@@@ -2902,413 -2896,6 +2910,413 @@@ static void pim_show_nexthop(struct pim
        hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd);
  }
  
 +/* Display the bsm database details */
 +static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
 +{
 +      struct listnode *bsmnode;
 +      int count = 0;
 +      int fragment = 1;
 +      struct bsm_info *bsm;
 +      json_object *json = NULL;
 +      json_object *json_group = NULL;
 +      json_object *json_row = NULL;
 +
 +      count = pim->global_scope.bsm_list->count;
 +
 +      if (uj) {
 +              json = json_object_new_object();
 +              json_object_int_add(json, "Number of the fragments", count);
 +      } else {
 +              vty_out(vty, "Scope Zone: Global\n");
 +              vty_out(vty, "Number of the fragments: %d\n", count);
 +              vty_out(vty, "\n");
 +      }
 +
 +      for (ALL_LIST_ELEMENTS_RO(pim->global_scope.bsm_list, bsmnode, bsm)) {
 +              char grp_str[INET_ADDRSTRLEN];
 +              char rp_str[INET_ADDRSTRLEN];
 +              char bsr_str[INET_ADDRSTRLEN];
 +              struct bsmmsg_grpinfo *group;
 +              struct bsmmsg_rpinfo *rpaddr;
 +              struct prefix grp;
 +              struct bsm_hdr *hdr;
 +              uint32_t offset = 0;
 +              uint8_t *buf;
 +              uint32_t len = 0;
 +              uint32_t frag_rp_cnt = 0;
 +
 +              buf = bsm->bsm;
 +              len = bsm->size;
 +
 +              /* skip pim header */
 +              buf += PIM_MSG_HEADER_LEN;
 +              len -= PIM_MSG_HEADER_LEN;
 +
 +              hdr = (struct bsm_hdr *)buf;
 +
 +              /* BSM starts with bsr header */
 +              buf += sizeof(struct bsm_hdr);
 +              len -= sizeof(struct bsm_hdr);
 +
 +              pim_inet4_dump("<BSR Address?>", hdr->bsr_addr.addr, bsr_str,
 +                             sizeof(bsr_str));
 +
 +
 +              if (uj) {
 +                      json_object_string_add(json, "BSR address", bsr_str);
 +                      json_object_int_add(json, "BSR priority",
 +                                          hdr->bsr_prio);
 +                      json_object_int_add(json, "Hashmask Length",
 +                                          hdr->hm_len);
 +                      json_object_int_add(json, "Fragment Tag",
 +                                          ntohs(hdr->frag_tag));
 +              } else {
 +                      vty_out(vty, "BSM Fragment : %d\n", fragment);
 +                      vty_out(vty, "------------------\n");
 +                      vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
 +                              "BSR-Priority", "Hashmask-len", "Fragment-Tag");
 +                      vty_out(vty, "%-15s %-15d %-15d %-15d\n", bsr_str,
 +                              hdr->bsr_prio, hdr->hm_len,
 +                              ntohs(hdr->frag_tag));
 +              }
 +
 +              vty_out(vty, "\n");
 +
 +              while (offset < len) {
 +                      group = (struct bsmmsg_grpinfo *)buf;
 +
 +                      if (group->group.family == PIM_MSG_ADDRESS_FAMILY_IPV4)
 +                              grp.family = AF_INET;
 +
 +                      grp.prefixlen = group->group.mask;
 +                      grp.u.prefix4.s_addr = group->group.addr.s_addr;
 +
 +                      prefix2str(&grp, grp_str, sizeof(grp_str));
 +
 +                      buf += sizeof(struct bsmmsg_grpinfo);
 +                      offset += sizeof(struct bsmmsg_grpinfo);
 +
 +                      if (uj) {
 +                              json_object_object_get_ex(json, grp_str,
 +                                                        &json_group);
 +                              if (!json_group) {
 +                                      json_group = json_object_new_object();
 +                                      json_object_int_add(json_group,
 +                                                          "Rp Count",
 +                                                          group->rp_count);
 +                                      json_object_int_add(
 +                                              json_group, "Fragment Rp count",
 +                                              group->frag_rp_count);
 +                                      json_object_object_add(json, grp_str,
 +                                                             json_group);
 +                              }
 +                      } else {
 +                              vty_out(vty, "Group : %s\n", grp_str);
 +                              vty_out(vty, "-------------------\n");
 +                              vty_out(vty, "Rp Count:%d\n", group->rp_count);
 +                              vty_out(vty, "Fragment Rp Count : %d\n",
 +                                      group->frag_rp_count);
 +                      }
 +
 +                      frag_rp_cnt = group->frag_rp_count;
 +
 +                      if (!frag_rp_cnt)
 +                              continue;
 +
 +                      if (!uj)
 +                              vty_out(vty,
 +                                      "RpAddress     HoldTime     Priority\n");
 +
 +                      while (frag_rp_cnt--) {
 +                              rpaddr = (struct bsmmsg_rpinfo *)buf;
 +
 +                              buf += sizeof(struct bsmmsg_rpinfo);
 +                              offset += sizeof(struct bsmmsg_rpinfo);
 +
 +                              pim_inet4_dump("<Rp addr?>",
 +                                             rpaddr->rpaddr.addr, rp_str,
 +                                             sizeof(rp_str));
 +
 +                              if (uj) {
 +                                      json_row = json_object_new_object();
 +                                      json_object_string_add(
 +                                              json_row, "Rp Address", rp_str);
 +                                      json_object_int_add(
 +                                              json_row, "Rp HoldTime",
 +                                              ntohs(rpaddr->rp_holdtime));
 +                                      json_object_int_add(json_row,
 +                                                          "Rp Priority",
 +                                                          rpaddr->rp_pri);
 +                                      json_object_object_add(
 +                                              json_group, rp_str, json_row);
 +                              } else {
 +                                      vty_out(vty, "%-15s %-12d %d\n", rp_str,
 +                                              ntohs(rpaddr->rp_holdtime),
 +                                              rpaddr->rp_pri);
 +                              }
 +                      }
 +                      vty_out(vty, "\n");
 +              }
 +
 +              fragment++;
 +      }
 +
 +      if (uj) {
 +              vty_out(vty, "%s\n", json_object_to_json_string_ext(
 +                                           json, JSON_C_TO_STRING_PRETTY));
 +              json_object_free(json);
 +      }
 +}
 +
 +/*Display the group-rp mappings */
 +static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
 +                                          struct vty *vty, bool uj)
 +{
 +      struct bsgrp_node *bsgrp;
 +      struct listnode *rpnode;
 +      struct bsm_rpinfo *bsm_rp;
 +      struct route_node *rn;
 +      char bsr_str[INET_ADDRSTRLEN];
 +      json_object *json = NULL;
 +      json_object *json_group = NULL;
 +      json_object *json_row = NULL;
 +
 +      if (pim->global_scope.current_bsr.s_addr == INADDR_ANY)
 +              strncpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
 +
 +      else
 +              pim_inet4_dump("<bsr?>", pim->global_scope.current_bsr, bsr_str,
 +                             sizeof(bsr_str));
 +
 +      if (uj) {
 +              json = json_object_new_object();
 +              json_object_string_add(json, "BSR Address", bsr_str);
 +      } else {
 +              vty_out(vty, "BSR Address  %s\n", bsr_str);
 +      }
 +
 +      for (rn = route_top(pim->global_scope.bsrp_table); rn;
 +           rn = route_next(rn)) {
 +              bsgrp = (struct bsgrp_node *)rn->info;
 +
 +              if (!bsgrp)
 +                      continue;
 +
 +              char grp_str[INET_ADDRSTRLEN];
 +
 +              prefix2str(&bsgrp->group, grp_str, sizeof(grp_str));
 +
 +              if (uj) {
 +                      json_object_object_get_ex(json, grp_str, &json_group);
 +                      if (!json_group) {
 +                              json_group = json_object_new_object();
 +                              json_object_object_add(json, grp_str,
 +                                                     json_group);
 +                      }
 +              } else {
 +                      vty_out(vty, "Group Address %s\n", grp_str);
 +                      vty_out(vty, "--------------------------\n");
 +                      vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
 +                              "priority", "Holdtime", "Hash");
 +
 +                      vty_out(vty, "(ACTIVE)\n");
 +              }
 +
 +              if (bsgrp->bsrp_list) {
 +                      for (ALL_LIST_ELEMENTS_RO(bsgrp->bsrp_list, rpnode,
 +                                                bsm_rp)) {
 +                              char rp_str[INET_ADDRSTRLEN];
 +
 +                              pim_inet4_dump("<Rp Address?>",
 +                                             bsm_rp->rp_address, rp_str,
 +                                             sizeof(rp_str));
 +
 +                              if (uj) {
 +                                      json_row = json_object_new_object();
 +                                      json_object_string_add(
 +                                              json_row, "Rp Address", rp_str);
 +                                      json_object_int_add(
 +                                              json_row, "Rp HoldTime",
 +                                              bsm_rp->rp_holdtime);
 +                                      json_object_int_add(json_row,
 +                                                          "Rp Priority",
 +                                                          bsm_rp->rp_prio);
 +                                      json_object_int_add(json_row,
 +                                                          "Hash Val",
 +                                                          bsm_rp->hash);
 +                                      json_object_object_add(
 +                                              json_group, rp_str, json_row);
 +
 +                              } else {
 +                                      vty_out(vty,
 +                                              "%-15s %-15u %-15u %-15u\n",
 +                                              rp_str, bsm_rp->rp_prio,
 +                                              bsm_rp->rp_holdtime,
 +                                              bsm_rp->hash);
 +                              }
 +                      }
 +                      if (!bsgrp->bsrp_list->count && !uj)
 +                              vty_out(vty, "Active List is empty.\n");
 +              }
 +
 +              if (uj) {
 +                      json_object_int_add(json_group, "Pending RP count",
 +                                          bsgrp->pend_rp_cnt);
 +              } else {
 +                      vty_out(vty, "(PENDING)\n");
 +                      vty_out(vty, "Pending RP count :%d\n",
 +                              bsgrp->pend_rp_cnt);
 +                      if (bsgrp->pend_rp_cnt)
 +                              vty_out(vty, "%-15s %-15s %-15s %-15s\n",
 +                                      "Rp Address", "priority", "Holdtime",
 +                                      "Hash");
 +              }
 +
 +              if (bsgrp->partial_bsrp_list) {
 +                      for (ALL_LIST_ELEMENTS_RO(bsgrp->partial_bsrp_list,
 +                                                rpnode, bsm_rp)) {
 +                              char rp_str[INET_ADDRSTRLEN];
 +
 +                              pim_inet4_dump("<Rp Addr?>", bsm_rp->rp_address,
 +                                             rp_str, sizeof(rp_str));
 +
 +                              if (uj) {
 +                                      json_row = json_object_new_object();
 +                                      json_object_string_add(
 +                                              json_row, "Rp Address", rp_str);
 +                                      json_object_int_add(
 +                                              json_row, "Rp HoldTime",
 +                                              bsm_rp->rp_holdtime);
 +                                      json_object_int_add(json_row,
 +                                                          "Rp Priority",
 +                                                          bsm_rp->rp_prio);
 +                                      json_object_int_add(json_row,
 +                                                          "Hash Val",
 +                                                          bsm_rp->hash);
 +                                      json_object_object_add(
 +                                              json_group, rp_str, json_row);
 +                              } else {
 +                                      vty_out(vty,
 +                                              "%-15s %-15u %-15u %-15u\n",
 +                                              rp_str, bsm_rp->rp_prio,
 +                                              bsm_rp->rp_holdtime,
 +                                              bsm_rp->hash);
 +                              }
 +                      }
 +                      if (!bsgrp->partial_bsrp_list->count && !uj)
 +                              vty_out(vty, "Partial List is empty\n");
 +              }
 +
 +              if (!uj)
 +                      vty_out(vty, "\n");
 +      }
 +
 +      if (uj) {
 +              vty_out(vty, "%s\n", json_object_to_json_string_ext(
 +                                           json, JSON_C_TO_STRING_PRETTY));
 +              json_object_free(json);
 +      }
 +}
 +
 +/* pim statistics - just adding only bsm related now.
 + * We can continue to add all pim related stats here.
 + */
 +static void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
 +                              const char *ifname, bool uj)
 +{
 +      json_object *json = NULL;
 +      struct interface *ifp;
 +
 +      if (uj) {
 +              json = json_object_new_object();
 +              json_object_int_add(json, "Number of Received BSMs",
 +                                  pim->bsm_rcvd);
 +              json_object_int_add(json, "Number of Forwared BSMs",
 +                                  pim->bsm_sent);
 +              json_object_int_add(json, "Number of Dropped BSMs",
 +                                  pim->bsm_dropped);
 +      } else {
 +              vty_out(vty, "BSM Statistics :\n");
 +              vty_out(vty, "----------------\n");
 +              vty_out(vty, "Number of Received BSMs : %ld\n", pim->bsm_rcvd);
 +              vty_out(vty, "Number of Forwared BSMs : %ld\n", pim->bsm_sent);
 +              vty_out(vty, "Number of Dropped BSMs  : %ld\n",
 +                      pim->bsm_dropped);
 +      }
 +
 +      vty_out(vty, "\n");
 +
 +      /* scan interfaces */
 +      FOR_ALL_INTERFACES (pim->vrf, ifp) {
 +              struct pim_interface *pim_ifp = ifp->info;
 +
 +              if (ifname && strcmp(ifname, ifp->name))
 +                      continue;
 +
 +              if (!pim_ifp)
 +                      continue;
 +
 +              if (!uj) {
 +                      vty_out(vty, "Interface : %s\n", ifp->name);
 +                      vty_out(vty, "-------------------\n");
 +                      vty_out(vty,
 +                              "Number of BSMs dropped due to config miss : %u\n",
 +                              pim_ifp->pim_ifstat_bsm_cfg_miss);
 +                      vty_out(vty, "Number of unicast BSMs dropped : %u\n",
 +                              pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
 +                      vty_out(vty,
 +                              "Number of BSMs dropped due to invalid scope zone : %u\n",
 +                              pim_ifp->pim_ifstat_bsm_invalid_sz);
 +              } else {
 +
 +                      json_object *json_row = NULL;
 +
 +                      json_row = json_object_new_object();
 +
 +                      json_object_string_add(json_row, "If Name", ifp->name);
 +                      json_object_int_add(
 +                              json_row,
 +                              "Number of BSMs dropped due to config miss",
 +                              pim_ifp->pim_ifstat_bsm_cfg_miss);
 +                      json_object_int_add(
 +                              json_row, "Number of unicast BSMs dropped",
 +                              pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
 +                      json_object_int_add(json_row,
 +                                          "Number of BSMs dropped due to invalid scope zone",
 +                                          pim_ifp->pim_ifstat_bsm_invalid_sz);
 +                      json_object_object_add(json, ifp->name, json_row);
 +              }
 +              vty_out(vty, "\n");
 +      }
 +
 +      if (uj) {
 +              vty_out(vty, "%s\n", json_object_to_json_string_ext(
 +                                           json, JSON_C_TO_STRING_PRETTY));
 +              json_object_free(json);
 +      }
 +}
 +
 +static void clear_pim_statistics(struct pim_instance *pim)
 +{
 +      struct interface *ifp;
 +
 +      pim->bsm_rcvd = 0;
 +      pim->bsm_sent = 0;
 +      pim->bsm_dropped = 0;
 +
 +      /* scan interfaces */
 +      FOR_ALL_INTERFACES (pim->vrf, ifp) {
 +              struct pim_interface *pim_ifp = ifp->info;
 +
 +              if (!pim_ifp)
 +                      continue;
 +
 +              pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
 +              pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
 +              pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
 +      }
 +}
 +
  static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
  {
        struct interface *ifp;
@@@ -3628,82 -3215,6 +3636,82 @@@ static void igmp_show_source_retransmis
        }                         /* scan interfaces */
  }
  
 +static void pim_show_bsr(struct pim_instance *pim,
 +                       struct vty *vty,
 +                       bool uj)
 +{
 +      char uptime[10];
 +      char last_bsm_seen[10];
 +      time_t now;
 +      char bsr_state[20];
 +      char bsr_str[PREFIX_STRLEN];
 +      json_object *json = NULL;
 +
 +      vty_out(vty, "PIMv2 Bootstrap information\n");
 +
 +      if (pim->global_scope.current_bsr.s_addr == INADDR_ANY) {
 +              strncpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
 +              pim_time_uptime(uptime, sizeof(uptime),
 +                              pim->global_scope.current_bsr_first_ts);
 +              pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
 +                              pim->global_scope.current_bsr_last_ts);
 +      }
 +
 +      else {
 +              pim_inet4_dump("<bsr?>", pim->global_scope.current_bsr,
 +                             bsr_str, sizeof(bsr_str));
 +              now = pim_time_monotonic_sec();
 +              pim_time_uptime(uptime, sizeof(uptime),
 +                              (now - pim->global_scope.current_bsr_first_ts));
 +              pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
 +                              now - pim->global_scope.current_bsr_last_ts);
 +      }
 +
 +      switch (pim->global_scope.state) {
 +      case NO_INFO:
 +              strncpy(bsr_state, "NO_INFO", sizeof(bsr_state));
 +              break;
 +      case ACCEPT_ANY:
 +              strncpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
 +              break;
 +      case ACCEPT_PREFERRED:
 +              strncpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
 +              break;
 +      default:
 +              strncpy(bsr_state, "", sizeof(bsr_state));
 +      }
 +
 +      if (uj) {
 +              json = json_object_new_object();
 +              json_object_string_add(json, "bsr", bsr_str);
 +              json_object_int_add(json, "priority",
 +                                  pim->global_scope.current_bsr_prio);
 +              json_object_int_add(json, "fragment_tag",
 +                                  pim->global_scope.bsm_frag_tag);
 +              json_object_string_add(json, "state", bsr_state);
 +              json_object_string_add(json, "upTime", uptime);
 +              json_object_string_add(json, "last_bsm_seen", last_bsm_seen);
 +      }
 +
 +      else {
 +              vty_out(vty, "Current preferred BSR address: %s\n", bsr_str);
 +              vty_out(vty,
 +                      "Priority        Fragment-Tag       State           UpTime\n");
 +              vty_out(vty, "  %-12d    %-12d    %-13s    %7s\n",
 +                      pim->global_scope.current_bsr_prio,
 +                      pim->global_scope.bsm_frag_tag,
 +                      bsr_state,
 +                      uptime);
 +              vty_out(vty, "Last BSM seen: %s\n", last_bsm_seen);
 +      }
 +
 +      if (uj) {
 +              vty_out(vty, "%s\n", json_object_to_json_string_ext(
 +                                           json, JSON_C_TO_STRING_PRETTY));
 +              json_object_free(json);
 +      }
 +}
 +
  static void clear_igmp_interfaces(struct pim_instance *pim)
  {
        struct interface *ifp;
@@@ -3779,25 -3290,6 +3787,25 @@@ DEFUN (clear_ip_igmp_interfaces
        return CMD_SUCCESS;
  }
  
 +DEFUN (clear_ip_pim_statistics,
 +       clear_ip_pim_statistics_cmd,
 +       "clear ip pim statistics [vrf NAME]",
 +       CLEAR_STR
 +       IP_STR
 +       CLEAR_IP_PIM_STR
 +       VRF_CMD_HELP_STR
 +       "Reset PIM statistics\n")
 +{
 +      int idx = 2;
 +      struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
 +
 +      if (!vrf)
 +              return CMD_WARNING;
 +
 +      clear_pim_statistics(vrf->info);
 +      return CMD_SUCCESS;
 +}
 +
  static void mroute_add_all(struct pim_instance *pim)
  {
        struct listnode *node;
@@@ -3916,8 -3408,6 +3924,8 @@@ DEFUN (clear_ip_pim_interface_traffic
                pim_ifp->pim_ifstat_reg_stop_send = 0;
                pim_ifp->pim_ifstat_assert_recv = 0;
                pim_ifp->pim_ifstat_assert_send = 0;
 +              pim_ifp->pim_ifstat_bsm_rx = 0;
 +              pim_ifp->pim_ifstat_bsm_tx = 0;
        }
  
        return CMD_SUCCESS;
@@@ -4977,76 -4467,6 +4985,76 @@@ DEFUN (show_ip_pim_interface_traffic
        return CMD_SUCCESS;
  }
  
 +DEFUN (show_ip_pim_bsm_db,
 +       show_ip_pim_bsm_db_cmd,
 +       "show ip pim bsm-database [vrf NAME] [json]",
 +       SHOW_STR
 +       IP_STR
 +       PIM_STR
 +       VRF_CMD_HELP_STR
 +       "PIM cached bsm packets information\n"
 +       JSON_STR)
 +{
 +      int idx = 2;
 +      struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
 +      bool uj = use_json(argc, argv);
 +
 +      if (!vrf)
 +              return CMD_WARNING;
 +
 +      pim_show_bsm_db(vrf->info, vty, uj);
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (show_ip_pim_bsrp,
 +       show_ip_pim_bsrp_cmd,
 +       "show ip pim bsrp-info [vrf NAME] [json]",
 +       SHOW_STR
 +       IP_STR
 +       PIM_STR
 +       VRF_CMD_HELP_STR
 +       "PIM cached group-rp mappings information\n"
 +       JSON_STR)
 +{
 +      int idx = 2;
 +      struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
 +      bool uj = use_json(argc, argv);
 +
 +      if (!vrf)
 +              return CMD_WARNING;
 +
 +      pim_show_group_rp_mappings_info(vrf->info, vty, uj);
 +
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (show_ip_pim_statistics,
 +       show_ip_pim_statistics_cmd,
 +       "show ip pim [vrf NAME] statistics  [interface WORD] [json]",
 +       SHOW_STR
 +       IP_STR
 +       PIM_STR
 +       VRF_CMD_HELP_STR
 +       "PIM statistics\n"
 +       "interface\n"
 +       "PIM interface\n"
 +       JSON_STR)
 +{
 +      int idx = 2;
 +      struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
 +      bool uj = use_json(argc, argv);
 +
 +      if (!vrf)
 +              return CMD_WARNING;
 +
 +      if (argv_find(argv, argc, "WORD", &idx))
 +              pim_show_statistics(vrf->info, vty, argv[idx]->arg, uj);
 +      else
 +              pim_show_statistics(vrf->info, vty, NULL, uj);
 +
 +      return CMD_SUCCESS;
 +}
 +
  static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty)
  {
        struct interface *ifp;
@@@ -5234,9 -4654,9 +5242,9 @@@ static void show_mroute(struct pim_inst
                ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
  
                if (ifp_in)
 -                      strcpy(in_ifname, ifp_in->name);
 +                      strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
                else
 -                      strcpy(in_ifname, "<iif?>");
 +                      strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
  
                if (uj) {
  
                        found_oif = 1;
  
                        if (ifp_out)
 -                              strcpy(out_ifname, ifp_out->name);
 +                              strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
                        else
 -                              strcpy(out_ifname, "<oif?>");
 +                              strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
  
                        if (uj) {
                                json_ifp_out = json_object_new_object();
                        } else {
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_PIM) {
 -                                      strcpy(proto, "PIM");
 +                                      strlcpy(proto, "PIM", sizeof(proto));
                                }
  
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_IGMP) {
 -                                      strcpy(proto, "IGMP");
 +                                      strlcpy(proto, "IGMP", sizeof(proto));
                                }
  
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_VXLAN) {
 -                                      strcpy(proto, "VxLAN");
 +                                      strlcpy(proto, "VxLAN", sizeof(proto));
                                }
  
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_SOURCE) {
 -                                      strcpy(proto, "SRC");
 +                                      strlcpy(proto, "SRC", sizeof(proto));
                                }
  
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_STAR) {
 -                                      strcpy(proto, "STAR");
 +                                      strlcpy(proto, "STAR", sizeof(proto));
                                }
  
                                vty_out(vty,
                found_oif = 0;
  
                if (ifp_in)
 -                      strcpy(in_ifname, ifp_in->name);
 +                      strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
                else
 -                      strcpy(in_ifname, "<iif?>");
 +                      strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
  
                if (uj) {
  
                        json_object_string_add(json_source, "iif", in_ifname);
                        json_oil = NULL;
                } else {
 -                      strcpy(proto, "STATIC");
 +                      strlcpy(proto, "STATIC", sizeof(proto));
                }
  
                for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
                        found_oif = 1;
  
                        if (ifp_out)
 -                              strcpy(out_ifname, ifp_out->name);
 +                              strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
                        else
 -                              strcpy(out_ifname, "<oif?>");
 +                              strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
  
                        if (uj) {
                                json_ifp_out = json_object_new_object();
@@@ -5705,97 -5125,6 +5713,97 @@@ DEFUN (show_ip_mroute_count_vrf_all
        return CMD_SUCCESS;
  }
  
 +static void show_mroute_summary(struct pim_instance *pim, struct vty *vty)
 +{
 +      struct listnode *node;
 +      struct channel_oil *c_oil;
 +      struct static_route *s_route;
 +      uint32_t starg_sw_mroute_cnt = 0;
 +      uint32_t sg_sw_mroute_cnt = 0;
 +      uint32_t starg_hw_mroute_cnt = 0;
 +      uint32_t sg_hw_mroute_cnt = 0;
 +
 +      vty_out(vty, "Mroute Type    Installed/Total\n");
 +
 +      for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
 +              if (!c_oil->installed) {
 +                      if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
 +                              starg_sw_mroute_cnt++;
 +                      else
 +                              sg_sw_mroute_cnt++;
 +              } else {
 +                      if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
 +                              starg_hw_mroute_cnt++;
 +                      else
 +                              sg_hw_mroute_cnt++;
 +              }
 +      }
 +
 +      for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
 +              if (!s_route->c_oil.installed) {
 +                      if (s_route->c_oil.oil.mfcc_origin.s_addr == INADDR_ANY)
 +                              starg_sw_mroute_cnt++;
 +                      else
 +                              sg_sw_mroute_cnt++;
 +              } else {
 +                      if (s_route->c_oil.oil.mfcc_origin.s_addr == INADDR_ANY)
 +                              starg_hw_mroute_cnt++;
 +                      else
 +                              sg_hw_mroute_cnt++;
 +              }
 +      }
 +
 +      vty_out(vty, "%-20s %d/%d\n", "(*, G)", starg_hw_mroute_cnt,
 +              starg_sw_mroute_cnt + starg_hw_mroute_cnt);
 +      vty_out(vty, "%-20s %d/%d\n", "(S, G)", sg_hw_mroute_cnt,
 +              sg_sw_mroute_cnt + sg_hw_mroute_cnt);
 +      vty_out(vty, "------\n");
 +      vty_out(vty, "%-20s %d/%d\n", "Total",
 +              (starg_hw_mroute_cnt + sg_hw_mroute_cnt),
 +              (starg_sw_mroute_cnt +
 +               starg_hw_mroute_cnt +
 +               sg_sw_mroute_cnt +
 +               sg_hw_mroute_cnt));
 +}
 +
 +DEFUN (show_ip_mroute_summary,
 +       show_ip_mroute_summary_cmd,
 +       "show ip mroute [vrf NAME] summary",
 +       SHOW_STR
 +       IP_STR
 +       MROUTE_STR
 +       VRF_CMD_HELP_STR
 +       "Summary of all mroutes\n")
 +{
 +      int idx = 2;
 +      struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
 +
 +      if (!vrf)
 +              return CMD_WARNING;
 +
 +      show_mroute_summary(vrf->info, vty);
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (show_ip_mroute_summary_vrf_all,
 +       show_ip_mroute_summary_vrf_all_cmd,
 +       "show ip mroute vrf all summary",
 +       SHOW_STR
 +       IP_STR
 +       MROUTE_STR
 +       VRF_CMD_HELP_STR
 +       "Summary of all mroutes\n")
 +{
 +      struct vrf *vrf;
 +
 +      RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 +              vty_out(vty, "VRF: %s\n", vrf->name);
 +              show_mroute_summary(vrf->info, vty);
 +      }
 +
 +      return CMD_SUCCESS;
 +}
 +
  DEFUN (show_ip_rib,
         show_ip_rib_cmd,
         "show ip rib [vrf NAME] A.B.C.D",
@@@ -5912,13 -5241,7 +5920,13 @@@ static int pim_rp_cmd_worker(struct pim
  {
        int result;
  
 -      result = pim_rp_new(pim, rp, group, plist);
 +      result = pim_rp_new_config(pim, rp, group, plist);
 +
 +      if (result == PIM_GROUP_BAD_ADDR_MASK_COMBO) {
 +              vty_out(vty, "%% Inconsistent address and mask: %s\n",
 +                      group);
 +              return CMD_WARNING_CONFIG_FAILED;
 +      }
  
        if (result == PIM_GROUP_BAD_ADDRESS) {
                vty_out(vty, "%% Bad group address specified: %s\n", group);
@@@ -6244,7 -5567,7 +6252,7 @@@ static int pim_no_rp_cmd_worker(struct 
                                const char *rp, const char *group,
                                const char *plist)
  {
 -      int result = pim_rp_del(pim, rp, group, plist);
 +      int result = pim_rp_del_config(pim, rp, group, plist);
  
        if (result == PIM_GROUP_BAD_ADDRESS) {
                vty_out(vty, "%% Bad group address specified: %s\n", group);
@@@ -6463,27 -5786,6 +6471,27 @@@ DEFUN (show_ip_pim_group_type
        return CMD_SUCCESS;
  }
  
 +DEFUN (show_ip_pim_bsr,
 +       show_ip_pim_bsr_cmd,
 +       "show ip pim bsr [json]",
 +       SHOW_STR
 +       IP_STR
 +       PIM_STR
 +       "boot-strap router information\n"
 +       JSON_STR)
 +{
 +      int idx = 2;
 +      struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
 +      bool uj = use_json(argc, argv);
 +
 +      if (!vrf)
 +              return CMD_WARNING;
 +
 +      pim_show_bsr(vrf->info, vty, uj);
 +
 +      return CMD_SUCCESS;
 +}
 +
  DEFUN (ip_ssmpingd,
         ip_ssmpingd_cmd,
         "ip ssmpingd [A.B.C.D]",
@@@ -7161,6 -6463,106 +7169,106 @@@ DEFUN_HIDDEN (interface_no_ip_igmp_quer
        return CMD_SUCCESS;
  }
  
+ #define IGMP_LAST_MEMBER_QUERY_COUNT_MIN (1)
+ #define IGMP_LAST_MEMBER_QUERY_COUNT_MAX (7)
+ DEFUN (interface_ip_igmp_last_member_query_count,
+        interface_ip_igmp_last_member_query_count_cmd,
+        "ip igmp last-member-query-count (1-7)",
+        IP_STR
+        IFACE_IGMP_STR
+        IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR
+        "Last member query count\n")
+ {
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+       int last_member_query_count;
+       int ret;
+       if (!pim_ifp) {
+               ret = pim_cmd_igmp_start(vty, ifp);
+               if (ret != CMD_SUCCESS)
+                       return ret;
+               pim_ifp = ifp->info;
+       }
+       last_member_query_count = atoi(argv[3]->arg);
+       pim_ifp->igmp_last_member_query_count = last_member_query_count;
+       return CMD_SUCCESS;
+ }
+ DEFUN (interface_no_ip_igmp_last_member_query_count,
+        interface_no_ip_igmp_last_member_query_count_cmd,
+        "no ip igmp last-member-query-count",
+        NO_STR
+        IP_STR
+        IFACE_IGMP_STR
+        IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR)
+ {
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+       if (!pim_ifp)
+               return CMD_SUCCESS;
+       pim_ifp->igmp_last_member_query_count =
+               IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
+       return CMD_SUCCESS;
+ }
+ #define IGMP_LAST_MEMBER_QUERY_INTERVAL_MIN (1)
+ #define IGMP_LAST_MEMBER_QUERY_INTERVAL_MAX (255)
+ DEFUN (interface_ip_igmp_last_member_query_interval,
+        interface_ip_igmp_last_member_query_interval_cmd,
+        "ip igmp last-member-query-interval (1-255)",
+        IP_STR
+        IFACE_IGMP_STR
+        IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR
+        "Last member query interval in deciseconds\n")
+ {
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+       int last_member_query_interval;
+       int ret;
+       if (!pim_ifp) {
+               ret = pim_cmd_igmp_start(vty, ifp);
+               if (ret != CMD_SUCCESS)
+                       return ret;
+               pim_ifp = ifp->info;
+       }
+       last_member_query_interval = atoi(argv[3]->arg);
+       pim_ifp->igmp_specific_query_max_response_time_dsec
+               = last_member_query_interval;
+       return CMD_SUCCESS;
+ }
+ DEFUN (interface_no_ip_igmp_last_member_query_interval,
+        interface_no_ip_igmp_last_member_query_interval_cmd,
+        "no ip igmp last-member-query-interval",
+        NO_STR
+        IP_STR
+        IFACE_IGMP_STR
+        IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR)
+ {
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+       if (!pim_ifp)
+               return CMD_SUCCESS;
+       pim_ifp->igmp_specific_query_max_response_time_dsec =
+               IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
+       return CMD_SUCCESS;
+ }
  DEFUN (interface_ip_pim_drprio,
         interface_ip_pim_drprio_cmd,
         "ip pim drpriority (1-4294967295)",
@@@ -7932,7 -7334,6 +8040,7 @@@ DEFUN (debug_pim
        PIM_DO_DEBUG_PIM_TRACE;
        PIM_DO_DEBUG_MSDP_EVENTS;
        PIM_DO_DEBUG_MSDP_PACKETS;
 +      PIM_DO_DEBUG_BSM;
        return CMD_SUCCESS;
  }
  
@@@ -7951,7 -7352,6 +8059,7 @@@ DEFUN (no_debug_pim
  
        PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
        PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
 +      PIM_DONT_DEBUG_BSM;
  
        return CMD_SUCCESS;
  }
@@@ -8337,30 -7737,6 +8445,30 @@@ DEFUN (no_debug_mtrace
        return CMD_SUCCESS;
  }
  
 +DEFUN (debug_bsm,
 +       debug_bsm_cmd,
 +       "debug pim bsm",
 +       DEBUG_STR
 +       DEBUG_PIM_STR
 +       DEBUG_PIM_BSM_STR)
 +{
 +      PIM_DO_DEBUG_BSM;
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (no_debug_bsm,
 +       no_debug_bsm_cmd,
 +       "no debug pim bsm",
 +       NO_STR
 +       DEBUG_STR
 +       DEBUG_PIM_STR
 +       DEBUG_PIM_BSM_STR)
 +{
 +      PIM_DONT_DEBUG_BSM;
 +      return CMD_SUCCESS;
 +}
 +
 +
  DEFUN_NOSH (show_debugging_pim,
            show_debugging_pim_cmd,
            "show debugging [pim]",
@@@ -8484,94 -7860,6 +8592,94 @@@ DEFUN (no_ip_pim_bfd
        return CMD_SUCCESS;
  }
  
 +DEFUN (ip_pim_bsm,
 +       ip_pim_bsm_cmd,
 +       "ip pim bsm",
 +       IP_STR
 +       PIM_STR
 +       "Enables BSM support on the interface\n")
 +{
 +      VTY_DECLVAR_CONTEXT(interface, ifp);
 +      struct pim_interface *pim_ifp = ifp->info;
 +
 +      if (!pim_ifp) {
 +              if (!pim_cmd_interface_add(ifp)) {
 +                      vty_out(vty, "Could not enable PIM SM on interface\n");
 +                      return CMD_WARNING;
 +              }
 +      }
 +
 +      pim_ifp = ifp->info;
 +      pim_ifp->bsm_enable = true;
 +
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (no_ip_pim_bsm,
 +       no_ip_pim_bsm_cmd,
 +       "no ip pim bsm",
 +       NO_STR
 +       IP_STR
 +       PIM_STR
 +       "Disables BSM support\n")
 +{
 +      VTY_DECLVAR_CONTEXT(interface, ifp);
 +      struct pim_interface *pim_ifp = ifp->info;
 +
 +      if (!pim_ifp) {
 +              vty_out(vty, "Pim not enabled on this interface\n");
 +              return CMD_WARNING;
 +      }
 +
 +      pim_ifp->bsm_enable = false;
 +
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (ip_pim_ucast_bsm,
 +       ip_pim_ucast_bsm_cmd,
 +       "ip pim unicast-bsm",
 +       IP_STR
 +       PIM_STR
 +       "Accept/Send unicast BSM on the interface\n")
 +{
 +      VTY_DECLVAR_CONTEXT(interface, ifp);
 +      struct pim_interface *pim_ifp = ifp->info;
 +
 +      if (!pim_ifp) {
 +              if (!pim_cmd_interface_add(ifp)) {
 +                      vty_out(vty, "Could not enable PIM SM on interface\n");
 +                      return CMD_WARNING;
 +              }
 +      }
 +
 +      pim_ifp = ifp->info;
 +      pim_ifp->ucast_bsm_accept = true;
 +
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (no_ip_pim_ucast_bsm,
 +       no_ip_pim_ucast_bsm_cmd,
 +       "no ip pim unicast-bsm",
 +       NO_STR
 +       IP_STR
 +       PIM_STR
 +       "Block send/receive unicast BSM on this interface\n")
 +{
 +      VTY_DECLVAR_CONTEXT(interface, ifp);
 +      struct pim_interface *pim_ifp = ifp->info;
 +
 +      if (!pim_ifp) {
 +              vty_out(vty, "Pim not enabled on this interface\n");
 +              return CMD_WARNING;
 +      }
 +
 +      pim_ifp->ucast_bsm_accept = false;
 +
 +      return CMD_SUCCESS;
 +}
 +
  #if HAVE_BFDD > 0
  DEFUN_HIDDEN(
  #else
@@@ -9089,7 -8377,7 +9197,7 @@@ static void ip_msdp_show_peers(struct p
                        pim_time_uptime(timebuf, sizeof(timebuf),
                                        now - mp->uptime);
                } else {
 -                      strcpy(timebuf, "-");
 +                      strlcpy(timebuf, "-", sizeof(timebuf));
                }
                pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
                pim_inet4_dump("<local?>", mp->local, local_str,
@@@ -9146,7 -8434,7 +9254,7 @@@ static void ip_msdp_show_peers_detail(s
                        pim_time_uptime(timebuf, sizeof(timebuf),
                                        now - mp->uptime);
                } else {
 -                      strcpy(timebuf, "-");
 +                      strlcpy(timebuf, "-", sizeof(timebuf));
                }
                pim_inet4_dump("<local?>", mp->local, local_str,
                               sizeof(local_str));
@@@ -9325,18 -8613,18 +9433,18 @@@ static void ip_msdp_show_sa(struct pim_
                if (sa->flags & PIM_MSDP_SAF_PEER) {
                        pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
                        if (sa->up) {
 -                              strcpy(spt_str, "yes");
 +                              strlcpy(spt_str, "yes", sizeof(spt_str));
                        } else {
 -                              strcpy(spt_str, "no");
 +                              strlcpy(spt_str, "no", sizeof(spt_str));
                        }
                } else {
 -                      strcpy(rp_str, "-");
 -                      strcpy(spt_str, "-");
 +                      strlcpy(rp_str, "-", sizeof(rp_str));
 +                      strlcpy(spt_str, "-", sizeof(spt_str));
                }
                if (sa->flags & PIM_MSDP_SAF_LOCAL) {
 -                      strcpy(local_str, "yes");
 +                      strlcpy(local_str, "yes", sizeof(local_str));
                } else {
 -                      strcpy(local_str, "no");
 +                      strlcpy(local_str, "no", sizeof(local_str));
                }
                if (uj) {
                        json_object_object_get_ex(json, grp_str, &json_group);
@@@ -9390,19 -8678,19 +9498,19 @@@ static void ip_msdp_show_sa_entry_detai
                pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
                pim_inet4_dump("<peer?>", sa->peer, peer_str, sizeof(peer_str));
                if (sa->up) {
 -                      strcpy(spt_str, "yes");
 +                      strlcpy(spt_str, "yes", sizeof(spt_str));
                } else {
 -                      strcpy(spt_str, "no");
 +                      strlcpy(spt_str, "no", sizeof(spt_str));
                }
        } else {
 -              strcpy(rp_str, "-");
 -              strcpy(peer_str, "-");
 -              strcpy(spt_str, "-");
 +              strlcpy(rp_str, "-", sizeof(rp_str));
 +              strlcpy(peer_str, "-", sizeof(peer_str));
 +              strlcpy(spt_str, "-", sizeof(spt_str));
        }
        if (sa->flags & PIM_MSDP_SAF_LOCAL) {
 -              strcpy(local_str, "yes");
 +              strlcpy(local_str, "yes", sizeof(local_str));
        } else {
 -              strcpy(local_str, "no");
 +              strlcpy(local_str, "no", sizeof(local_str));
        }
        pim_time_timer_to_hhmmss(statetimer, sizeof(statetimer),
                                 sa->sa_state_timer);
@@@ -10116,6 -9404,14 +10224,14 @@@ void pim_cmd_init(void
                        &interface_ip_igmp_query_max_response_time_dsec_cmd);
        install_element(INTERFACE_NODE,
                        &interface_no_ip_igmp_query_max_response_time_dsec_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_ip_igmp_last_member_query_count_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_no_ip_igmp_last_member_query_count_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_ip_igmp_last_member_query_interval_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_no_ip_igmp_last_member_query_interval_cmd);
        install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
        install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
        install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd);
        install_element(VIEW_NODE, &show_ip_pim_rp_cmd);
        install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd);
 +      install_element(VIEW_NODE, &show_ip_pim_bsr_cmd);
        install_element(VIEW_NODE, &show_ip_multicast_cmd);
        install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_count_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_count_vrf_all_cmd);
 +      install_element(VIEW_NODE, &show_ip_mroute_summary_cmd);
 +      install_element(VIEW_NODE, &show_ip_mroute_summary_vrf_all_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(VIEW_NODE, &show_ip_pim_bsrp_cmd);
 +      install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd);
 +      install_element(VIEW_NODE, &show_ip_pim_statistics_cmd);
  
        install_element(ENABLE_NODE, &clear_ip_interfaces_cmd);
        install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_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, &clear_ip_pim_statistics_cmd);
  
        install_element(ENABLE_NODE, &debug_igmp_cmd);
        install_element(ENABLE_NODE, &no_debug_igmp_cmd);
        install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd);
        install_element(ENABLE_NODE, &debug_mtrace_cmd);
        install_element(ENABLE_NODE, &no_debug_mtrace_cmd);
 +      install_element(ENABLE_NODE, &debug_bsm_cmd);
 +      install_element(ENABLE_NODE, &no_debug_bsm_cmd);
  
        install_element(CONFIG_NODE, &debug_igmp_cmd);
        install_element(CONFIG_NODE, &no_debug_igmp_cmd);
        install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd);
        install_element(CONFIG_NODE, &debug_mtrace_cmd);
        install_element(CONFIG_NODE, &no_debug_mtrace_cmd);
 +      install_element(CONFIG_NODE, &debug_bsm_cmd);
 +      install_element(CONFIG_NODE, &no_debug_bsm_cmd);
  
        install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd);
        install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd);
        install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd);
        install_element(INTERFACE_NODE, &interface_pim_use_source_cmd);
        install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd);
 +      /* Install BSM command */
 +      install_element(INTERFACE_NODE, &ip_pim_bsm_cmd);
 +      install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd);
 +      install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd);
 +      install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd);
        /* Install BFD command */
        install_element(INTERFACE_NODE, &ip_pim_bfd_cmd);
        install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd);
diff --combined pimd/pim_cmd.h
index 558f28231ba2278a2ddf9162259f9c1363ead4e4,0bbd003f95337f3903e4b619c55fb4b17b61298f..f5bb316a7ae3b3648d6b7641db30566a700b3187
@@@ -35,6 -35,8 +35,8 @@@
  #define IFACE_IGMP_QUERY_INTERVAL_STR          "IGMP host query interval\n"
  #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR      "IGMP max query response value (seconds)\n"
  #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "IGMP max query response value (deciseconds)\n"
+ #define IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR   "IGMP last member query interval\n"
+ #define IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR      "IGMP last member query count\n"
  #define DEBUG_IGMP_STR                              "IGMP protocol activity\n"
  #define DEBUG_IGMP_EVENTS_STR                       "IGMP protocol events\n"
  #define DEBUG_IGMP_PACKETS_STR                      "IGMP protocol packets\n"
@@@ -65,8 -67,6 +67,8 @@@
  #define DEBUG_MSDP_INTERNAL_STR                     "MSDP protocol internal\n"
  #define DEBUG_MSDP_PACKETS_STR                      "MSDP protocol packets\n"
  #define DEBUG_MTRACE_STR                            "Mtrace protocol activity\n"
 +#define DEBUG_PIM_BSM_STR                           "BSR message processing activity\n"
 +
  
  void pim_cmd_init(void);
  
diff --combined pimd/pim_iface.c
index 08be38c138abe570908e2949650f3152652b172b,74fb6424bc6da46b54c9cf11da1367ae64efd061..7b8f045697884cd7de1a85f7e8c7e841a77b883a
@@@ -131,11 -131,9 +131,13 @@@ struct pim_interface *pim_if_new(struc
                IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
        pim_ifp->igmp_specific_query_max_response_time_dsec =
                IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
+       pim_ifp->igmp_last_member_query_count =
+               IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
  
 +      /* BSM config on interface: TRUE by default */
 +      pim_ifp->bsm_enable = true;
 +      pim_ifp->ucast_bsm_accept = true;
 +
        /*
          RFC 3376: 8.3. Query Response Interval
          The number of seconds represented by the [Query Response Interval]
diff --combined pimd/pim_iface.h
index ab138589bd1252e41891a9409a1223ea50585329,8bf829470e19ce59f6e8586783a2e8a0757a3067..1c11e85705189364f398a783d43055808c4b943f
@@@ -88,8 -88,14 +88,14 @@@ struct pim_interface 
        int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in
                                                  dsecs for general queries */
        int igmp_specific_query_max_response_time_dsec; /* IGMPv3 Max Response
-                                                          Time in dsecs for
-                                                          specific queries */
+                                                          Time in dsecs called
+                                                          as last member query
+                                                          interval, defines the
+                                                          maximum response time
+                                                          advertised in IGMP
+                                                          group-specific
+                                                          queries */
+       int igmp_last_member_query_count; /* IGMP last member query count */
        struct list *igmp_socket_list; /* list of struct igmp_sock */
        struct list *igmp_join_list;   /* list of struct igmp_join */
  
        bool activeactive;
  
        int64_t pim_ifstat_start; /* start timestamp for stats */
 +      uint64_t pim_ifstat_bsm_rx;
 +      uint64_t pim_ifstat_bsm_tx;
        uint32_t pim_ifstat_hello_sent;
        uint32_t pim_ifstat_hello_sendfail;
        uint32_t pim_ifstat_hello_recv;
        uint32_t pim_ifstat_reg_stop_send;
        uint32_t pim_ifstat_assert_recv;
        uint32_t pim_ifstat_assert_send;
 +      uint32_t pim_ifstat_bsm_cfg_miss;
 +      uint32_t pim_ifstat_ucast_bsm_cfg_miss;
 +      uint32_t pim_ifstat_bsm_invalid_sz;
        struct bfd_info *bfd_info;
 +      bool bsm_enable; /* bsm processing enable */
 +      bool ucast_bsm_accept; /* ucast bsm processing */
  };
  
  /*
diff --combined pimd/pim_vty.c
index 8d40f85132acb78fe150578b6413e00e6b4dc59d,e5587503b60e02aaf9068d4539e95ac864f03379..468cd56ee55bf315726948b9433ba2b8ca065a99
@@@ -39,7 -39,6 +39,7 @@@
  #include "pim_msdp.h"
  #include "pim_ssm.h"
  #include "pim_bfd.h"
 +#include "pim_bsm.h"
  #include "pim_vxlan.h"
  
  int pim_debug_config_write(struct vty *vty)
                ++writes;
        }
  
 +      if (PIM_DEBUG_BSM) {
 +              vty_out(vty, "debug pim bsm\n");
 +              ++writes;
 +      }
 +
        if (PIM_DEBUG_VXLAN) {
                vty_out(vty, "debug pim vxlan\n");
                ++writes;
@@@ -350,6 -344,24 +350,24 @@@ int pim_interface_config_write(struct v
                                        ++writes;
                                }
  
+                               /* IF ip igmp last-member_query-count */
+                               if (pim_ifp->igmp_last_member_query_count
+                                   != IGMP_DEFAULT_ROBUSTNESS_VARIABLE) {
+                                       vty_out(vty,
+                                               " ip igmp last-member-query-count %d\n",
+                                               pim_ifp->igmp_last_member_query_count);
+                                       ++writes;
+                               }
+                               /* IF ip igmp last-member_query-interval */
+                               if (pim_ifp->igmp_specific_query_max_response_time_dsec
+                                   != IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) {
+                                       vty_out(vty,
+                                               " ip igmp last-member-query-interval %d\n",
+                                               pim_ifp->igmp_specific_query_max_response_time_dsec);
+                                         ++writes;
+                               }
                                /* IF ip igmp join */
                                if (pim_ifp->igmp_join_list) {
                                        struct listnode *node;
  
                                writes +=
                                        pim_static_write_mroute(pim, vty, ifp);
 +                              pim_bsm_write_config(vty, ifp);
 +                              ++writes;
                                pim_bfd_write_config(vty, ifp);
 +                              ++writes;
                        }
                        vty_endframe(vty, "!\n");
                        ++writes;