summaryrefslogtreecommitdiff
path: root/pimd/pim_cmd_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_cmd_common.c')
-rw-r--r--pimd/pim_cmd_common.c681
1 files changed, 614 insertions, 67 deletions
diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c
index afb360f9b5..28e4c488f3 100644
--- a/pimd/pim_cmd_common.c
+++ b/pimd/pim_cmd_common.c
@@ -566,6 +566,18 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (pim_addr_is_any(rp_addr) || pim_addr_is_multicast(rp_addr)) {
+ vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+#if PIM_IPV == 6
+ if (IN6_IS_ADDR_LINKLOCAL(&rp_addr)) {
+ vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+#endif
+
vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;
@@ -1027,6 +1039,11 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
json_object *json)
{
struct channel_oil *c_oil;
+#if PIM_IPV != 4
+ struct ttable *tt = NULL;
+ char *table = NULL;
+#endif
+ char flag[50];
json_object *json_group = NULL;
json_object *json_ifp_in = NULL;
json_object *json_ifp_out = NULL;
@@ -1038,9 +1055,18 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
if (!json) {
vty_out(vty,
- "Codes: J -> Pim Join, I -> " GM " Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted");
+ "Codes: J -> Pim Join, I -> " GM " Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted\n");
+#if PIM_IPV == 4
vty_out(vty,
- "\nActive Source Group RPT IIF OIL\n");
+ "Active Source Group RPT IIF OIL\n");
+#else
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Active|Source|Group|RPT|IIF|OIL");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+#endif
}
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
@@ -1153,11 +1179,14 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
"wrongInterface",
c_oil->cc.wrong_if);
}
- } else
+ }
+#if PIM_IPV == 4
+ else
vty_out(vty, "%-6d %-15pPAs %-15pPAs %-3s %-16s ",
c_oil->installed, oil_origin(c_oil),
oil_mcastgrp(c_oil), isRpt ? "y" : "n",
in_ifname);
+#endif
for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
++oif_vif_index) {
@@ -1199,72 +1228,72 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
json_object_object_add(json_ifp_in, out_ifname,
json_ifp_out);
} else {
+ flag[0] = '\0';
+ snprintf(flag, sizeof(flag), "(%c%c%c%c%c)",
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_GM)
+ ? 'I'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_PIM)
+ ? 'J'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_VXLAN)
+ ? 'V'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_STAR)
+ ? '*'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_MUTE)
+ ? 'M'
+ : ' ');
+
if (first_oif) {
first_oif = 0;
- vty_out(vty, "%s(%c%c%c%c%c)",
- out_ifname,
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_GM)
- ? 'I'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_PIM)
- ? 'J'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_VXLAN)
- ? 'V'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_STAR)
- ? '*'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_MUTE)
- ? 'M'
- : ' ');
- } else
- vty_out(vty, ", %s(%c%c%c%c%c)",
- out_ifname,
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_GM)
- ? 'I'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_PIM)
- ? 'J'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_VXLAN)
- ? 'V'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_STAR)
- ? '*'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_MUTE)
- ? 'M'
- : ' ');
+#if PIM_IPV == 4
+ vty_out(vty, "%s%s", out_ifname, flag);
+#else
+ ttable_add_row(
+ tt, "%d|%pPAs|%pPAs|%s|%s|%s%s",
+ c_oil->installed,
+ oil_origin(c_oil),
+ oil_mcastgrp(c_oil),
+ isRpt ? "y" : "n", in_ifname,
+ out_ifname, flag);
+#endif
+ } else {
+#if PIM_IPV == 4
+ vty_out(vty, ", %s%s", out_ifname,
+ flag);
+#else
+ ttable_add_row(tt,
+ "%c|%c|%c|%c|%c|%s%s",
+ ' ', ' ', ' ', ' ', ' ',
+ out_ifname, flag);
+#endif
+ }
}
}
-
+#if PIM_IPV == 4
if (!json)
vty_out(vty, "\n");
+#endif
}
- if (!json)
+ /* Dump the generated table. */
+ if (!json) {
+#if PIM_IPV == 4
vty_out(vty, "\n");
+#else
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+#endif
+ }
}
/* pim statistics - just adding only bsm related now.
@@ -2795,21 +2824,35 @@ static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
struct nexthop *nh_node = NULL;
ifindex_t first_ifindex;
struct interface *ifp = NULL;
+ struct ttable *tt = NULL;
+ char *table = NULL;
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Address|Interface|Nexthop");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
first_ifindex = nh_node->ifindex;
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
- vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr);
- vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
#if PIM_IPV == 4
- vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
+ ttable_add_row(tt, "%pPA|%s|%pI4", &pnc->rpf.rpf_addr,
+ ifp ? ifp->name : "NULL", &nh_node->gate.ipv4);
#else
- vty_out(vty, "%pI6 ", &nh_node->gate.ipv6);
+ ttable_add_row(tt, "%pPA|%s|%pI6", &pnc->rpf.rpf_addr,
+ ifp ? ifp->name : "NULL", &nh_node->gate.ipv6);
#endif
- vty_out(vty, "\n");
}
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+
return CMD_SUCCESS;
}
@@ -2937,8 +2980,6 @@ void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
} else {
vty_out(vty, "Number of registered addresses: %lu\n",
pim->rpf_hash->count);
- vty_out(vty, "Address Interface Nexthop\n");
- vty_out(vty, "---------------------------------------------\n");
}
if (uj) {
@@ -3399,6 +3440,66 @@ int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation,
return nb_cli_apply_changes(vty, NULL);
}
+int pim_process_bsm_cmd(struct vty *vty)
+{
+ const struct lyd_node *gm_enable_dnode;
+
+ gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ if (!gm_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(gm_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
+int pim_process_no_bsm_cmd(struct vty *vty)
+{
+ nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
+int pim_process_unicast_bsm_cmd(struct vty *vty)
+{
+ const struct lyd_node *gm_enable_dnode;
+
+ gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ if (!gm_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(gm_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
+int pim_process_no_unicast_bsm_cmd(struct vty *vty)
+{
+ nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
time_t now)
{
@@ -5166,3 +5267,449 @@ void clear_pim_interfaces(struct pim_instance *pim)
pim_neighbor_delete_all(ifp, "interface cleared");
}
}
+
+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];
+ json_object *json = NULL;
+
+ if (pim_addr_is_any(pim->global_scope.current_bsr)) {
+ 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 {
+ 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:
+ strlcpy(bsr_state, "NO_INFO", sizeof(bsr_state));
+ break;
+ case ACCEPT_ANY:
+ strlcpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
+ break;
+ case ACCEPT_PREFERRED:
+ strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
+ break;
+ default:
+ strlcpy(bsr_state, "", sizeof(bsr_state));
+ }
+
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_string_addf(json, "bsr", "%pPA",
+ &pim->global_scope.current_bsr);
+ json_object_int_add(json, "priority",
+ pim->global_scope.current_bsr_prio);
+ json_object_int_add(json, "fragmentTag",
+ 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, "lastBsmSeen", last_bsm_seen);
+ }
+
+ else {
+ vty_out(vty, "PIMv2 Bootstrap information\n");
+ vty_out(vty, "Current preferred BSR address: %pPA\n",
+ &pim->global_scope.current_bsr);
+ 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_json(vty, json);
+}
+
+int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj)
+{
+ struct pim_instance *pim;
+ struct vrf *v;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+ if (!v)
+ return CMD_WARNING;
+
+ pim = pim_get_pim_instance(v->vrf_id);
+
+ if (!pim) {
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ pim_show_bsr(v->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+/*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 bsm_rpinfo *bsm_rp;
+ struct route_node *rn;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+ struct ttable *tt = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_string_addf(json, "BSR Address", "%pPA",
+ &pim->global_scope.current_bsr);
+ } else
+ vty_out(vty, "BSR Address %pPA\n",
+ &pim->global_scope.current_bsr);
+
+ 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[PREFIX_STRLEN];
+
+ 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 %pFX\n", &bsgrp->group);
+ vty_out(vty, "--------------------------\n");
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Rp Address|priority|Holdtime|Hash");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+
+ ttable_add_row(tt, "%s|%c|%c|%c", "(ACTIVE)", ' ', ' ',
+ ' ');
+ }
+
+ frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_addf(json_row, "Rp Address",
+ "%pPA",
+ &bsm_rp->rp_address);
+ 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_addf(json_group, json_row,
+ "%pPA",
+ &bsm_rp->rp_address);
+
+ } else {
+ ttable_add_row(
+ tt, "%pPA|%u|%u|%u",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
+ }
+ }
+ /* Dump the generated table. */
+ if (tt) {
+ char *table = NULL;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ tt = NULL;
+ }
+ if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !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) {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Rp Address|priority|Holdtime|Hash");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
+ }
+
+ frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_addf(json_row, "Rp Address",
+ "%pPA",
+ &bsm_rp->rp_address);
+ 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_addf(json_group, json_row,
+ "%pPA",
+ &bsm_rp->rp_address);
+ } else {
+ ttable_add_row(
+ tt, "%pPA|%u|%u|%u",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
+ }
+ }
+ /* Dump the generated table. */
+ if (tt) {
+ char *table = NULL;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
+ if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
+ vty_out(vty, "Partial List is empty\n");
+
+ if (!uj)
+ vty_out(vty, "\n");
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+int pim_show_group_rp_mappings_info_helper(const char *vrf, struct vty *vty,
+ bool uj)
+{
+ struct pim_instance *pim;
+ struct vrf *v;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+ if (!v)
+ return CMD_WARNING;
+
+ pim = v->info;
+
+ if (!pim) {
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ pim_show_group_rp_mappings_info(v->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+/* Display the bsm database details */
+static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
+{
+ int count = 0;
+ int fragment = 1;
+ struct bsm_frag *bsfrag;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+
+ count = bsm_frags_count(pim->global_scope.bsm_frags);
+
+ 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");
+ }
+
+ frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
+ char grp_str[PREFIX_STRLEN];
+ struct bsmmsg_grpinfo *group;
+ struct bsmmsg_rpinfo *bsm_rpinfo;
+ struct prefix grp;
+ struct bsm_hdr *hdr;
+ pim_addr bsr_addr;
+ uint32_t offset = 0;
+ uint8_t *buf;
+ uint32_t len = 0;
+ uint32_t frag_rp_cnt = 0;
+
+ buf = bsfrag->data;
+ len = bsfrag->size;
+
+ /* skip pim header */
+ buf += PIM_MSG_HEADER_LEN;
+ len -= PIM_MSG_HEADER_LEN;
+
+ hdr = (struct bsm_hdr *)buf;
+ /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
+ memcpy(&bsr_addr, &hdr->bsr_addr.addr, sizeof(bsr_addr));
+
+ /* BSM starts with bsr header */
+ buf += sizeof(struct bsm_hdr);
+ len -= sizeof(struct bsm_hdr);
+
+ if (uj) {
+ json_object_string_addf(json, "BSR address", "%pPA",
+ &bsr_addr);
+ 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, "%-15pPA %-15d %-15d %-15d\n", &bsr_addr,
+ 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;
+ else if (group->group.family ==
+ PIM_MSG_ADDRESS_FAMILY_IPV6)
+ grp.family = AF_INET6;
+
+ grp.prefixlen = group->group.mask;
+#if PIM_IPV == 4
+ grp.u.prefix4 = group->group.addr;
+#else
+ grp.u.prefix6 = group->group.addr;
+#endif
+
+ 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--) {
+ pim_addr rp_addr;
+
+ bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
+ /* unaligned, again */
+ memcpy(&rp_addr, &bsm_rpinfo->rpaddr.addr,
+ sizeof(rp_addr));
+
+ buf += sizeof(struct bsmmsg_rpinfo);
+ offset += sizeof(struct bsmmsg_rpinfo);
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_addf(
+ json_row, "Rp Address", "%pPA",
+ &rp_addr);
+ json_object_int_add(
+ json_row, "Rp HoldTime",
+ ntohs(bsm_rpinfo->rp_holdtime));
+ json_object_int_add(json_row,
+ "Rp Priority",
+ bsm_rpinfo->rp_pri);
+ json_object_object_addf(
+ json_group, json_row, "%pPA",
+ &rp_addr);
+ } else {
+ vty_out(vty, "%-15pPA %-12d %d\n",
+ &rp_addr,
+ ntohs(bsm_rpinfo->rp_holdtime),
+ bsm_rpinfo->rp_pri);
+ }
+ }
+ vty_out(vty, "\n");
+ }
+
+ fragment++;
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj)
+{
+ struct pim_instance *pim;
+ struct vrf *v;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+ if (!v)
+ return CMD_WARNING;
+
+ pim = v->info;
+
+ if (!pim) {
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ pim_show_bsm_db(v->info, vty, uj);
+
+ return CMD_SUCCESS;
+}