summaryrefslogtreecommitdiffstats
path: root/pimd/pim_cmd.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pimd/pim_cmd.c6882
1 files changed, 6882 insertions, 0 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
new file mode 100644
index 0000000..c2f7396
--- /dev/null
+++ b/pimd/pim_cmd.c
@@ -0,0 +1,6882 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2008 Everton da Silva Marques
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "lib/json.h"
+#include "command.h"
+#include "if.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "plist.h"
+#include "hash.h"
+#include "nexthop.h"
+#include "vrf.h"
+#include "ferr.h"
+
+#include "pimd.h"
+#include "pim_mroute.h"
+#include "pim_cmd.h"
+#include "pim_iface.h"
+#include "pim_vty.h"
+#include "pim_mroute.h"
+#include "pim_str.h"
+#include "pim_igmp.h"
+#include "pim_igmpv3.h"
+#include "pim_sock.h"
+#include "pim_time.h"
+#include "pim_util.h"
+#include "pim_oil.h"
+#include "pim_neighbor.h"
+#include "pim_pim.h"
+#include "pim_ifchannel.h"
+#include "pim_hello.h"
+#include "pim_msg.h"
+#include "pim_upstream.h"
+#include "pim_rpf.h"
+#include "pim_macro.h"
+#include "pim_ssmpingd.h"
+#include "pim_zebra.h"
+#include "pim_static.h"
+#include "pim_rp.h"
+#include "pim_zlookup.h"
+#include "pim_msdp.h"
+#include "pim_ssm.h"
+#include "pim_nht.h"
+#include "pim_bfd.h"
+#include "pim_vxlan.h"
+#include "pim_mlag.h"
+#include "bfd.h"
+#include "pim_bsm.h"
+#include "lib/northbound_cli.h"
+#include "pim_errors.h"
+#include "pim_nb.h"
+#include "pim_addr.h"
+#include "pim_cmd_common.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "pimd/pim_cmd_clippy.c"
+#endif
+
+static struct cmd_node debug_node = {
+ .name = "debug",
+ .node = DEBUG_NODE,
+ .prompt = "",
+ .config_write = pim_debug_config_write,
+};
+
+static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
+ const int argc, int *idx)
+{
+ struct vrf *vrf;
+
+ if (argv_find(argv, argc, "NAME", idx))
+ vrf = vrf_lookup_by_name(argv[*idx]->arg);
+ else
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+ if (!vrf)
+ vty_out(vty, "Specified VRF: %s does not exist\n",
+ argv[*idx]->arg);
+
+ return vrf;
+}
+
+static void pim_show_assert_helper(struct vty *vty,
+ struct pim_interface *pim_ifp,
+ struct pim_ifchannel *ch, time_t now)
+{
+ char winner_str[INET_ADDRSTRLEN];
+ struct in_addr ifaddr;
+ char uptime[10];
+ char timer[10];
+ char buf[PREFIX_STRLEN];
+
+ ifaddr = pim_ifp->primary_address;
+
+ pim_inet4_dump("<assrt_win?>", ch->ifassert_winner, winner_str,
+ sizeof(winner_str));
+
+ pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation);
+ pim_time_timer_to_mmss(timer, sizeof(timer), ch->t_ifassert_timer);
+
+ vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-6s %-15s %-8s %-5s\n",
+ ch->interface->name,
+ inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src,
+ &ch->sg.grp, pim_ifchannel_ifassert_name(ch->ifassert_state),
+ winner_str, uptime, timer);
+}
+
+static void pim_show_assert(struct pim_instance *pim, struct vty *vty)
+{
+ struct pim_interface *pim_ifp;
+ struct pim_ifchannel *ch;
+ struct interface *ifp;
+ time_t now;
+
+ now = pim_time_monotonic_sec();
+
+ vty_out(vty,
+ "Interface Address Source Group State Winner Uptime Timer\n");
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ pim_ifp = ifp->info;
+ if (!pim_ifp)
+ continue;
+
+ RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+ if (ch->ifassert_state == PIM_IFASSERT_NOINFO)
+ continue;
+
+ pim_show_assert_helper(vty, pim_ifp, ch, now);
+ } /* scan interface channels */
+ }
+}
+
+static void pim_show_assert_internal_helper(struct vty *vty,
+ struct pim_interface *pim_ifp,
+ struct pim_ifchannel *ch)
+{
+ struct in_addr ifaddr;
+ char buf[PREFIX_STRLEN];
+
+ ifaddr = pim_ifp->primary_address;
+
+ vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-3s %-3s %-3s %-4s\n",
+ ch->interface->name,
+ inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src,
+ &ch->sg.grp,
+ PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no",
+ pim_macro_ch_could_assert_eval(ch) ? "yes" : "no",
+ PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) ? "yes"
+ : "no",
+ pim_macro_assert_tracking_desired_eval(ch) ? "yes" : "no");
+}
+
+static void pim_show_assert_internal(struct pim_instance *pim, struct vty *vty)
+{
+ struct pim_interface *pim_ifp;
+ struct pim_ifchannel *ch;
+ struct interface *ifp;
+
+ vty_out(vty,
+ "CA: CouldAssert\n"
+ "ECA: Evaluate CouldAssert\n"
+ "ATD: AssertTrackingDesired\n"
+ "eATD: Evaluate AssertTrackingDesired\n\n");
+
+ vty_out(vty,
+ "Interface Address Source Group CA eCA ATD eATD\n");
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ pim_ifp = ifp->info;
+ if (!pim_ifp)
+ continue;
+
+ RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+ pim_show_assert_internal_helper(vty, pim_ifp, ch);
+ } /* scan interface channels */
+ }
+}
+
+static void pim_show_assert_metric_helper(struct vty *vty,
+ struct pim_interface *pim_ifp,
+ struct pim_ifchannel *ch)
+{
+ char addr_str[INET_ADDRSTRLEN];
+ struct pim_assert_metric am;
+ struct in_addr ifaddr;
+ char buf[PREFIX_STRLEN];
+
+ ifaddr = pim_ifp->primary_address;
+
+ am = pim_macro_spt_assert_metric(&ch->upstream->rpf,
+ pim_ifp->primary_address);
+
+ pim_inet4_dump("<addr?>", am.ip_address, addr_str, sizeof(addr_str));
+
+ vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-3s %4u %6u %-15s\n",
+ ch->interface->name,
+ inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src,
+ &ch->sg.grp, am.rpt_bit_flag ? "yes" : "no",
+ am.metric_preference, am.route_metric, addr_str);
+}
+
+static void pim_show_assert_metric(struct pim_instance *pim, struct vty *vty)
+{
+ struct pim_interface *pim_ifp;
+ struct pim_ifchannel *ch;
+ struct interface *ifp;
+
+ vty_out(vty,
+ "Interface Address Source Group RPT Pref Metric Address \n");
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ pim_ifp = ifp->info;
+ if (!pim_ifp)
+ continue;
+
+ RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+ pim_show_assert_metric_helper(vty, pim_ifp, ch);
+ } /* scan interface channels */
+ }
+}
+
+static void pim_show_assert_winner_metric_helper(struct vty *vty,
+ struct pim_interface *pim_ifp,
+ struct pim_ifchannel *ch)
+{
+ char addr_str[INET_ADDRSTRLEN];
+ struct pim_assert_metric *am;
+ struct in_addr ifaddr;
+ char pref_str[16];
+ char metr_str[16];
+ char buf[PREFIX_STRLEN];
+
+ ifaddr = pim_ifp->primary_address;
+
+ am = &ch->ifassert_winner_metric;
+
+ pim_inet4_dump("<addr?>", am->ip_address, addr_str, sizeof(addr_str));
+
+ if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
+ snprintf(pref_str, sizeof(pref_str), "INFI");
+ else
+ snprintf(pref_str, sizeof(pref_str), "%4u",
+ am->metric_preference);
+
+ if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX)
+ snprintf(metr_str, sizeof(metr_str), "INFI");
+ else
+ snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric);
+
+ vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-3s %-4s %-6s %-15s\n",
+ ch->interface->name,
+ inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src,
+ &ch->sg.grp, am->rpt_bit_flag ? "yes" : "no", pref_str,
+ metr_str, addr_str);
+}
+
+static void pim_show_assert_winner_metric(struct pim_instance *pim,
+ struct vty *vty)
+{
+ struct pim_interface *pim_ifp;
+ struct pim_ifchannel *ch;
+ struct interface *ifp;
+
+ vty_out(vty,
+ "Interface Address Source Group RPT Pref Metric Address \n");
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ pim_ifp = ifp->info;
+ if (!pim_ifp)
+ continue;
+
+ RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+ pim_show_assert_winner_metric_helper(vty, pim_ifp, ch);
+ } /* scan interface channels */
+ }
+}
+
+static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty,
+ bool uj)
+{
+ struct interface *ifp;
+ time_t now;
+ char buf[PREFIX_STRLEN];
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
+ now = pim_time_monotonic_sec();
+
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "Interface State Address V Querier QuerierIp Query Timer Uptime\n");
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp;
+ struct listnode *sock_node;
+ struct gm_sock *igmp;
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node,
+ igmp)) {
+ char uptime[10];
+ char query_hhmmss[10];
+
+ pim_time_uptime(uptime, sizeof(uptime),
+ now - igmp->sock_creation);
+ pim_time_timer_to_hhmmss(query_hhmmss,
+ sizeof(query_hhmmss),
+ igmp->t_igmp_query_timer);
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_pim_ifp_add(json_row, ifp);
+ json_object_string_add(json_row, "upTime",
+ uptime);
+ json_object_int_add(json_row, "version",
+ pim_ifp->igmp_version);
+
+ if (igmp->t_igmp_query_timer) {
+ json_object_boolean_true_add(json_row,
+ "querier");
+ json_object_string_add(json_row,
+ "queryTimer",
+ query_hhmmss);
+ }
+ json_object_string_addf(json_row, "querierIp",
+ "%pI4",
+ &igmp->querier_addr);
+
+ json_object_object_add(json, ifp->name,
+ json_row);
+
+ if (igmp->mtrace_only) {
+ json_object_boolean_true_add(
+ json_row, "mtraceOnly");
+ }
+ } else {
+ vty_out(vty,
+ "%-16s %5s %15s %d %7s %17pI4 %11s %8s\n",
+ ifp->name,
+ if_is_up(ifp)
+ ? (igmp->mtrace_only ? "mtrc"
+ : "up")
+ : "down",
+ inet_ntop(AF_INET, &igmp->ifaddr, buf,
+ sizeof(buf)),
+ pim_ifp->igmp_version,
+ igmp->t_igmp_query_timer ? "local"
+ : "other",
+ &igmp->querier_addr, query_hhmmss,
+ uptime);
+ }
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void igmp_show_interfaces_single(struct pim_instance *pim,
+ struct vty *vty, const char *ifname,
+ bool uj)
+{
+ struct gm_sock *igmp;
+ struct interface *ifp;
+ struct listnode *sock_node;
+ struct pim_interface *pim_ifp;
+ char uptime[10];
+ char query_hhmmss[10];
+ char other_hhmmss[10];
+ int found_ifname = 0;
+ int sqi;
+ long gmi_msec; /* Group Membership Interval */
+ long lmqt_msec;
+ long ohpi_msec;
+ long oqpi_msec; /* Other Querier Present Interval */
+ long qri_msec;
+ time_t now;
+ int lmqc;
+
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
+ if (uj)
+ json = json_object_new_object();
+
+ now = pim_time_monotonic_sec();
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node,
+ igmp)) {
+ found_ifname = 1;
+ pim_time_uptime(uptime, sizeof(uptime),
+ now - igmp->sock_creation);
+ pim_time_timer_to_hhmmss(query_hhmmss,
+ sizeof(query_hhmmss),
+ igmp->t_igmp_query_timer);
+ pim_time_timer_to_hhmmss(other_hhmmss,
+ sizeof(other_hhmmss),
+ igmp->t_other_querier_timer);
+
+ gmi_msec = PIM_IGMP_GMI_MSEC(
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval,
+ pim_ifp->gm_query_max_response_time_dsec);
+
+ sqi = PIM_IGMP_SQI(pim_ifp->gm_default_query_interval);
+
+ oqpi_msec = PIM_IGMP_OQPI_MSEC(
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval,
+ pim_ifp->gm_query_max_response_time_dsec);
+
+ lmqt_msec = PIM_IGMP_LMQT_MSEC(
+ pim_ifp->gm_specific_query_max_response_time_dsec,
+ pim_ifp->gm_last_member_query_count);
+
+ ohpi_msec =
+ PIM_IGMP_OHPI_DSEC(
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval,
+ pim_ifp->gm_query_max_response_time_dsec) *
+ 100;
+
+ qri_msec =
+ pim_ifp->gm_query_max_response_time_dsec * 100;
+ lmqc = pim_ifp->gm_last_member_query_count;
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_pim_ifp_add(json_row, ifp);
+ json_object_string_add(json_row, "upTime",
+ uptime);
+ json_object_string_add(json_row, "querier",
+ igmp->t_igmp_query_timer
+ ? "local"
+ : "other");
+ json_object_string_addf(json_row, "querierIp",
+ "%pI4",
+ &igmp->querier_addr);
+ json_object_int_add(json_row, "queryStartCount",
+ igmp->startup_query_count);
+ json_object_string_add(json_row,
+ "queryQueryTimer",
+ query_hhmmss);
+ json_object_string_add(json_row,
+ "queryOtherTimer",
+ other_hhmmss);
+ json_object_int_add(json_row, "version",
+ pim_ifp->igmp_version);
+ json_object_int_add(
+ json_row,
+ "timerGroupMembershipIntervalMsec",
+ gmi_msec);
+ json_object_int_add(json_row,
+ "lastMemberQueryCount",
+ lmqc);
+ json_object_int_add(json_row,
+ "timerLastMemberQueryMsec",
+ lmqt_msec);
+ json_object_int_add(
+ json_row,
+ "timerOlderHostPresentIntervalMsec",
+ ohpi_msec);
+ json_object_int_add(
+ json_row,
+ "timerOtherQuerierPresentIntervalMsec",
+ oqpi_msec);
+ json_object_int_add(
+ json_row, "timerQueryInterval",
+ igmp->querier_query_interval);
+ json_object_int_add(
+ json_row,
+ "timerQueryResponseIntervalMsec",
+ qri_msec);
+ json_object_int_add(
+ json_row, "timerRobustnessVariable",
+ igmp->querier_robustness_variable);
+ json_object_int_add(json_row,
+ "timerStartupQueryInterval",
+ sqi);
+
+ json_object_object_add(json, ifp->name,
+ json_row);
+
+ if (igmp->mtrace_only) {
+ json_object_boolean_true_add(
+ json_row, "mtraceOnly");
+ }
+ } else {
+ vty_out(vty, "Interface : %s\n", ifp->name);
+ vty_out(vty, "State : %s\n",
+ if_is_up(ifp) ? (igmp->mtrace_only ?
+ "mtrace"
+ : "up")
+ : "down");
+ vty_out(vty, "Address : %pI4\n",
+ &pim_ifp->primary_address);
+ vty_out(vty, "Uptime : %s\n", uptime);
+ vty_out(vty, "Version : %d\n",
+ pim_ifp->igmp_version);
+ vty_out(vty, "\n");
+ vty_out(vty, "\n");
+
+ vty_out(vty, "Querier\n");
+ vty_out(vty, "-------\n");
+ vty_out(vty, "Querier : %s\n",
+ igmp->t_igmp_query_timer ? "local"
+ : "other");
+ vty_out(vty, "QuerierIp : %pI4",
+ &igmp->querier_addr);
+ if (pim_ifp->primary_address.s_addr
+ == igmp->querier_addr.s_addr)
+ vty_out(vty, " (this router)\n");
+ else
+ vty_out(vty, "\n");
+
+ vty_out(vty, "Start Count : %d\n",
+ igmp->startup_query_count);
+ vty_out(vty, "Query Timer : %s\n",
+ query_hhmmss);
+ vty_out(vty, "Other Timer : %s\n",
+ other_hhmmss);
+ vty_out(vty, "\n");
+ vty_out(vty, "\n");
+
+ vty_out(vty, "Timers\n");
+ vty_out(vty, "------\n");
+ 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);
+ vty_out(vty,
+ "Older Host Present Interval : %lis\n",
+ ohpi_msec / 1000);
+ vty_out(vty,
+ "Other Querier Present Interval : %lis\n",
+ oqpi_msec / 1000);
+ vty_out(vty,
+ "Query Interval : %ds\n",
+ igmp->querier_query_interval);
+ vty_out(vty,
+ "Query Response Interval : %lis\n",
+ qri_msec / 1000);
+ vty_out(vty,
+ "Robustness Variable : %d\n",
+ igmp->querier_robustness_variable);
+ vty_out(vty,
+ "Startup Query Interval : %ds\n",
+ sqi);
+ vty_out(vty, "\n");
+ vty_out(vty, "\n");
+
+ pim_print_ifp_flags(vty, ifp);
+ }
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+ else if (!found_ifname)
+ vty_out(vty, "%% No such interface\n");
+}
+
+static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
+ bool uj)
+{
+ struct interface *ifp;
+ time_t now;
+ json_object *json = NULL;
+ json_object *json_iface = NULL;
+ json_object *json_grp = NULL;
+ json_object *json_grp_arr = NULL;
+
+ now = pim_time_monotonic_sec();
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_string_add(json, "vrf",
+ vrf_id_to_name(pim->vrf->vrf_id));
+ } else {
+ vty_out(vty,
+ "Interface Address Source Group Socket Uptime \n");
+ }
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp;
+ struct listnode *join_node;
+ struct gm_join *ij;
+ struct in_addr pri_addr;
+ char pri_addr_str[INET_ADDRSTRLEN];
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (!pim_ifp->gm_join_list)
+ continue;
+
+ pri_addr = pim_find_primary_addr(ifp);
+ pim_inet4_dump("<pri?>", pri_addr, pri_addr_str,
+ sizeof(pri_addr_str));
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, join_node,
+ ij)) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ char uptime[10];
+
+ pim_time_uptime(uptime, sizeof(uptime),
+ now - ij->sock_creation);
+ pim_inet4_dump("<grp?>", ij->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<src?>", ij->source_addr, source_str,
+ sizeof(source_str));
+
+ if (uj) {
+ json_object_object_get_ex(json, ifp->name,
+ &json_iface);
+
+ if (!json_iface) {
+ json_iface = json_object_new_object();
+ json_object_string_add(
+ json_iface, "name", ifp->name);
+ json_object_object_add(json, ifp->name,
+ json_iface);
+ json_grp_arr = json_object_new_array();
+ json_object_object_add(json_iface,
+ "groups",
+ json_grp_arr);
+ }
+
+ json_grp = json_object_new_object();
+ json_object_string_add(json_grp, "source",
+ source_str);
+ json_object_string_add(json_grp, "group",
+ group_str);
+ json_object_string_add(json_grp, "primaryAddr",
+ pri_addr_str);
+ json_object_int_add(json_grp, "sockFd",
+ ij->sock_fd);
+ json_object_string_add(json_grp, "upTime",
+ uptime);
+ json_object_array_add(json_grp_arr, json_grp);
+ } else {
+ vty_out(vty,
+ "%-16s %-15s %-15s %-15s %6d %8s\n",
+ ifp->name, pri_addr_str, source_str,
+ group_str, ij->sock_fd, uptime);
+ }
+ } /* for (pim_ifp->gm_join_list) */
+
+ } /* for (iflist) */
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
+ const char *ifname, bool uj)
+{
+ struct interface *ifp;
+ struct igmp_stats igmp_stats;
+ bool found_ifname = false;
+ json_object *json = NULL;
+
+ igmp_stats_init(&igmp_stats);
+
+ if (uj)
+ json = json_object_new_object();
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp;
+ struct listnode *sock_node, *source_node, *group_node;
+ struct gm_sock *igmp;
+ struct gm_group *group;
+ struct gm_source *src;
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (ifname && strcmp(ifname, ifp->name))
+ continue;
+
+ found_ifname = true;
+
+ igmp_stats.joins_failed += pim_ifp->igmp_ifstat_joins_failed;
+ igmp_stats.joins_sent += pim_ifp->igmp_ifstat_joins_sent;
+ igmp_stats.total_groups +=
+ pim_ifp->gm_group_list
+ ? listcount(pim_ifp->gm_group_list)
+ : 0;
+ igmp_stats.peak_groups += pim_ifp->igmp_peak_group_count;
+
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, group_node,
+ group)) {
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list,
+ source_node, src)) {
+ if (pim_addr_is_any(src->source_addr))
+ continue;
+
+ igmp_stats.total_source_groups++;
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node,
+ igmp)) {
+ igmp_stats_add(&igmp_stats, &igmp->igmp_stats);
+ }
+ }
+
+ if (!found_ifname) {
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty, "%% No such interface\n");
+ return;
+ }
+
+ if (uj) {
+ json_object *json_row = json_object_new_object();
+
+ json_object_string_add(json_row, "name",
+ ifname ? ifname : "global");
+ json_object_int_add(json_row, "queryV1", igmp_stats.query_v1);
+ json_object_int_add(json_row, "queryV2", igmp_stats.query_v2);
+ json_object_int_add(json_row, "queryV3", igmp_stats.query_v3);
+ json_object_int_add(json_row, "leaveV2", igmp_stats.leave_v2);
+ json_object_int_add(json_row, "reportV1", igmp_stats.report_v1);
+ json_object_int_add(json_row, "reportV2", igmp_stats.report_v2);
+ json_object_int_add(json_row, "reportV3", igmp_stats.report_v3);
+ json_object_int_add(json_row, "mtraceResponse",
+ igmp_stats.mtrace_rsp);
+ json_object_int_add(json_row, "mtraceRequest",
+ igmp_stats.mtrace_req);
+ json_object_int_add(json_row, "unsupported",
+ igmp_stats.unsupported);
+ json_object_int_add(json_row, "totalReceivedMessages",
+ igmp_stats.total_recv_messages);
+ json_object_int_add(json_row, "peakGroups",
+ igmp_stats.peak_groups);
+ json_object_int_add(json_row, "totalGroups",
+ igmp_stats.total_groups);
+ json_object_int_add(json_row, "totalSourceGroups",
+ igmp_stats.total_source_groups);
+ json_object_int_add(json_row, "joinsFailed",
+ igmp_stats.joins_failed);
+ json_object_int_add(json_row, "joinsSent",
+ igmp_stats.joins_sent);
+ json_object_int_add(json_row, "generalQueriesSent",
+ igmp_stats.general_queries_sent);
+ json_object_int_add(json_row, "groupQueriesSent",
+ igmp_stats.group_queries_sent);
+ json_object_object_add(json, ifname ? ifname : "global",
+ json_row);
+ vty_json(vty, json);
+ } else {
+ vty_out(vty, "IGMP statistics\n");
+ vty_out(vty, "Interface : %s\n",
+ ifname ? ifname : "global");
+ vty_out(vty, "V1 query : %u\n",
+ igmp_stats.query_v1);
+ vty_out(vty, "V2 query : %u\n",
+ igmp_stats.query_v2);
+ vty_out(vty, "V3 query : %u\n",
+ igmp_stats.query_v3);
+ vty_out(vty, "V2 leave : %u\n",
+ igmp_stats.leave_v2);
+ vty_out(vty, "V1 report : %u\n",
+ igmp_stats.report_v1);
+ vty_out(vty, "V2 report : %u\n",
+ igmp_stats.report_v2);
+ vty_out(vty, "V3 report : %u\n",
+ igmp_stats.report_v3);
+ vty_out(vty, "mtrace response : %u\n",
+ igmp_stats.mtrace_rsp);
+ vty_out(vty, "mtrace request : %u\n",
+ igmp_stats.mtrace_req);
+ vty_out(vty, "unsupported : %u\n",
+ igmp_stats.unsupported);
+ vty_out(vty, "total received messages : %u\n",
+ igmp_stats.total_recv_messages);
+ vty_out(vty, "joins failed : %u\n",
+ igmp_stats.joins_failed);
+ vty_out(vty, "joins sent : %u\n",
+ igmp_stats.joins_sent);
+ vty_out(vty, "general queries sent : %u\n",
+ igmp_stats.general_queries_sent);
+ vty_out(vty, "group queries sent : %u\n",
+ igmp_stats.group_queries_sent);
+ vty_out(vty, "peak groups : %u\n",
+ igmp_stats.peak_groups);
+ vty_out(vty, "total groups : %u\n",
+ igmp_stats.total_groups);
+ vty_out(vty, "total source groups : %u\n",
+ igmp_stats.total_source_groups);
+ }
+}
+
+/* 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,
+ 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);
+}
+
+/*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;
+
+ 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");
+ vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
+ "priority", "Holdtime", "Hash");
+
+ vty_out(vty, "(ACTIVE)\n");
+ }
+
+ 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 {
+ vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
+ }
+ }
+ 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)
+ vty_out(vty, "%-15s %-15s %-15s %-15s\n",
+ "Rp Address", "priority", "Holdtime",
+ "Hash");
+ }
+
+ 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 {
+ vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
+ }
+ }
+ 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);
+}
+
+static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
+{
+ struct interface *ifp;
+ time_t now;
+ json_object *json = NULL;
+ json_object *json_iface = NULL;
+ json_object *json_group = NULL;
+ json_object *json_groups = NULL;
+
+ now = pim_time_monotonic_sec();
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_int_add(json, "totalGroups", pim->gm_group_count);
+ json_object_int_add(json, "watermarkLimit",
+ pim->gm_watermark_limit);
+ } else {
+ vty_out(vty, "Total IGMP groups: %u\n", pim->gm_group_count);
+ vty_out(vty, "Watermark warn limit(%s): %u\n",
+ pim->gm_watermark_limit ? "Set" : "Not Set",
+ pim->gm_watermark_limit);
+ vty_out(vty,
+ "Interface Group Mode Timer Srcs V Uptime \n");
+ }
+
+ /* scan interfaces */
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *grpnode;
+ struct gm_group *grp;
+
+ if (!pim_ifp)
+ continue;
+
+ /* scan igmp groups */
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
+ grp)) {
+ char group_str[INET_ADDRSTRLEN];
+ char hhmmss[10];
+ char uptime[10];
+
+ pim_inet4_dump("<group?>", grp->group_addr, group_str,
+ sizeof(group_str));
+ pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss),
+ grp->t_group_timer);
+ pim_time_uptime(uptime, sizeof(uptime),
+ now - grp->group_creation);
+
+ if (uj) {
+ json_object_object_get_ex(json, ifp->name,
+ &json_iface);
+
+ if (!json_iface) {
+ json_iface = json_object_new_object();
+ json_object_pim_ifp_add(json_iface,
+ ifp);
+ json_object_object_add(json, ifp->name,
+ json_iface);
+ json_groups = json_object_new_array();
+ json_object_object_add(json_iface,
+ "groups",
+ json_groups);
+ }
+
+ json_group = json_object_new_object();
+ json_object_string_add(json_group, "group",
+ group_str);
+
+ if (grp->igmp_version == 3)
+ json_object_string_add(
+ json_group, "mode",
+ grp->group_filtermode_isexcl
+ ? "EXCLUDE"
+ : "INCLUDE");
+
+ json_object_string_add(json_group, "timer",
+ hhmmss);
+ json_object_int_add(
+ json_group, "sourcesCount",
+ grp->group_source_list ? listcount(
+ grp->group_source_list)
+ : 0);
+ json_object_int_add(json_group, "version",
+ grp->igmp_version);
+ json_object_string_add(json_group, "uptime",
+ uptime);
+ json_object_array_add(json_groups, json_group);
+ } else {
+ vty_out(vty, "%-16s %-15s %4s %8s %4d %d %8s\n",
+ ifp->name, group_str,
+ grp->igmp_version == 3
+ ? (grp->group_filtermode_isexcl
+ ? "EXCL"
+ : "INCL")
+ : "----",
+ hhmmss,
+ grp->group_source_list ? listcount(
+ grp->group_source_list)
+ : 0,
+ grp->igmp_version, uptime);
+ }
+ } /* scan igmp groups */
+ } /* scan interfaces */
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void igmp_show_group_retransmission(struct pim_instance *pim,
+ struct vty *vty)
+{
+ struct interface *ifp;
+
+ vty_out(vty,
+ "Interface Group RetTimer Counter RetSrcs\n");
+
+ /* scan interfaces */
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *grpnode;
+ struct gm_group *grp;
+
+ if (!pim_ifp)
+ continue;
+
+ /* scan igmp groups */
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
+ grp)) {
+ char group_str[INET_ADDRSTRLEN];
+ char grp_retr_mmss[10];
+ struct listnode *src_node;
+ struct gm_source *src;
+ int grp_retr_sources = 0;
+
+ pim_inet4_dump("<group?>", grp->group_addr, group_str,
+ sizeof(group_str));
+ pim_time_timer_to_mmss(
+ grp_retr_mmss, sizeof(grp_retr_mmss),
+ grp->t_group_query_retransmit_timer);
+
+
+ /* count group sources with retransmission state
+ */
+ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+ src_node, src)) {
+ if (src->source_query_retransmit_count > 0) {
+ ++grp_retr_sources;
+ }
+ }
+
+ vty_out(vty, "%-16s %-15s %-8s %7d %7d\n", ifp->name,
+ group_str, grp_retr_mmss,
+ grp->group_specific_query_retransmit_count,
+ grp_retr_sources);
+
+ } /* scan igmp groups */
+ } /* scan interfaces */
+}
+
+static void igmp_show_sources(struct pim_instance *pim, struct vty *vty,
+ bool uj)
+{
+ struct interface *ifp;
+ time_t now;
+ json_object *json = NULL;
+ json_object *json_iface = NULL;
+ json_object *json_group = NULL;
+ json_object *json_source = NULL;
+ json_object *json_sources = NULL;
+
+ now = pim_time_monotonic_sec();
+
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "Interface Group Source Timer Fwd Uptime \n");
+
+ /* scan interfaces */
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *grpnode;
+ struct gm_group *grp;
+
+ if (!pim_ifp)
+ continue;
+
+ /* scan igmp groups */
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
+ grp)) {
+ char group_str[INET_ADDRSTRLEN];
+ struct listnode *srcnode;
+ struct gm_source *src;
+
+ pim_inet4_dump("<group?>", grp->group_addr, group_str,
+ sizeof(group_str));
+
+ /* scan group sources */
+ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+ srcnode, src)) {
+ char source_str[INET_ADDRSTRLEN];
+ char mmss[10];
+ char uptime[10];
+
+ pim_inet4_dump("<source?>", src->source_addr,
+ source_str, sizeof(source_str));
+
+ pim_time_timer_to_mmss(mmss, sizeof(mmss),
+ src->t_source_timer);
+
+ pim_time_uptime(uptime, sizeof(uptime),
+ now - src->source_creation);
+
+ if (uj) {
+ json_object_object_get_ex(
+ json, ifp->name, &json_iface);
+ if (!json_iface) {
+ json_iface =
+ json_object_new_object();
+ json_object_string_add(
+ json_iface, "name",
+ ifp->name);
+ json_object_object_add(
+ json, ifp->name,
+ json_iface);
+ }
+ json_object_object_get_ex(json_iface,
+ group_str,
+ &json_group);
+
+ if (!json_group) {
+ json_group =
+ json_object_new_object();
+ json_object_string_add(
+ json_group, "group",
+ group_str);
+ json_object_object_add(
+ json_iface, group_str,
+ json_group);
+ json_sources =
+ json_object_new_array();
+ json_object_object_add(
+ json_group, "sources",
+ json_sources);
+ }
+ json_source = json_object_new_object();
+ json_object_string_add(json_source,
+ "source",
+ source_str);
+ json_object_string_add(json_source,
+ "timer", mmss);
+ json_object_boolean_add(
+ json_source, "forwarded",
+ IGMP_SOURCE_TEST_FORWARDING(
+ src->source_flags));
+ json_object_string_add(
+ json_source, "uptime", uptime);
+ json_object_array_add(json_sources,
+ json_source);
+
+ } else {
+ vty_out(vty,
+ "%-16s %-15s %-15s %5s %3s %8s\n",
+ ifp->name, group_str,
+ source_str, mmss,
+ IGMP_SOURCE_TEST_FORWARDING(
+ src->source_flags)
+ ? "Y"
+ : "N",
+ uptime);
+ }
+
+ } /* scan group sources */
+ } /* scan igmp groups */
+ } /* scan interfaces */
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void igmp_show_source_retransmission(struct pim_instance *pim,
+ struct vty *vty)
+{
+ struct interface *ifp;
+
+ vty_out(vty,
+ "Interface Group Source Counter\n");
+
+ /* scan interfaces */
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *grpnode;
+ struct gm_group *grp;
+
+ if (!pim_ifp)
+ continue;
+
+ /* scan igmp groups */
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
+ grp)) {
+ char group_str[INET_ADDRSTRLEN];
+ struct listnode *srcnode;
+ struct gm_source *src;
+
+ pim_inet4_dump("<group?>", grp->group_addr, group_str,
+ sizeof(group_str));
+
+ /* scan group sources */
+ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+ srcnode, src)) {
+ char source_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<source?>", src->source_addr,
+ source_str, sizeof(source_str));
+
+ vty_out(vty, "%-16s %-15s %-15s %7d\n",
+ ifp->name, group_str, source_str,
+ src->source_query_retransmit_count);
+
+ } /* scan group sources */
+ } /* scan igmp groups */
+ } /* 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];
+ 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);
+}
+
+static void clear_igmp_interfaces(struct pim_instance *pim)
+{
+ struct interface *ifp;
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp)
+ pim_if_addr_del_all_igmp(ifp);
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp)
+ pim_if_addr_add_all(ifp);
+}
+
+static void clear_interfaces(struct pim_instance *pim)
+{
+ clear_igmp_interfaces(pim);
+ clear_pim_interfaces(pim);
+}
+
+#define PIM_GET_PIM_INTERFACE(pim_ifp, ifp) \
+ pim_ifp = ifp->info; \
+ if (!pim_ifp) { \
+ vty_out(vty, \
+ "%% Enable PIM and/or IGMP on this interface first\n"); \
+ return CMD_WARNING_CONFIG_FAILED; \
+ }
+
+/**
+ * Compatibility function to keep the legacy mesh group CLI behavior:
+ * Delete group when there are no more configurations in it.
+ *
+ * NOTE:
+ * Don't forget to call `nb_cli_apply_changes` after this.
+ */
+static void pim_cli_legacy_mesh_group_behavior(struct vty *vty,
+ const char *gname)
+{
+ const char *vrfname;
+ char xpath_value[XPATH_MAXLEN];
+ char xpath_member_value[XPATH_MAXLEN];
+ const struct lyd_node *member_dnode;
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return;
+
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ /* Group must exists, otherwise just quit. */
+ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
+ return;
+
+ /* Group members check: */
+ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "/members", sizeof(xpath_member_value));
+ if (yang_dnode_exists(vty->candidate_config->dnode,
+ xpath_member_value)) {
+ member_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ xpath_member_value);
+ if (!member_dnode || !yang_is_last_list_dnode(member_dnode))
+ return;
+ }
+
+ /* Source address check: */
+ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "/source", sizeof(xpath_member_value));
+ if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value))
+ return;
+
+ /* No configurations found: delete it. */
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
+}
+
+DEFUN (clear_ip_interfaces,
+ clear_ip_interfaces_cmd,
+ "clear ip interfaces [vrf NAME]",
+ CLEAR_STR
+ IP_STR
+ "Reset interfaces\n"
+ VRF_CMD_HELP_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ clear_interfaces(vrf->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (clear_ip_igmp_interfaces,
+ clear_ip_igmp_interfaces_cmd,
+ "clear ip igmp [vrf NAME] interfaces",
+ CLEAR_STR
+ IP_STR
+ CLEAR_IP_IGMP_STR
+ VRF_CMD_HELP_STR
+ "Reset IGMP interfaces\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ clear_igmp_interfaces(vrf->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (clear_ip_pim_statistics,
+ clear_ip_pim_statistics_cmd,
+ "clear ip pim statistics [vrf NAME]$name",
+ CLEAR_STR
+ IP_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset PIM statistics\n")
+{
+ struct vrf *v = pim_cmd_lookup(vty, name);
+
+ if (!v)
+ return CMD_WARNING;
+
+ clear_pim_statistics(v->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (clear_ip_mroute,
+ clear_ip_mroute_cmd,
+ "clear ip mroute [vrf NAME]$name",
+ CLEAR_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR)
+{
+ struct vrf *v = pim_cmd_lookup(vty, name);
+
+ if (!v)
+ return CMD_WARNING;
+
+ clear_mroute(v->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (clear_ip_pim_interfaces,
+ clear_ip_pim_interfaces_cmd,
+ "clear ip pim [vrf NAME] interfaces",
+ CLEAR_STR
+ IP_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset PIM interfaces\n")
+{
+ struct vrf *v = pim_cmd_lookup(vty, vrf);
+
+ if (!v)
+ return CMD_WARNING;
+
+ clear_pim_interfaces(v->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (clear_ip_pim_interface_traffic,
+ clear_ip_pim_interface_traffic_cmd,
+ "clear ip pim [vrf NAME] interface traffic",
+ CLEAR_STR
+ IP_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset PIM interfaces\n"
+ "Reset Protocol Packet counters\n")
+{
+ return clear_pim_interface_traffic(vrf, vty);
+}
+
+DEFPY (clear_ip_pim_oil,
+ clear_ip_pim_oil_cmd,
+ "clear ip pim [vrf NAME]$name oil",
+ CLEAR_STR
+ IP_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Rescan PIM OIL (output interface list)\n")
+{
+ struct vrf *v = pim_cmd_lookup(vty, name);
+
+ if (!v)
+ return CMD_WARNING;
+
+ pim_scan_oil(v->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (clear_ip_pim_bsr_db,
+ clear_ip_pim_bsr_db_cmd,
+ "clear ip pim [vrf NAME] bsr-data",
+ CLEAR_STR
+ IP_STR
+ CLEAR_IP_PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset pim bsr data\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim_bsm_clear(vrf->info);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_interface,
+ show_ip_igmp_interface_cmd,
+ "show ip igmp [vrf NAME] interface [detail|WORD] [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP interface information\n"
+ "Detailed output\n"
+ "interface name\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, "detail", &idx)
+ || argv_find(argv, argc, "WORD", &idx))
+ igmp_show_interfaces_single(vrf->info, vty, argv[idx]->arg, uj);
+ else
+ igmp_show_interfaces(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_interface_vrf_all,
+ show_ip_igmp_interface_vrf_all_cmd,
+ "show ip igmp vrf all interface [detail|WORD] [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP interface information\n"
+ "Detailed output\n"
+ "interface name\n"
+ JSON_STR)
+{
+ int idx = 2;
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ if (argv_find(argv, argc, "detail", &idx)
+ || argv_find(argv, argc, "WORD", &idx))
+ igmp_show_interfaces_single(vrf->info, vty,
+ argv[idx]->arg, uj);
+ else
+ igmp_show_interfaces(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_join,
+ show_ip_igmp_join_cmd,
+ "show ip igmp [vrf NAME] join [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP static join 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;
+
+ igmp_show_interface_join(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_join_vrf_all,
+ show_ip_igmp_join_vrf_all_cmd,
+ "show ip igmp vrf all join [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP static join information\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ igmp_show_interface_join(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_groups,
+ show_ip_igmp_groups_cmd,
+ "show ip igmp [vrf NAME] groups [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ IGMP_GROUP_STR
+ 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;
+
+ igmp_show_groups(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_groups_vrf_all,
+ show_ip_igmp_groups_vrf_all_cmd,
+ "show ip igmp vrf all groups [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ IGMP_GROUP_STR
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ igmp_show_groups(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_groups_retransmissions,
+ show_ip_igmp_groups_retransmissions_cmd,
+ "show ip igmp [vrf NAME] groups retransmissions",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ IGMP_GROUP_STR
+ "IGMP group retransmissions\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ igmp_show_group_retransmission(vrf->info, vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_sources,
+ show_ip_igmp_sources_cmd,
+ "show ip igmp [vrf NAME] sources [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ IGMP_SOURCE_STR
+ JSON_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ igmp_show_sources(vrf->info, vty, use_json(argc, argv));
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_sources_retransmissions,
+ show_ip_igmp_sources_retransmissions_cmd,
+ "show ip igmp [vrf NAME] sources retransmissions",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ IGMP_SOURCE_STR
+ "IGMP source retransmissions\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ igmp_show_source_retransmission(vrf->info, vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_statistics,
+ show_ip_igmp_statistics_cmd,
+ "show ip igmp [vrf NAME] statistics [interface WORD] [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP statistics\n"
+ "interface\n"
+ "IGMP 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))
+ igmp_show_statistics(vrf->info, vty, argv[idx]->arg, uj);
+ else
+ igmp_show_statistics(vrf->info, vty, NULL, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_mlag_summary,
+ show_ip_pim_mlag_summary_cmd,
+ "show ip pim mlag summary [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "MLAG\n"
+ "status and stats\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ char role_buf[MLAG_ROLE_STRSIZE];
+ char addr_buf[INET_ADDRSTRLEN];
+
+ if (uj) {
+ json_object *json = NULL;
+ json_object *json_stat = NULL;
+
+ json = json_object_new_object();
+ if (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)
+ json_object_boolean_true_add(json, "mlagConnUp");
+ if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
+ json_object_boolean_true_add(json, "mlagPeerConnUp");
+ if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
+ json_object_boolean_true_add(json, "mlagPeerZebraUp");
+ json_object_string_add(json, "mlagRole",
+ mlag_role2str(router->mlag_role,
+ role_buf, sizeof(role_buf)));
+ inet_ntop(AF_INET, &router->local_vtep_ip,
+ addr_buf, INET_ADDRSTRLEN);
+ json_object_string_add(json, "localVtepIp", addr_buf);
+ inet_ntop(AF_INET, &router->anycast_vtep_ip,
+ addr_buf, INET_ADDRSTRLEN);
+ json_object_string_add(json, "anycastVtepIp", addr_buf);
+ json_object_string_add(json, "peerlinkRif",
+ router->peerlink_rif);
+
+ json_stat = json_object_new_object();
+ json_object_int_add(json_stat, "mlagConnFlaps",
+ router->mlag_stats.mlagd_session_downs);
+ json_object_int_add(json_stat, "mlagPeerConnFlaps",
+ router->mlag_stats.peer_session_downs);
+ json_object_int_add(json_stat, "mlagPeerZebraFlaps",
+ router->mlag_stats.peer_zebra_downs);
+ json_object_int_add(json_stat, "mrouteAddRx",
+ router->mlag_stats.msg.mroute_add_rx);
+ json_object_int_add(json_stat, "mrouteAddTx",
+ router->mlag_stats.msg.mroute_add_tx);
+ json_object_int_add(json_stat, "mrouteDelRx",
+ router->mlag_stats.msg.mroute_del_rx);
+ json_object_int_add(json_stat, "mrouteDelTx",
+ router->mlag_stats.msg.mroute_del_tx);
+ json_object_int_add(json_stat, "mlagStatusUpdates",
+ router->mlag_stats.msg.mlag_status_updates);
+ json_object_int_add(json_stat, "peerZebraStatusUpdates",
+ router->mlag_stats.msg.peer_zebra_status_updates);
+ json_object_int_add(json_stat, "pimStatusUpdates",
+ router->mlag_stats.msg.pim_status_updates);
+ json_object_int_add(json_stat, "vxlanUpdates",
+ router->mlag_stats.msg.vxlan_updates);
+ json_object_object_add(json, "connStats", json_stat);
+
+ vty_json(vty, json);
+ return CMD_SUCCESS;
+ }
+
+ vty_out(vty, "MLAG daemon connection: %s\n",
+ (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)
+ ? "up" : "down");
+ vty_out(vty, "MLAG peer state: %s\n",
+ (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
+ ? "up" : "down");
+ vty_out(vty, "Zebra peer state: %s\n",
+ (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
+ ? "up" : "down");
+ vty_out(vty, "MLAG role: %s\n",
+ mlag_role2str(router->mlag_role, role_buf, sizeof(role_buf)));
+ inet_ntop(AF_INET, &router->local_vtep_ip,
+ addr_buf, INET_ADDRSTRLEN);
+ vty_out(vty, "Local VTEP IP: %s\n", addr_buf);
+ inet_ntop(AF_INET, &router->anycast_vtep_ip,
+ addr_buf, INET_ADDRSTRLEN);
+ vty_out(vty, "Anycast VTEP IP: %s\n", addr_buf);
+ vty_out(vty, "Peerlink: %s\n", router->peerlink_rif);
+ vty_out(vty, "Session flaps: mlagd: %d mlag-peer: %d zebra-peer: %d\n",
+ router->mlag_stats.mlagd_session_downs,
+ router->mlag_stats.peer_session_downs,
+ router->mlag_stats.peer_zebra_downs);
+ vty_out(vty, "Message Statistics:\n");
+ vty_out(vty, " mroute adds: rx: %d, tx: %d\n",
+ router->mlag_stats.msg.mroute_add_rx,
+ router->mlag_stats.msg.mroute_add_tx);
+ vty_out(vty, " mroute dels: rx: %d, tx: %d\n",
+ router->mlag_stats.msg.mroute_del_rx,
+ router->mlag_stats.msg.mroute_del_tx);
+ vty_out(vty, " peer zebra status updates: %d\n",
+ router->mlag_stats.msg.peer_zebra_status_updates);
+ vty_out(vty, " PIM status updates: %d\n",
+ router->mlag_stats.msg.pim_status_updates);
+ vty_out(vty, " VxLAN updates: %d\n",
+ router->mlag_stats.msg.vxlan_updates);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_assert,
+ show_ip_pim_assert_cmd,
+ "show ip pim [vrf NAME] assert",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface assert\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim_show_assert(vrf->info, vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_assert_internal,
+ show_ip_pim_assert_internal_cmd,
+ "show ip pim [vrf NAME] assert-internal",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface internal assert state\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim_show_assert_internal(vrf->info, vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_assert_metric,
+ show_ip_pim_assert_metric_cmd,
+ "show ip pim [vrf NAME] assert-metric",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface assert metric\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim_show_assert_metric(vrf->info, vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_assert_winner_metric,
+ show_ip_pim_assert_winner_metric_cmd,
+ "show ip pim [vrf NAME] assert-winner-metric",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface assert winner metric\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim_show_assert_winner_metric(vrf->info, vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_pim_interface,
+ show_ip_pim_interface_cmd,
+ "show ip pim [mlag$mlag] [vrf NAME] interface [detail|WORD]$interface [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "MLAG\n"
+ VRF_CMD_HELP_STR
+ "PIM interface information\n"
+ "Detailed output\n"
+ "interface name\n"
+ JSON_STR)
+{
+ return pim_show_interface_cmd_helper(vrf, vty, !!json, !!mlag,
+ interface);
+}
+
+DEFPY (show_ip_pim_interface_vrf_all,
+ show_ip_pim_interface_vrf_all_cmd,
+ "show ip pim [mlag$mlag] vrf all interface [detail|WORD]$interface [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "MLAG\n"
+ VRF_CMD_HELP_STR
+ "PIM interface information\n"
+ "Detailed output\n"
+ "interface name\n"
+ JSON_STR)
+{
+ return pim_show_interface_vrf_all_cmd_helper(vty, !!json, !!mlag,
+ interface);
+}
+
+DEFPY (show_ip_pim_join,
+ show_ip_pim_join_cmd,
+ "show ip pim [vrf NAME] join [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface join information\n"
+ "The Source or Group\n"
+ "The Group\n"
+ JSON_STR)
+{
+ return pim_show_join_cmd_helper(vrf, vty, s_or_g, g, json);
+}
+
+DEFPY (show_ip_pim_join_vrf_all,
+ show_ip_pim_join_vrf_all_cmd,
+ "show ip pim vrf all join [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface join information\n"
+ JSON_STR)
+{
+ return pim_show_join_vrf_all_cmd_helper(vty, json);
+}
+
+DEFPY (show_ip_pim_jp_agg,
+ show_ip_pim_jp_agg_cmd,
+ "show ip pim [vrf NAME] jp-agg",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "join prune aggregation list\n")
+{
+ return pim_show_jp_agg_list_cmd_helper(vrf, vty);
+}
+
+DEFPY (show_ip_pim_local_membership,
+ show_ip_pim_local_membership_cmd,
+ "show ip pim [vrf NAME] local-membership [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface local-membership\n"
+ JSON_STR)
+{
+ return pim_show_membership_cmd_helper(vrf, vty, !!json);
+}
+
+static void pim_show_mlag_up_entry_detail(struct vrf *vrf,
+ struct vty *vty,
+ struct pim_upstream *up,
+ char *src_str, char *grp_str,
+ json_object *json)
+{
+ if (json) {
+ json_object *json_row = NULL;
+ json_object *own_list = NULL;
+ json_object *json_group = NULL;
+
+
+ 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);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+
+ own_list = json_object_new_array();
+ if (pim_up_mlag_is_local(up))
+ json_object_array_add(own_list,
+ json_object_new_string("local"));
+ if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
+ json_object_array_add(own_list,
+ json_object_new_string("peer"));
+ if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
+ json_object_array_add(
+ own_list, json_object_new_string("Interface"));
+ json_object_object_add(json_row, "owners", own_list);
+
+ json_object_int_add(json_row, "localCost",
+ pim_up_mlag_local_cost(up));
+ json_object_int_add(json_row, "peerCost",
+ pim_up_mlag_peer_cost(up));
+ if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
+ json_object_boolean_false_add(json_row, "df");
+ else
+ json_object_boolean_true_add(json_row, "df");
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ char own_str[6];
+
+ own_str[0] = '\0';
+ if (pim_up_mlag_is_local(up))
+ strlcat(own_str, "L", sizeof(own_str));
+ if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
+ strlcat(own_str, "P", sizeof(own_str));
+ if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
+ strlcat(own_str, "I", sizeof(own_str));
+ /* XXX - fixup, print paragraph output */
+ vty_out(vty,
+ "%-15s %-15s %-6s %-11u %-10d %2s\n",
+ src_str, grp_str, own_str,
+ pim_up_mlag_local_cost(up),
+ pim_up_mlag_peer_cost(up),
+ PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
+ ? "n" : "y");
+ }
+}
+
+static void pim_show_mlag_up_detail(struct vrf *vrf,
+ struct vty *vty, const char *src_or_group,
+ const char *group, bool uj)
+{
+ char src_str[PIM_ADDRSTRLEN];
+ char grp_str[PIM_ADDRSTRLEN];
+ struct pim_upstream *up;
+ struct pim_instance *pim = vrf->info;
+ json_object *json = NULL;
+
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "Source Group Owner Local-cost Peer-cost DF\n");
+
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
+ if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
+ && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
+ && !pim_up_mlag_is_local(up))
+ continue;
+
+ snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
+ snprintfrr(src_str, sizeof(src_str), "%pPAs", &up->sg.src);
+
+ /* XXX: strcmps are clearly inefficient. we should do uint comps
+ * here instead.
+ */
+ if (group) {
+ if (strcmp(src_str, src_or_group) ||
+ strcmp(grp_str, group))
+ continue;
+ } else {
+ if (strcmp(src_str, src_or_group) &&
+ strcmp(grp_str, src_or_group))
+ continue;
+ }
+ pim_show_mlag_up_entry_detail(vrf, vty, up,
+ src_str, grp_str, json);
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj)
+{
+ json_object *json = NULL;
+ json_object *json_row;
+ struct pim_upstream *up;
+ struct pim_instance *pim = vrf->info;
+ json_object *json_group = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty,
+ "Source Group Owner Local-cost Peer-cost DF\n");
+ }
+
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
+ if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
+ && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
+ && !pim_up_mlag_is_local(up))
+ continue;
+ if (uj) {
+ char src_str[PIM_ADDRSTRLEN];
+ char grp_str[PIM_ADDRSTRLEN];
+ json_object *own_list = NULL;
+
+ snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
+ &up->sg.grp);
+ snprintfrr(src_str, sizeof(src_str), "%pPAs",
+ &up->sg.src);
+
+ 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);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "vrf", vrf->name);
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+
+ own_list = json_object_new_array();
+ if (pim_up_mlag_is_local(up)) {
+
+ json_object_array_add(own_list,
+ json_object_new_string(
+ "local"));
+ }
+ if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) {
+ json_object_array_add(own_list,
+ json_object_new_string(
+ "peer"));
+ }
+ json_object_object_add(json_row, "owners", own_list);
+
+ json_object_int_add(json_row, "localCost",
+ pim_up_mlag_local_cost(up));
+ json_object_int_add(json_row, "peerCost",
+ pim_up_mlag_peer_cost(up));
+ if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
+ json_object_boolean_false_add(json_row, "df");
+ else
+ json_object_boolean_true_add(json_row, "df");
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ char own_str[6];
+
+ own_str[0] = '\0';
+ if (pim_up_mlag_is_local(up))
+ strlcat(own_str, "L", sizeof(own_str));
+ if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
+ strlcat(own_str, "P", sizeof(own_str));
+ if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
+ strlcat(own_str, "I", sizeof(own_str));
+ vty_out(vty,
+ "%-15pPAs %-15pPAs %-6s %-11u %-10u %2s\n",
+ &up->sg.src, &up->sg.grp, own_str,
+ pim_up_mlag_local_cost(up),
+ pim_up_mlag_peer_cost(up),
+ PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
+ ? "n" : "y");
+ }
+ }
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void pim_show_mlag_help_string(struct vty *vty, bool uj)
+{
+ if (!uj) {
+ vty_out(vty, "Owner codes:\n");
+ vty_out(vty,
+ "L: EVPN-MLAG Entry, I:PIM-MLAG Entry, P: Peer Entry\n");
+ }
+}
+
+
+DEFUN(show_ip_pim_mlag_up, show_ip_pim_mlag_up_cmd,
+ "show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "MLAG\n"
+ "upstream\n"
+ "Unicast or Multicast address\n"
+ "Multicast address\n" JSON_STR)
+{
+ const char *src_or_group = NULL;
+ const char *group = NULL;
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ bool uj = use_json(argc, argv);
+
+ if (!vrf || !vrf->info) {
+ vty_out(vty, "%s: VRF or Info missing\n", __func__);
+ return CMD_WARNING;
+ }
+
+ if (uj)
+ argc--;
+
+ if (argv_find(argv, argc, "A.B.C.D", &idx)) {
+ src_or_group = argv[idx]->arg;
+ if (idx + 1 < argc)
+ group = argv[idx + 1]->arg;
+ }
+
+ pim_show_mlag_help_string(vty, uj);
+
+ if (src_or_group)
+ pim_show_mlag_up_detail(vrf, vty, src_or_group, group, uj);
+ else
+ pim_show_mlag_up_vrf(vrf, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN(show_ip_pim_mlag_up_vrf_all, show_ip_pim_mlag_up_vrf_all_cmd,
+ "show ip pim vrf all mlag upstream [json]",
+ SHOW_STR IP_STR PIM_STR VRF_CMD_HELP_STR
+ "MLAG\n"
+ "upstream\n" JSON_STR)
+{
+ struct vrf *vrf;
+ bool uj = use_json(argc, argv);
+
+ pim_show_mlag_help_string(vty, uj);
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ pim_show_mlag_up_vrf(vrf, vty, uj);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_pim_neighbor,
+ show_ip_pim_neighbor_cmd,
+ "show ip pim [vrf NAME] neighbor [detail|WORD]$interface [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM neighbor information\n"
+ "Detailed output\n"
+ "Name of interface or neighbor\n"
+ JSON_STR)
+{
+ return pim_show_neighbors_cmd_helper(vrf, vty, json, interface);
+}
+
+DEFPY (show_ip_pim_neighbor_vrf_all,
+ show_ip_pim_neighbor_vrf_all_cmd,
+ "show ip pim vrf all neighbor [detail|WORD]$interface [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM neighbor information\n"
+ "Detailed output\n"
+ "Name of interface or neighbor\n"
+ JSON_STR)
+{
+ return pim_show_neighbors_vrf_all_cmd_helper(vty, json, interface);
+}
+
+DEFPY (show_ip_pim_secondary,
+ show_ip_pim_secondary_cmd,
+ "show ip pim [vrf NAME] secondary",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM neighbor addresses\n")
+{
+ return pim_show_secondary_helper(vrf, vty);
+}
+
+DEFPY (show_ip_pim_state,
+ show_ip_pim_state_cmd,
+ "show ip pim [vrf NAME] state [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM state information\n"
+ "Unicast or Multicast address\n"
+ "Multicast address\n"
+ JSON_STR)
+{
+ return pim_show_state_helper(vrf, vty, s_or_g_str, g_str, !!json);
+}
+
+DEFPY (show_ip_pim_state_vrf_all,
+ show_ip_pim_state_vrf_all_cmd,
+ "show ip pim vrf all state [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM state information\n"
+ "Unicast or Multicast address\n"
+ "Multicast address\n"
+ JSON_STR)
+{
+ return pim_show_state_vrf_all_helper(vty, s_or_g_str, g_str, !!json);
+}
+
+DEFPY (show_ip_pim_upstream,
+ show_ip_pim_upstream_cmd,
+ "show ip pim [vrf NAME] upstream [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM upstream information\n"
+ "The Source or Group\n"
+ "The Group\n"
+ JSON_STR)
+{
+ return pim_show_upstream_helper(vrf, vty, s_or_g, g, !!json);
+}
+
+DEFPY (show_ip_pim_upstream_vrf_all,
+ show_ip_pim_upstream_vrf_all_cmd,
+ "show ip pim vrf all upstream [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM upstream information\n"
+ JSON_STR)
+{
+ return pim_show_upstream_vrf_all_helper(vty, !!json);
+}
+
+DEFPY (show_ip_pim_channel,
+ show_ip_pim_channel_cmd,
+ "show ip pim [vrf NAME] channel [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM downstream channel info\n"
+ JSON_STR)
+{
+ return pim_show_channel_cmd_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_pim_upstream_join_desired,
+ show_ip_pim_upstream_join_desired_cmd,
+ "show ip pim [vrf NAME] upstream-join-desired [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM upstream join-desired\n"
+ JSON_STR)
+{
+ return pim_show_upstream_join_desired_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_pim_upstream_rpf,
+ show_ip_pim_upstream_rpf_cmd,
+ "show ip pim [vrf NAME] upstream-rpf [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM upstream source rpf\n"
+ JSON_STR)
+{
+ return pim_show_upstream_rpf_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_pim_rp,
+ show_ip_pim_rp_cmd,
+ "show ip pim [vrf NAME] rp-info [A.B.C.D/M$group] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM RP information\n"
+ "Multicast Group range\n"
+ JSON_STR)
+{
+ return pim_show_rp_helper(vrf, vty, group_str, (struct prefix *)group,
+ !!json);
+}
+
+DEFPY (show_ip_pim_rp_vrf_all,
+ show_ip_pim_rp_vrf_all_cmd,
+ "show ip pim vrf all rp-info [A.B.C.D/M$group] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM RP information\n"
+ "Multicast Group range\n"
+ JSON_STR)
+{
+ return pim_show_rp_vrf_all_helper(vty, group_str,
+ (struct prefix *)group, !!json);
+}
+
+DEFPY (show_ip_pim_rpf,
+ show_ip_pim_rpf_cmd,
+ "show ip pim [vrf NAME] rpf [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM cached source rpf information\n"
+ JSON_STR)
+{
+ return pim_show_rpf_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_pim_rpf_vrf_all,
+ show_ip_pim_rpf_vrf_all_cmd,
+ "show ip pim vrf all rpf [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM cached source rpf information\n"
+ JSON_STR)
+{
+ return pim_show_rpf_vrf_all_helper(vty, !!json);
+}
+
+DEFPY (show_ip_pim_nexthop,
+ show_ip_pim_nexthop_cmd,
+ "show ip pim [vrf NAME] nexthop [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM cached nexthop rpf information\n"
+ JSON_STR)
+{
+ return pim_show_nexthop_cmd_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_pim_nexthop_lookup,
+ show_ip_pim_nexthop_lookup_cmd,
+ "show ip pim [vrf NAME] nexthop-lookup A.B.C.D$source A.B.C.D$group",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM cached nexthop rpf lookup\n"
+ "Source/RP address\n"
+ "Multicast Group address\n")
+{
+ return pim_show_nexthop_lookup_cmd_helper(vrf, vty, source, group);
+}
+
+DEFPY (show_ip_pim_interface_traffic,
+ show_ip_pim_interface_traffic_cmd,
+ "show ip pim [vrf NAME] interface traffic [WORD$if_name] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM interface information\n"
+ "Protocol Packet counters\n"
+ "Interface name\n"
+ JSON_STR)
+{
+ return pim_show_interface_traffic_helper(vrf, if_name, vty, !!json);
+}
+
+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
+ "PIM cached bsm packets information\n"
+ VRF_CMD_HELP_STR
+ 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
+ "PIM cached group-rp mappings information\n"
+ VRF_CMD_HELP_STR
+ 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;
+}
+
+DEFPY (show_ip_pim_statistics,
+ show_ip_pim_statistics_cmd,
+ "show ip pim [vrf NAME] statistics [interface WORD$word] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM statistics\n"
+ INTERFACE_STR
+ "PIM interface\n"
+ JSON_STR)
+{
+ return pim_show_statistics_helper(vrf, vty, word, !!json);
+}
+
+DEFPY (show_ip_multicast,
+ show_ip_multicast_cmd,
+ "show ip multicast [vrf NAME]",
+ SHOW_STR
+ IP_STR
+ "Multicast global information\n"
+ VRF_CMD_HELP_STR)
+{
+ return pim_show_multicast_helper(vrf, vty);
+}
+
+DEFPY (show_ip_multicast_vrf_all,
+ show_ip_multicast_vrf_all_cmd,
+ "show ip multicast vrf all",
+ SHOW_STR
+ IP_STR
+ "Multicast global information\n"
+ VRF_CMD_HELP_STR)
+{
+ return pim_show_multicast_vrf_all_helper(vty);
+}
+
+DEFPY (show_ip_multicast_count,
+ show_ip_multicast_count_cmd,
+ "show ip multicast count [vrf NAME] [json$json]",
+ SHOW_STR
+ IP_STR
+ "Multicast global information\n"
+ "Data packet count\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ return pim_show_multicast_count_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_multicast_count_vrf_all,
+ show_ip_multicast_count_vrf_all_cmd,
+ "show ip multicast count vrf all [json$json]",
+ SHOW_STR
+ IP_STR
+ "Multicast global information\n"
+ "Data packet count\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ return pim_show_multicast_count_vrf_all_helper(vty, !!json);
+}
+
+DEFPY (show_ip_mroute,
+ show_ip_mroute_cmd,
+ "show ip mroute [vrf NAME] [A.B.C.D$s_or_g [A.B.C.D$g]] [fill$fill] [json$json]",
+ SHOW_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "The Source or Group\n"
+ "The Group\n"
+ "Fill in Assumed data\n"
+ JSON_STR)
+{
+ return pim_show_mroute_helper(vrf, vty, s_or_g, g, !!fill, !!json);
+}
+
+DEFPY (show_ip_mroute_vrf_all,
+ show_ip_mroute_vrf_all_cmd,
+ "show ip mroute vrf all [fill$fill] [json$json]",
+ SHOW_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "Fill in Assumed data\n"
+ JSON_STR)
+{
+ return pim_show_mroute_vrf_all_helper(vty, !!fill, !!json);
+}
+
+DEFPY (clear_ip_mroute_count,
+ clear_ip_mroute_count_cmd,
+ "clear ip mroute [vrf NAME]$name count",
+ CLEAR_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "Route and packet count data\n")
+{
+ return clear_ip_mroute_count_command(vty, name);
+}
+
+DEFPY (show_ip_mroute_count,
+ show_ip_mroute_count_cmd,
+ "show ip mroute [vrf NAME] count [json$json]",
+ SHOW_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "Route and packet count data\n"
+ JSON_STR)
+{
+ return pim_show_mroute_count_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_mroute_count_vrf_all,
+ show_ip_mroute_count_vrf_all_cmd,
+ "show ip mroute vrf all count [json$json]",
+ SHOW_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "Route and packet count data\n"
+ JSON_STR)
+{
+ return pim_show_mroute_count_vrf_all_helper(vty, !!json);
+}
+
+DEFPY (show_ip_mroute_summary,
+ show_ip_mroute_summary_cmd,
+ "show ip mroute [vrf NAME] summary [json$json]",
+ SHOW_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "Summary of all mroutes\n"
+ JSON_STR)
+{
+ return pim_show_mroute_summary_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_mroute_summary_vrf_all,
+ show_ip_mroute_summary_vrf_all_cmd,
+ "show ip mroute vrf all summary [json$json]",
+ SHOW_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "Summary of all mroutes\n"
+ JSON_STR)
+{
+ return pim_show_mroute_summary_vrf_all_helper(vty, !!json);
+}
+
+DEFUN (show_ip_rib,
+ show_ip_rib_cmd,
+ "show ip rib [vrf NAME] A.B.C.D",
+ SHOW_STR
+ IP_STR
+ RIB_STR
+ VRF_CMD_HELP_STR
+ "Unicast address\n")
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ struct in_addr addr;
+ const char *addr_str;
+ struct pim_nexthop nexthop;
+ int result;
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ memset(&nexthop, 0, sizeof(nexthop));
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ addr_str = argv[idx]->arg;
+ result = inet_pton(AF_INET, addr_str, &addr);
+ if (result <= 0) {
+ vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str,
+ errno, safe_strerror(errno));
+ return CMD_WARNING;
+ }
+
+ if (!pim_nexthop_lookup(vrf->info, &nexthop, addr, 0)) {
+ vty_out(vty,
+ "Failure querying RIB nexthop for unicast address %s\n",
+ addr_str);
+ return CMD_WARNING;
+ }
+
+ vty_out(vty,
+ "Address NextHop Interface Metric Preference\n");
+
+ vty_out(vty, "%-15s %-15pPAs %-9s %6d %10d\n", addr_str,
+ &nexthop.mrib_nexthop_addr,
+ nexthop.interface ? nexthop.interface->name : "<ifname?>",
+ nexthop.mrib_route_metric, nexthop.mrib_metric_preference);
+
+ return CMD_SUCCESS;
+}
+
+static void show_ssmpingd(struct pim_instance *pim, struct vty *vty)
+{
+ struct listnode *node;
+ struct ssmpingd_sock *ss;
+ time_t now;
+
+ vty_out(vty,
+ "Source Socket Address Port Uptime Requests\n");
+
+ if (!pim->ssmpingd_list)
+ return;
+
+ now = pim_time_monotonic_sec();
+
+ for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) {
+ char source_str[INET_ADDRSTRLEN];
+ char ss_uptime[10];
+ struct sockaddr_in bind_addr;
+ socklen_t len = sizeof(bind_addr);
+ char bind_addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<src?>", ss->source_addr, source_str,
+ sizeof(source_str));
+
+ if (pim_socket_getsockname(
+ ss->sock_fd, (struct sockaddr *)&bind_addr, &len)) {
+ vty_out(vty,
+ "%% Failure reading socket name for ssmpingd source %s on fd=%d\n",
+ source_str, ss->sock_fd);
+ }
+
+ pim_inet4_dump("<addr?>", bind_addr.sin_addr, bind_addr_str,
+ sizeof(bind_addr_str));
+ pim_time_uptime(ss_uptime, sizeof(ss_uptime),
+ now - ss->creation);
+
+ vty_out(vty, "%-15s %6d %-15s %5d %8s %8lld\n", source_str,
+ ss->sock_fd, bind_addr_str, ntohs(bind_addr.sin_port),
+ ss_uptime, (long long)ss->requests);
+ }
+}
+
+DEFUN (show_ip_ssmpingd,
+ show_ip_ssmpingd_cmd,
+ "show ip ssmpingd [vrf NAME]",
+ SHOW_STR
+ IP_STR
+ SHOW_SSMPINGD_STR
+ VRF_CMD_HELP_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ show_ssmpingd(vrf->info, vty);
+ 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_process_spt_switchover_infinity_cmd(vty);
+}
+
+DEFPY (ip_pim_spt_switchover_infinity_plist,
+ ip_pim_spt_switchover_infinity_plist_cmd,
+ "ip pim spt-switchover infinity-and-beyond prefix-list WORD$plist",
+ 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_process_spt_switchover_prefixlist_cmd(vty, plist);
+}
+
+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_process_no_spt_switchover_cmd(vty);
+}
+
+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_process_no_spt_switchover_cmd(vty);
+}
+
+DEFPY (pim_register_accept_list,
+ pim_register_accept_list_cmd,
+ "[no] ip pim register-accept-list WORD$word",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Only accept registers from a specific source prefix list\n"
+ "Prefix-List name\n")
+{
+ const char *vrfname;
+ char reg_alist_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(reg_alist_xpath, sizeof(reg_alist_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ "frr-routing:ipv4");
+ strlcat(reg_alist_xpath, "/register-accept-list",
+ sizeof(reg_alist_xpath));
+
+ if (no)
+ nb_cli_enqueue_change(vty, reg_alist_xpath,
+ NB_OP_DESTROY, NULL);
+ else
+ nb_cli_enqueue_change(vty, reg_alist_xpath,
+ NB_OP_MODIFY, word);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY (ip_pim_joinprune_time,
+ ip_pim_joinprune_time_cmd,
+ "ip pim join-prune-interval (1-65535)$jpi",
+ IP_STR
+ "pim multicast routing\n"
+ "Join Prune Send Interval\n"
+ "Seconds\n")
+{
+ return pim_process_join_prune_cmd(vty, jpi_str);
+}
+
+DEFUN (no_ip_pim_joinprune_time,
+ no_ip_pim_joinprune_time_cmd,
+ "no ip pim join-prune-interval [(1-65535)]",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Join Prune Send Interval\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_join_prune_cmd(vty);
+}
+
+DEFPY (ip_pim_register_suppress,
+ ip_pim_register_suppress_cmd,
+ "ip pim register-suppress-time (1-65535)$rst",
+ IP_STR
+ "pim multicast routing\n"
+ "Register Suppress Timer\n"
+ "Seconds\n")
+{
+ return pim_process_register_suppress_cmd(vty, rst_str);
+}
+
+DEFUN (no_ip_pim_register_suppress,
+ no_ip_pim_register_suppress_cmd,
+ "no ip pim register-suppress-time [(1-65535)]",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Register Suppress Timer\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_register_suppress_cmd(vty);
+}
+
+DEFPY (ip_pim_rp_keep_alive,
+ ip_pim_rp_keep_alive_cmd,
+ "ip pim rp keep-alive-timer (1-65535)$kat",
+ IP_STR
+ "pim multicast routing\n"
+ "Rendezvous Point\n"
+ "Keep alive Timer\n"
+ "Seconds\n")
+{
+ return pim_process_rp_kat_cmd(vty, kat_str);
+}
+
+DEFUN (no_ip_pim_rp_keep_alive,
+ no_ip_pim_rp_keep_alive_cmd,
+ "no ip pim rp keep-alive-timer [(1-65535)]",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Rendezvous Point\n"
+ "Keep alive Timer\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_rp_kat_cmd(vty);
+}
+
+DEFPY (ip_pim_keep_alive,
+ ip_pim_keep_alive_cmd,
+ "ip pim keep-alive-timer (1-65535)$kat",
+ IP_STR
+ "pim multicast routing\n"
+ "Keep alive Timer\n"
+ "Seconds\n")
+{
+ return pim_process_keepalivetimer_cmd(vty, kat_str);
+}
+
+DEFUN (no_ip_pim_keep_alive,
+ no_ip_pim_keep_alive_cmd,
+ "no ip pim keep-alive-timer [(1-65535)]",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Keep alive Timer\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_keepalivetimer_cmd(vty);
+}
+
+DEFPY (ip_pim_packets,
+ ip_pim_packets_cmd,
+ "ip pim packets (1-255)",
+ IP_STR
+ "pim multicast routing\n"
+ "packets to process at one time per fd\n"
+ "Number of packets\n")
+{
+ return pim_process_pim_packet_cmd(vty, packets_str);
+}
+
+DEFUN (no_ip_pim_packets,
+ no_ip_pim_packets_cmd,
+ "no ip pim packets [(1-255)]",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "packets to process at one time per fd\n"
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_pim_packet_cmd(vty);
+}
+
+DEFPY (ip_igmp_group_watermark,
+ ip_igmp_group_watermark_cmd,
+ "ip igmp watermark-warn (1-65535)$limit",
+ IP_STR
+ IGMP_STR
+ "Configure group limit for watermark warning\n"
+ "Group count to generate watermark warning\n")
+{
+ PIM_DECLVAR_CONTEXT_VRF(vrf, pim);
+ pim->gm_watermark_limit = limit;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_ip_igmp_group_watermark,
+ no_ip_igmp_group_watermark_cmd,
+ "no ip igmp watermark-warn [(1-65535)$limit]",
+ NO_STR
+ IP_STR
+ IGMP_STR
+ "Unconfigure group limit for watermark warning\n"
+ IGNORED_IN_NO_STR)
+{
+ PIM_DECLVAR_CONTEXT_VRF(vrf, pim);
+ pim->gm_watermark_limit = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_v6_secondary,
+ ip_pim_v6_secondary_cmd,
+ "ip pim send-v6-secondary",
+ IP_STR
+ "pim multicast routing\n"
+ "Send v6 secondary addresses\n")
+{
+ const char *vrfname;
+ char send_v6_secondary_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(send_v6_secondary_xpath, "/send-v6-secondary",
+ sizeof(send_v6_secondary_xpath));
+
+ nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY,
+ "true");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN (no_ip_pim_v6_secondary,
+ no_ip_pim_v6_secondary_cmd,
+ "no ip pim send-v6-secondary",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Send v6 secondary addresses\n")
+{
+ const char *vrfname;
+ char send_v6_secondary_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(send_v6_secondary_xpath, "/send-v6-secondary",
+ sizeof(send_v6_secondary_xpath));
+
+ nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY,
+ "false");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY (ip_pim_rp,
+ ip_pim_rp_cmd,
+ "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp",
+ IP_STR
+ "pim multicast routing\n"
+ "Rendezvous Point\n"
+ "ip address of RP\n"
+ "Group Address range to cover\n")
+{
+ const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4";
+
+ return pim_process_rp_cmd(vty, rp_str, group_str);
+}
+
+DEFPY (ip_pim_rp_prefix_list,
+ ip_pim_rp_prefix_list_cmd,
+ "ip pim rp A.B.C.D$rp prefix-list WORD$plist",
+ IP_STR
+ "pim multicast routing\n"
+ "Rendezvous Point\n"
+ "ip address of RP\n"
+ "group prefix-list filter\n"
+ "Name of a prefix-list\n")
+{
+ return pim_process_rp_plist_cmd(vty, rp_str, plist);
+}
+
+DEFPY (no_ip_pim_rp,
+ no_ip_pim_rp_cmd,
+ "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Rendezvous Point\n"
+ "ip address of RP\n"
+ "Group Address range to cover\n")
+{
+ const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4";
+
+ return pim_process_no_rp_cmd(vty, rp_str, group_str);
+}
+
+DEFPY (no_ip_pim_rp_prefix_list,
+ no_ip_pim_rp_prefix_list_cmd,
+ "no ip pim rp A.B.C.D$rp prefix-list WORD$plist",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Rendezvous Point\n"
+ "ip address of RP\n"
+ "group prefix-list filter\n"
+ "Name of a prefix-list\n")
+{
+ return pim_process_no_rp_plist_cmd(vty, rp_str, plist);
+}
+
+DEFUN (ip_pim_ssm_prefix_list,
+ ip_pim_ssm_prefix_list_cmd,
+ "ip pim ssm prefix-list WORD",
+ IP_STR
+ "pim multicast routing\n"
+ "Source Specific Multicast\n"
+ "group range prefix-list filter\n"
+ "Name of a prefix-list\n")
+{
+ const char *vrfname;
+ char ssm_plist_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
+
+ nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN (no_ip_pim_ssm_prefix_list,
+ no_ip_pim_ssm_prefix_list_cmd,
+ "no ip pim ssm prefix-list",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Source Specific Multicast\n"
+ "group range prefix-list filter\n")
+{
+ const char *vrfname;
+ char ssm_plist_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
+
+ nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN (no_ip_pim_ssm_prefix_list_name,
+ no_ip_pim_ssm_prefix_list_name_cmd,
+ "no ip pim ssm prefix-list WORD",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Source Specific Multicast\n"
+ "group range prefix-list filter\n"
+ "Name of a prefix-list\n")
+{
+ const char *vrfname;
+ const struct lyd_node *ssm_plist_dnode;
+ char ssm_plist_xpath[XPATH_MAXLEN];
+ const char *ssm_plist_name;
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
+ ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ ssm_plist_xpath);
+
+ if (!ssm_plist_dnode) {
+ vty_out(vty,
+ "%% pim ssm prefix-list %s doesn't exist\n",
+ argv[5]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, ".");
+
+ if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) {
+ nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY,
+ NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+ }
+
+ vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg);
+
+ return CMD_WARNING_CONFIG_FAILED;
+}
+
+DEFUN (show_ip_pim_ssm_range,
+ show_ip_pim_ssm_range_cmd,
+ "show ip pim [vrf NAME] group-type [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM group type\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;
+
+ ip_pim_ssm_show_group_range(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+static void ip_pim_ssm_show_group_type(struct pim_instance *pim,
+ struct vty *vty, bool uj,
+ const char *group)
+{
+ struct in_addr group_addr;
+ const char *type_str;
+ int result;
+
+ result = inet_pton(AF_INET, group, &group_addr);
+ if (result <= 0)
+ type_str = "invalid";
+ else {
+ if (pim_is_group_224_4(group_addr))
+ type_str =
+ pim_is_grp_ssm(pim, group_addr) ? "SSM" : "ASM";
+ else
+ type_str = "not-multicast";
+ }
+
+ if (uj) {
+ json_object *json;
+ json = json_object_new_object();
+ json_object_string_add(json, "groupType", type_str);
+ vty_json(vty, json);
+ } else
+ vty_out(vty, "Group type : %s\n", type_str);
+}
+
+DEFUN (show_ip_pim_group_type,
+ show_ip_pim_group_type_cmd,
+ "show ip pim [vrf NAME] group-type A.B.C.D [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "multicast group type\n"
+ "group address\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;
+
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ ip_pim_ssm_show_group_type(vrf->info, vty, uj, argv[idx]->arg);
+
+ 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]",
+ IP_STR
+ CONF_SSMPINGD_STR
+ "Source address\n")
+{
+ int idx_ipv4 = 2;
+ const char *src_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0";
+
+ return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str);
+}
+
+DEFUN (no_ip_ssmpingd,
+ no_ip_ssmpingd_cmd,
+ "no ip ssmpingd [A.B.C.D]",
+ NO_STR
+ IP_STR
+ CONF_SSMPINGD_STR
+ "Source address\n")
+{
+ int idx_ipv4 = 3;
+ const char *src_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0";
+
+ return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str);
+}
+
+DEFUN (ip_pim_ecmp,
+ ip_pim_ecmp_cmd,
+ "ip pim ecmp",
+ IP_STR
+ "pim multicast routing\n"
+ "Enable PIM ECMP \n")
+{
+ const char *vrfname;
+ char ecmp_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
+
+ nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true");
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+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")
+{
+ const char *vrfname;
+ char ecmp_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
+
+ nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+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")
+{
+ const char *vrfname;
+ char ecmp_xpath[XPATH_MAXLEN];
+ char ecmp_rebalance_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
+ snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance",
+ sizeof(ecmp_rebalance_xpath));
+
+ nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true");
+ nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+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")
+{
+ const char *vrfname;
+ char ecmp_rebalance_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance",
+ sizeof(ecmp_rebalance_xpath));
+
+ nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN (interface_ip_igmp,
+ interface_ip_igmp_cmd,
+ "ip igmp",
+ IP_STR
+ IFACE_IGMP_STR)
+{
+ nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (interface_no_ip_igmp,
+ interface_no_ip_igmp_cmd,
+ "no ip igmp",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR)
+{
+ const struct lyd_node *pim_enable_dnode;
+ char pim_if_xpath[XPATH_MAXLEN];
+
+ int printed =
+ snprintf(pim_if_xpath, sizeof(pim_if_xpath),
+ "%s/frr-pim:pim/address-family[address-family='%s']",
+ VTY_CURR_XPATH, "frr-routing:ipv4");
+
+ if (printed >= (int)(sizeof(pim_if_xpath))) {
+ vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
+ XPATH_MAXLEN);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
+ "frr-routing:ipv4");
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, ".")) {
+ nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY,
+ NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+ } else
+ nb_cli_enqueue_change(vty, "./enable",
+ NB_OP_MODIFY, "false");
+ }
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (interface_ip_igmp_join,
+ interface_ip_igmp_join_cmd,
+ "ip igmp join A.B.C.D [A.B.C.D]",
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ int idx_group = 3;
+ int idx_source = 4;
+ const char *source_str;
+ char xpath[XPATH_MAXLEN];
+
+ if (argc == 5) {
+ source_str = argv[idx_source]->arg;
+
+ if (strcmp(source_str, "0.0.0.0") == 0) {
+ vty_out(vty, "Bad source address %s\n",
+ argv[idx_source]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ } else
+ source_str = "0.0.0.0";
+
+ snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
+ "frr-routing:ipv4", argv[idx_group]->arg, source_str);
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN (interface_no_ip_igmp_join,
+ interface_no_ip_igmp_join_cmd,
+ "no ip igmp join A.B.C.D [A.B.C.D]",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ int idx_group = 4;
+ int idx_source = 5;
+ const char *source_str;
+ char xpath[XPATH_MAXLEN];
+
+ if (argc == 6) {
+ source_str = argv[idx_source]->arg;
+
+ if (strcmp(source_str, "0.0.0.0") == 0) {
+ vty_out(vty, "Bad source address %s\n",
+ argv[idx_source]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ } else
+ source_str = "0.0.0.0";
+
+ snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
+ "frr-routing:ipv4", argv[idx_group]->arg, source_str);
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN (interface_ip_igmp_query_interval,
+ interface_ip_igmp_query_interval_cmd,
+ "ip igmp query-interval (1-65535)",
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_INTERVAL_STR
+ "Query interval in seconds\n")
+{
+ const struct lyd_node *pim_enable_dnode;
+
+ pim_enable_dnode =
+ yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
+ "frr-routing:ipv4");
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
+ "true");
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./enable",
+ NB_OP_MODIFY, "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
+ argv[3]->arg);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (interface_no_ip_igmp_query_interval,
+ interface_no_ip_igmp_query_interval_cmd,
+ "no ip igmp query-interval [(1-65535)]",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_INTERVAL_STR
+ IGNORED_IN_NO_STR)
+{
+ nb_cli_enqueue_change(vty, "./query-interval", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (interface_ip_igmp_version,
+ interface_ip_igmp_version_cmd,
+ "ip igmp version (2-3)",
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP version\n"
+ "IGMP version number\n")
+{
+ nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
+ "true");
+ nb_cli_enqueue_change(vty, "./igmp-version", NB_OP_MODIFY,
+ argv[3]->arg);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (interface_no_ip_igmp_version,
+ interface_no_ip_igmp_version_cmd,
+ "no ip igmp version (2-3)",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP version\n"
+ "IGMP version number\n")
+{
+ nb_cli_enqueue_change(vty, "./igmp-version", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFPY (interface_ip_igmp_query_max_response_time,
+ interface_ip_igmp_query_max_response_time_cmd,
+ "ip igmp query-max-response-time (1-65535)$qmrt",
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
+ "Query response value in deci-seconds\n")
+{
+ return gm_process_query_max_response_time_cmd(vty, qmrt_str);
+}
+
+DEFUN (interface_no_ip_igmp_query_max_response_time,
+ interface_no_ip_igmp_query_max_response_time_cmd,
+ "no ip igmp query-max-response-time [(1-65535)]",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
+ IGNORED_IN_NO_STR)
+{
+ return gm_process_no_query_max_response_time_cmd(vty);
+}
+
+DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
+ interface_ip_igmp_query_max_response_time_dsec_cmd,
+ "ip igmp query-max-response-time-dsec (1-65535)",
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR
+ "Query response value in deciseconds\n")
+{
+ const struct lyd_node *pim_enable_dnode;
+
+ pim_enable_dnode =
+ yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
+ "frr-routing:ipv4");
+ if (!pim_enable_dnode) {
+ nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
+ "true");
+ } else {
+ if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./enable",
+ NB_OP_MODIFY, "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+ argv[3]->arg);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
+ interface_no_ip_igmp_query_max_response_time_dsec_cmd,
+ "no ip igmp query-max-response-time-dsec [(1-65535)]",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR
+ IGNORED_IN_NO_STR)
+{
+ nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY,
+ NULL);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFPY (interface_ip_igmp_last_member_query_count,
+ interface_ip_igmp_last_member_query_count_cmd,
+ "ip igmp last-member-query-count (1-255)$lmqc",
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR
+ "Last member query count\n")
+{
+ return gm_process_last_member_query_count_cmd(vty, lmqc_str);
+}
+
+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 [(1-255)]",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR
+ IGNORED_IN_NO_STR)
+{
+ return gm_process_no_last_member_query_count_cmd(vty);
+}
+
+DEFPY (interface_ip_igmp_last_member_query_interval,
+ interface_ip_igmp_last_member_query_interval_cmd,
+ "ip igmp last-member-query-interval (1-65535)$lmqi",
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR
+ "Last member query interval in deciseconds\n")
+{
+ return gm_process_last_member_query_interval_cmd(vty, lmqi_str);
+}
+
+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 [(1-65535)]",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR
+ IGNORED_IN_NO_STR)
+{
+ return gm_process_no_last_member_query_interval_cmd(vty);
+}
+
+DEFUN (interface_ip_pim_drprio,
+ interface_ip_pim_drprio_cmd,
+ "ip pim drpriority (1-4294967295)",
+ IP_STR
+ PIM_STR
+ "Set the Designated Router Election Priority\n"
+ "Value of the new DR Priority\n")
+{
+ int idx_number = 3;
+
+ return pim_process_ip_pim_drprio_cmd(vty, argv[idx_number]->arg);
+}
+
+DEFUN (interface_no_ip_pim_drprio,
+ interface_no_ip_pim_drprio_cmd,
+ "no ip pim drpriority [(1-4294967295)]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Revert the Designated Router Priority to default\n"
+ "Old Value of the Priority\n")
+{
+ return pim_process_no_ip_pim_drprio_cmd(vty);
+}
+
+DEFPY_HIDDEN (interface_ip_igmp_query_generate,
+ interface_ip_igmp_query_generate_cmd,
+ "ip igmp generate-query-once [version (2-3)]",
+ IP_STR
+ IFACE_IGMP_STR
+ "Generate igmp general query once\n"
+ "IGMP version\n"
+ "IGMP version number\n")
+{
+#if PIM_IPV == 4
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ int igmp_version;
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (!ifp->info) {
+ vty_out(vty, "IGMP/PIM is not enabled on the interface %s\n",
+ ifp->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* It takes the igmp version configured on the interface as default */
+ igmp_version = pim_ifp->igmp_version;
+
+ if (argc > 3)
+ igmp_version = atoi(argv[4]->arg);
+
+ igmp_send_query_on_intf(ifp, igmp_version);
+#endif
+ return CMD_SUCCESS;
+}
+
+DEFPY_HIDDEN (pim_test_sg_keepalive,
+ pim_test_sg_keepalive_cmd,
+ "test pim [vrf NAME$name] keepalive-reset A.B.C.D$source A.B.C.D$group",
+ "Test code\n"
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "Reset the Keepalive Timer\n"
+ "The Source we are resetting\n"
+ "The Group we are resetting\n")
+{
+ struct pim_upstream *up;
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ pim_sgaddr sg;
+
+ sg.src = source;
+ sg.grp = group;
+
+ vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME);
+ if (!vrf) {
+ vty_out(vty, "%% Vrf specified: %s does not exist\n", name);
+ return CMD_WARNING;
+ }
+
+ pim = vrf->info;
+
+ if (!pim) {
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ up = pim_upstream_find(pim, &sg);
+ if (!up) {
+ vty_out(vty, "%% Unable to find %pSG specified\n", &sg);
+ return CMD_WARNING;
+ }
+
+ vty_out(vty, "Setting %pSG to current keep alive time: %d\n", &sg,
+ pim->keep_alive_time);
+ pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (interface_ip_pim_activeactive,
+ interface_ip_pim_activeactive_cmd,
+ "[no$no] ip pim active-active",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n")
+{
+ return pim_process_ip_pim_activeactive_cmd(vty, no);
+}
+
+DEFUN_HIDDEN (interface_ip_pim_ssm,
+ interface_ip_pim_ssm_cmd,
+ "ip pim ssm",
+ IP_STR
+ PIM_STR
+ IFACE_PIM_STR)
+{
+ int ret;
+
+ ret = pim_process_ip_pim_cmd(vty);
+
+ if (ret != NB_OK)
+ return ret;
+
+ vty_out(vty,
+ "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n");
+
+ return NB_OK;
+}
+
+DEFUN_HIDDEN (interface_ip_pim_sm,
+ interface_ip_pim_sm_cmd,
+ "ip pim sm",
+ IP_STR
+ PIM_STR
+ IFACE_PIM_SM_STR)
+{
+ return pim_process_ip_pim_cmd(vty);
+}
+
+DEFPY (interface_ip_pim,
+ interface_ip_pim_cmd,
+ "ip pim [passive$passive]",
+ IP_STR
+ PIM_STR
+ "Disable exchange of protocol packets\n")
+{
+ int ret;
+
+ ret = pim_process_ip_pim_cmd(vty);
+
+ if (ret != NB_OK)
+ return ret;
+
+ if (passive)
+ return pim_process_ip_pim_passive_cmd(vty, true);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (interface_no_ip_pim_ssm,
+ interface_no_ip_pim_ssm_cmd,
+ "no ip pim ssm",
+ NO_STR
+ IP_STR
+ PIM_STR
+ IFACE_PIM_STR)
+{
+ return pim_process_no_ip_pim_cmd(vty);
+}
+
+DEFUN_HIDDEN (interface_no_ip_pim_sm,
+ interface_no_ip_pim_sm_cmd,
+ "no ip pim sm",
+ NO_STR
+ IP_STR
+ PIM_STR
+ IFACE_PIM_SM_STR)
+{
+ return pim_process_no_ip_pim_cmd(vty);
+}
+
+DEFPY (interface_no_ip_pim,
+ interface_no_ip_pim_cmd,
+ "no ip pim [passive$passive]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Disable exchange of protocol packets\n")
+{
+ if (passive)
+ return pim_process_ip_pim_passive_cmd(vty, false);
+
+ return pim_process_no_ip_pim_cmd(vty);
+}
+
+/* boundaries */
+DEFUN(interface_ip_pim_boundary_oil,
+ interface_ip_pim_boundary_oil_cmd,
+ "ip multicast boundary oil WORD",
+ IP_STR
+ "Generic multicast configuration options\n"
+ "Define multicast boundary\n"
+ "Filter OIL by group using prefix list\n"
+ "Prefix list to filter OIL with\n")
+{
+ return pim_process_ip_pim_boundary_oil_cmd(vty, argv[4]->arg);
+}
+
+DEFUN(interface_no_ip_pim_boundary_oil,
+ interface_no_ip_pim_boundary_oil_cmd,
+ "no ip multicast boundary oil [WORD]",
+ NO_STR
+ IP_STR
+ "Generic multicast configuration options\n"
+ "Define multicast boundary\n"
+ "Filter OIL by group using prefix list\n"
+ "Prefix list to filter OIL with\n")
+{
+ return pim_process_no_ip_pim_boundary_oil_cmd(vty);
+}
+
+DEFUN (interface_ip_mroute,
+ interface_ip_mroute_cmd,
+ "ip mroute INTERFACE A.B.C.D [A.B.C.D]",
+ IP_STR
+ "Add multicast route\n"
+ "Outgoing interface name\n"
+ "Group address\n"
+ "Source address\n")
+{
+ int idx_interface = 2;
+ int idx_ipv4 = 3;
+ const char *source_str;
+
+ if (argc == (idx_ipv4 + 1))
+ source_str = "0.0.0.0";
+ else
+ source_str = argv[idx_ipv4 + 1]->arg;
+
+ return pim_process_ip_mroute_cmd(vty, argv[idx_interface]->arg,
+ argv[idx_ipv4]->arg, source_str);
+}
+
+DEFUN (interface_no_ip_mroute,
+ interface_no_ip_mroute_cmd,
+ "no ip mroute INTERFACE A.B.C.D [A.B.C.D]",
+ NO_STR
+ IP_STR
+ "Add multicast route\n"
+ "Outgoing interface name\n"
+ "Group Address\n"
+ "Source Address\n")
+{
+ int idx_interface = 3;
+ int idx_ipv4 = 4;
+ const char *source_str;
+
+ if (argc == (idx_ipv4 + 1))
+ source_str = "0.0.0.0";
+ else
+ source_str = argv[idx_ipv4 + 1]->arg;
+
+ return pim_process_no_ip_mroute_cmd(vty, argv[idx_interface]->arg,
+ argv[idx_ipv4]->arg, source_str);
+}
+
+DEFUN (interface_ip_pim_hello,
+ interface_ip_pim_hello_cmd,
+ "ip pim hello (1-65535) [(1-65535)]",
+ IP_STR
+ PIM_STR
+ IFACE_PIM_HELLO_STR
+ IFACE_PIM_HELLO_TIME_STR
+ IFACE_PIM_HELLO_HOLD_STR)
+{
+ int idx_time = 3;
+ int idx_hold = 4;
+
+ if (argc == idx_hold + 1)
+ return pim_process_ip_pim_hello_cmd(vty, argv[idx_time]->arg,
+ argv[idx_hold]->arg);
+
+ else
+ return pim_process_ip_pim_hello_cmd(vty, argv[idx_time]->arg,
+ NULL);
+}
+
+DEFUN (interface_no_ip_pim_hello,
+ interface_no_ip_pim_hello_cmd,
+ "no ip pim hello [(1-65535) [(1-65535)]]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ IFACE_PIM_HELLO_STR
+ IGNORED_IN_NO_STR
+ IGNORED_IN_NO_STR)
+{
+ return pim_process_no_ip_pim_hello_cmd(vty);
+}
+
+DEFUN (debug_igmp,
+ debug_igmp_cmd,
+ "debug igmp",
+ DEBUG_STR
+ DEBUG_IGMP_STR)
+{
+ PIM_DO_DEBUG_GM_EVENTS;
+ PIM_DO_DEBUG_GM_PACKETS;
+ PIM_DO_DEBUG_GM_TRACE;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_igmp,
+ no_debug_igmp_cmd,
+ "no debug igmp",
+ NO_STR
+ DEBUG_STR
+ DEBUG_IGMP_STR)
+{
+ PIM_DONT_DEBUG_GM_EVENTS;
+ PIM_DONT_DEBUG_GM_PACKETS;
+ PIM_DONT_DEBUG_GM_TRACE;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_igmp_events,
+ debug_igmp_events_cmd,
+ "debug igmp events",
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_EVENTS_STR)
+{
+ PIM_DO_DEBUG_GM_EVENTS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_igmp_events,
+ no_debug_igmp_events_cmd,
+ "no debug igmp events",
+ NO_STR
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_EVENTS_STR)
+{
+ PIM_DONT_DEBUG_GM_EVENTS;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_igmp_packets,
+ debug_igmp_packets_cmd,
+ "debug igmp packets",
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_PACKETS_STR)
+{
+ PIM_DO_DEBUG_GM_PACKETS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_igmp_packets,
+ no_debug_igmp_packets_cmd,
+ "no debug igmp packets",
+ NO_STR
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_PACKETS_STR)
+{
+ PIM_DONT_DEBUG_GM_PACKETS;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_igmp_trace,
+ debug_igmp_trace_cmd,
+ "debug igmp trace",
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_TRACE_STR)
+{
+ PIM_DO_DEBUG_GM_TRACE;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_igmp_trace,
+ no_debug_igmp_trace_cmd,
+ "no debug igmp trace",
+ NO_STR
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_TRACE_STR)
+{
+ PIM_DONT_DEBUG_GM_TRACE;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_igmp_trace_detail,
+ debug_igmp_trace_detail_cmd,
+ "debug igmp trace detail",
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_TRACE_STR
+ "detailed\n")
+{
+ PIM_DO_DEBUG_GM_TRACE_DETAIL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_igmp_trace_detail,
+ no_debug_igmp_trace_detail_cmd,
+ "no debug igmp trace detail",
+ NO_STR
+ DEBUG_STR
+ DEBUG_IGMP_STR
+ DEBUG_IGMP_TRACE_STR
+ "detailed\n")
+{
+ PIM_DONT_DEBUG_GM_TRACE_DETAIL;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_mroute,
+ debug_mroute_cmd,
+ "debug mroute",
+ DEBUG_STR
+ DEBUG_MROUTE_STR)
+{
+ PIM_DO_DEBUG_MROUTE;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_mroute_detail,
+ debug_mroute_detail_cmd,
+ "debug mroute detail",
+ DEBUG_STR
+ DEBUG_MROUTE_STR
+ "detailed\n")
+{
+ PIM_DO_DEBUG_MROUTE_DETAIL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_mroute,
+ no_debug_mroute_cmd,
+ "no debug mroute",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MROUTE_STR)
+{
+ PIM_DONT_DEBUG_MROUTE;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_mroute_detail,
+ no_debug_mroute_detail_cmd,
+ "no debug mroute detail",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MROUTE_STR
+ "detailed\n")
+{
+ PIM_DONT_DEBUG_MROUTE_DETAIL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_pim_static,
+ debug_pim_static_cmd,
+ "debug pim static",
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_STATIC_STR)
+{
+ PIM_DO_DEBUG_STATIC;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_static,
+ no_debug_pim_static_cmd,
+ "no debug pim static",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_STATIC_STR)
+{
+ PIM_DONT_DEBUG_STATIC;
+ return CMD_SUCCESS;
+}
+
+
+DEFPY (debug_pim,
+ debug_pim_cmd,
+ "[no] debug pim",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR)
+{
+ if (!no)
+ return pim_debug_pim_cmd();
+ else
+ return pim_no_debug_pim_cmd();
+}
+
+DEFPY (debug_pim_nht,
+ debug_pim_nht_cmd,
+ "[no] debug pim nht",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ "Nexthop Tracking\n")
+{
+ if (!no)
+ PIM_DO_DEBUG_PIM_NHT;
+ else
+ PIM_DONT_DEBUG_PIM_NHT;
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_pim_nht_det,
+ debug_pim_nht_det_cmd,
+ "[no] debug pim nht detail",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ "Nexthop Tracking\n"
+ "Detailed Information\n")
+{
+ if (!no)
+ PIM_DO_DEBUG_PIM_NHT_DETAIL;
+ else
+ PIM_DONT_DEBUG_PIM_NHT_DETAIL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_pim_nht_rp,
+ debug_pim_nht_rp_cmd,
+ "debug pim nht rp",
+ DEBUG_STR
+ DEBUG_PIM_STR
+ "Nexthop Tracking\n"
+ "RP Nexthop Tracking\n")
+{
+ PIM_DO_DEBUG_PIM_NHT_RP;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_nht_rp,
+ no_debug_pim_nht_rp_cmd,
+ "no debug pim nht rp",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ "Nexthop Tracking\n"
+ "RP Nexthop Tracking\n")
+{
+ PIM_DONT_DEBUG_PIM_NHT_RP;
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_pim_events,
+ debug_pim_events_cmd,
+ "[no] debug pim events",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_EVENTS_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_PIM_EVENTS;
+ else
+ PIM_DONT_DEBUG_PIM_EVENTS;
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_pim_packets,
+ debug_pim_packets_cmd,
+ "[no] debug pim packets [<hello$hello|joins$joins|register$registers>]",
+ NO_STR DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_PACKETS_STR
+ DEBUG_PIM_HELLO_PACKETS_STR
+ DEBUG_PIM_J_P_PACKETS_STR
+ DEBUG_PIM_PIM_REG_PACKETS_STR)
+{
+ if (!no)
+ return pim_debug_pim_packets_cmd(hello, joins, registers, vty);
+ else
+ return pim_no_debug_pim_packets_cmd(hello, joins, registers,
+ vty);
+}
+
+DEFPY (debug_pim_packetdump_send,
+ debug_pim_packetdump_send_cmd,
+ "[no] debug pim packet-dump send",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_PACKETDUMP_STR
+ DEBUG_PIM_PACKETDUMP_SEND_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_PIM_PACKETDUMP_SEND;
+ else
+ PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_pim_packetdump_recv,
+ debug_pim_packetdump_recv_cmd,
+ "[no] debug pim packet-dump receive",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_PACKETDUMP_STR
+ DEBUG_PIM_PACKETDUMP_RECV_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_PIM_PACKETDUMP_RECV;
+ else
+ PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_pim_trace,
+ debug_pim_trace_cmd,
+ "[no] debug pim trace",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_TRACE_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_PIM_TRACE;
+ else
+ PIM_DONT_DEBUG_PIM_TRACE;
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_pim_trace_detail,
+ debug_pim_trace_detail_cmd,
+ "[no] debug pim trace detail",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_TRACE_STR
+ "Detailed Information\n")
+{
+ if (!no)
+ PIM_DO_DEBUG_PIM_TRACE_DETAIL;
+ else
+ PIM_DONT_DEBUG_PIM_TRACE_DETAIL;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_ssmpingd,
+ debug_ssmpingd_cmd,
+ "debug ssmpingd",
+ DEBUG_STR
+ DEBUG_SSMPINGD_STR)
+{
+ PIM_DO_DEBUG_SSMPINGD;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ssmpingd,
+ no_debug_ssmpingd_cmd,
+ "no debug ssmpingd",
+ NO_STR
+ DEBUG_STR
+ DEBUG_SSMPINGD_STR)
+{
+ PIM_DONT_DEBUG_SSMPINGD;
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_pim_zebra,
+ debug_pim_zebra_cmd,
+ "[no] debug pim zebra",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_ZEBRA_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_ZEBRA;
+ else
+ PIM_DONT_DEBUG_ZEBRA;
+ return CMD_SUCCESS;
+}
+
+DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag",
+ DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR)
+{
+ PIM_DO_DEBUG_MLAG;
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag",
+ NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR)
+{
+ PIM_DONT_DEBUG_MLAG;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_pim_vxlan,
+ debug_pim_vxlan_cmd,
+ "debug pim vxlan",
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_VXLAN_STR)
+{
+ PIM_DO_DEBUG_VXLAN;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_vxlan,
+ no_debug_pim_vxlan_cmd,
+ "no debug pim vxlan",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_VXLAN_STR)
+{
+ PIM_DONT_DEBUG_VXLAN;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_msdp,
+ debug_msdp_cmd,
+ "debug msdp",
+ DEBUG_STR
+ DEBUG_MSDP_STR)
+{
+ PIM_DO_DEBUG_MSDP_EVENTS;
+ PIM_DO_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_msdp,
+ no_debug_msdp_cmd,
+ "no debug msdp",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MSDP_STR)
+{
+ PIM_DONT_DEBUG_MSDP_EVENTS;
+ PIM_DONT_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_msdp_events,
+ debug_msdp_events_cmd,
+ "debug msdp events",
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_EVENTS_STR)
+{
+ PIM_DO_DEBUG_MSDP_EVENTS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_msdp_events,
+ no_debug_msdp_events_cmd,
+ "no debug msdp events",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_EVENTS_STR)
+{
+ PIM_DONT_DEBUG_MSDP_EVENTS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_msdp_packets,
+ debug_msdp_packets_cmd,
+ "debug msdp packets",
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_PACKETS_STR)
+{
+ PIM_DO_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_msdp_packets,
+ no_debug_msdp_packets_cmd,
+ "no debug msdp packets",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_PACKETS_STR)
+{
+ PIM_DONT_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_mtrace,
+ debug_mtrace_cmd,
+ "debug mtrace",
+ DEBUG_STR
+ DEBUG_MTRACE_STR)
+{
+ PIM_DO_DEBUG_MTRACE;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_mtrace,
+ no_debug_mtrace_cmd,
+ "no debug mtrace",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MTRACE_STR)
+{
+ PIM_DONT_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]",
+ SHOW_STR
+ DEBUG_STR
+ PIM_STR)
+{
+ vty_out(vty, "PIM debugging status\n");
+
+ pim_debug_config_write(vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (interface_pim_use_source,
+ interface_pim_use_source_cmd,
+ "ip pim use-source A.B.C.D",
+ IP_STR
+ PIM_STR
+ "Configure primary IP address\n"
+ "source ip address\n")
+{
+ nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, argv[3]->arg);
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (interface_no_pim_use_source,
+ interface_no_pim_use_source_cmd,
+ "no ip pim use-source [A.B.C.D]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Delete source IP address\n"
+ "source ip address\n")
+{
+ nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, "0.0.0.0");
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFPY (ip_pim_bfd,
+ ip_pim_bfd_cmd,
+ "ip pim bfd [profile BFDPROF$prof]",
+ IP_STR
+ PIM_STR
+ "Enables BFD support\n"
+ "Use BFD profile\n"
+ "Use BFD profile name\n")
+{
+ const struct lyd_node *igmp_enable_dnode;
+
+ igmp_enable_dnode =
+ yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ "frr-routing:ipv4");
+ if (!igmp_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
+ if (prof)
+ nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_MODIFY, prof);
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd,
+ "no ip pim bfd profile [BFDPROF]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Enables BFD support\n"
+ "Disable BFD profile\n"
+ "BFD Profile name\n")
+{
+ nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (no_ip_pim_bfd,
+ no_ip_pim_bfd_cmd,
+ "no ip pim bfd",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Disables BFD support\n")
+{
+ nb_cli_enqueue_change(vty, "./bfd", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH,
+ "frr-routing:ipv4");
+}
+
+DEFUN (ip_pim_bsm,
+ ip_pim_bsm_cmd,
+ "ip pim bsm",
+ IP_STR
+ PIM_STR
+ "Enables BSM support on the interface\n")
+{
+ const struct lyd_node *igmp_enable_dnode;
+
+ igmp_enable_dnode =
+ yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ "frr-routing:ipv4");
+ if (!igmp_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(igmp_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-routing:ipv4");
+}
+
+DEFUN (no_ip_pim_bsm,
+ no_ip_pim_bsm_cmd,
+ "no ip pim bsm",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Disables BSM support\n")
+{
+ nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
+}
+
+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")
+{
+ const struct lyd_node *igmp_enable_dnode;
+
+ igmp_enable_dnode =
+ yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ "frr-routing:ipv4");
+ if (!igmp_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(igmp_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-routing:ipv4");
+
+}
+
+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")
+{
+ nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
+}
+
+#if HAVE_BFDD > 0
+DEFUN_HIDDEN (
+ ip_pim_bfd_param,
+ ip_pim_bfd_param_cmd,
+ "ip pim bfd (2-255) (1-65535) (1-65535)",
+ IP_STR
+ PIM_STR
+ "Enables BFD support\n"
+ "Detect Multiplier\n"
+ "Required min receive interval\n"
+ "Desired min transmit interval\n")
+#else
+ DEFUN(
+ ip_pim_bfd_param,
+ ip_pim_bfd_param_cmd,
+ "ip pim bfd (2-255) (1-65535) (1-65535)",
+ IP_STR
+ PIM_STR
+ "Enables BFD support\n"
+ "Detect Multiplier\n"
+ "Required min receive interval\n"
+ "Desired min transmit interval\n")
+#endif /* HAVE_BFDD */
+{
+ int idx_number = 3;
+ int idx_number_2 = 4;
+ int idx_number_3 = 5;
+ const struct lyd_node *igmp_enable_dnode;
+
+ igmp_enable_dnode =
+ yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ "frr-routing:ipv4");
+ if (!igmp_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY,
+ argv[idx_number_2]->arg);
+ nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY,
+ argv[idx_number_3]->arg);
+ nb_cli_enqueue_change(vty, "./bfd/detect_mult", NB_OP_MODIFY,
+ argv[idx_number]->arg);
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
+}
+
+#if HAVE_BFDD == 0
+ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
+ "no ip pim bfd (2-255) (1-65535) (1-65535)",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Enables BFD support\n"
+ "Detect Multiplier\n"
+ "Required min receive interval\n"
+ "Desired min transmit interval\n")
+#endif /* !HAVE_BFDD */
+
+DEFPY(ip_msdp_peer, ip_msdp_peer_cmd,
+ "ip msdp peer A.B.C.D$peer source A.B.C.D$source",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP peer\n"
+ "Peer IP address\n"
+ "Source address for TCP connection\n"
+ "Local IP address\n")
+{
+ const char *vrfname;
+ char temp_xpath[XPATH_MAXLEN];
+ char msdp_peer_source_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath),
+ FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
+ "frr-routing:ipv4");
+ snprintf(temp_xpath, sizeof(temp_xpath),
+ "/msdp-peer[peer-ip='%s']/source-ip", peer_str);
+ strlcat(msdp_peer_source_xpath, temp_xpath,
+ sizeof(msdp_peer_source_xpath));
+
+ nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY,
+ source_str);
+
+ return nb_cli_apply_changes(vty,
+ FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
+}
+
+DEFPY(ip_msdp_timers, ip_msdp_timers_cmd,
+ "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]",
+ IP_STR
+ CFG_MSDP_STR
+ "MSDP timers configuration\n"
+ "Keep alive period (in seconds)\n"
+ "Hold time period (in seconds)\n"
+ "Connection retry period (in seconds)\n")
+{
+ const char *vrfname;
+ char xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_MSDP_XPATH, "frr-pim:pimd",
+ "pim", vrfname, "frr-routing:ipv4");
+ nb_cli_enqueue_change(vty, "./hold-time", NB_OP_MODIFY, holdtime_str);
+ nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_MODIFY, keepalive_str);
+ if (connretry_str)
+ nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_MODIFY,
+ connretry_str);
+ else
+ nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY,
+ NULL);
+
+ nb_cli_apply_changes(vty, xpath);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_ip_msdp_timers, no_ip_msdp_timers_cmd,
+ "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "MSDP timers configuration\n"
+ IGNORED_IN_NO_STR
+ IGNORED_IN_NO_STR
+ IGNORED_IN_NO_STR)
+{
+ const char *vrfname;
+ char xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(xpath, sizeof(xpath), FRR_PIM_MSDP_XPATH, "frr-pim:pimd",
+ "pim", vrfname, "frr-routing:ipv4");
+
+ nb_cli_enqueue_change(vty, "./hold-time", NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, NULL);
+
+ nb_cli_apply_changes(vty, xpath);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_msdp_peer,
+ no_ip_msdp_peer_cmd,
+ "no ip msdp peer A.B.C.D",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP peer\n"
+ "peer ip address\n")
+{
+ const char *vrfname;
+ char msdp_peer_xpath[XPATH_MAXLEN];
+ char temp_xpath[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ snprintf(temp_xpath, sizeof(temp_xpath),
+ "/msdp-peer[peer-ip='%s']",
+ argv[4]->arg);
+
+ strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath));
+
+ nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(ip_msdp_mesh_group_member,
+ ip_msdp_mesh_group_member_cmd,
+ "ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP mesh-group\n"
+ "Mesh group name\n"
+ "Mesh group member\n"
+ "Peer IP address\n")
+{
+ const char *vrfname;
+ char xpath_value[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /* Create mesh group. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
+
+ /* Create mesh group member. */
+ strlcat(xpath_value, "/members[address='", sizeof(xpath_value));
+ strlcat(xpath_value, maddr_str, sizeof(xpath_value));
+ strlcat(xpath_value, "']", sizeof(xpath_value));
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_ip_msdp_mesh_group_member,
+ no_ip_msdp_mesh_group_member_cmd,
+ "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group member\n"
+ "Mesh group name\n"
+ "Mesh group member\n"
+ "Peer IP address\n")
+{
+ const char *vrfname;
+ char xpath_value[XPATH_MAXLEN];
+ char xpath_member_value[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+
+ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) {
+ vty_out(vty, "%% mesh-group does not exist\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Remove mesh group member. */
+ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "/members[address='",
+ sizeof(xpath_member_value));
+ strlcat(xpath_member_value, maddr_str, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "']", sizeof(xpath_member_value));
+ if (!yang_dnode_exists(vty->candidate_config->dnode,
+ xpath_member_value)) {
+ vty_out(vty, "%% mesh-group member does not exist\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ nb_cli_enqueue_change(vty, xpath_member_value, NB_OP_DESTROY, NULL);
+
+ /*
+ * If this is the last member, then we must remove the group altogether
+ * to not break legacy CLI behaviour.
+ */
+ pim_cli_legacy_mesh_group_behavior(vty, gname);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(ip_msdp_mesh_group_source,
+ ip_msdp_mesh_group_source_cmd,
+ "ip msdp mesh-group WORD$gname source A.B.C.D$saddr",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP mesh-group\n"
+ "Mesh group name\n"
+ "Mesh group local address\n"
+ "Source IP address for the TCP connection\n")
+{
+ const char *vrfname;
+ char xpath_value[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /* Create mesh group. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
+
+ /* Create mesh group source. */
+ strlcat(xpath_value, "/source", sizeof(xpath_value));
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_ip_msdp_mesh_group_source,
+ no_ip_msdp_mesh_group_source_cmd,
+ "no ip msdp mesh-group WORD$gname source [A.B.C.D]",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group source\n"
+ "Mesh group name\n"
+ "Mesh group source\n"
+ "Mesh group local address\n")
+{
+ const char *vrfname;
+ char xpath_value[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
+
+ /* Create mesh group source. */
+ strlcat(xpath_value, "/source", sizeof(xpath_value));
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
+
+ /*
+ * If this is the last member, then we must remove the group altogether
+ * to not break legacy CLI behaviour.
+ */
+ pim_cli_legacy_mesh_group_behavior(vty, gname);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_ip_msdp_mesh_group,
+ no_ip_msdp_mesh_group_cmd,
+ "no ip msdp mesh-group WORD$gname",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group\n"
+ "Mesh group name")
+{
+ const char *vrfname;
+ char xpath_value[XPATH_MAXLEN];
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
+ return CMD_SUCCESS;
+
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg,
+ struct json_object *json)
+{
+ struct listnode *mbrnode;
+ struct pim_msdp_mg_mbr *mbr;
+ char mbr_str[INET_ADDRSTRLEN];
+ char src_str[INET_ADDRSTRLEN];
+ char state_str[PIM_MSDP_STATE_STRLEN];
+ enum pim_msdp_peer_state state;
+ json_object *json_mg_row = NULL;
+ json_object *json_members = NULL;
+ json_object *json_row = NULL;
+
+ pim_inet4_dump("<source?>", mg->src_ip, src_str, sizeof(src_str));
+ if (json) {
+ /* currently there is only one mesh group but we should still
+ * make
+ * it a dict with mg-name as key */
+ json_mg_row = json_object_new_object();
+ json_object_string_add(json_mg_row, "name",
+ mg->mesh_group_name);
+ json_object_string_add(json_mg_row, "source", src_str);
+ } else {
+ vty_out(vty, "Mesh group : %s\n", mg->mesh_group_name);
+ vty_out(vty, " Source : %s\n", src_str);
+ vty_out(vty, " Member State\n");
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
+ pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str));
+ if (mbr->mp) {
+ state = mbr->mp->state;
+ } else {
+ state = PIM_MSDP_DISABLED;
+ }
+ pim_msdp_state_dump(state, state_str, sizeof(state_str));
+ if (json) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "member", mbr_str);
+ json_object_string_add(json_row, "state", state_str);
+ if (!json_members) {
+ json_members = json_object_new_object();
+ json_object_object_add(json_mg_row, "members",
+ json_members);
+ }
+ json_object_object_add(json_members, mbr_str, json_row);
+ } else {
+ vty_out(vty, " %-15s %11s\n", mbr_str, state_str);
+ }
+ }
+
+ if (json)
+ json_object_object_add(json, mg->mesh_group_name, json_mg_row);
+}
+
+DEFUN (show_ip_msdp_mesh_group,
+ show_ip_msdp_mesh_group_cmd,
+ "show ip msdp [vrf NAME] mesh-group [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP mesh-group information\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ int idx = 2;
+ struct pim_msdp_mg *mg;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ struct pim_instance *pim;
+ struct json_object *json = NULL;
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim = vrf->info;
+ /* Quick case: list is empty. */
+ if (SLIST_EMPTY(&pim->msdp.mglist)) {
+ if (uj)
+ vty_out(vty, "{}\n");
+
+ return CMD_SUCCESS;
+ }
+
+ if (uj)
+ json = json_object_new_object();
+
+ SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
+ ip_msdp_show_mesh_group(vty, mg, json);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_msdp_mesh_group_vrf_all,
+ show_ip_msdp_mesh_group_vrf_all_cmd,
+ "show ip msdp vrf all mesh-group [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP mesh-group information\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct json_object *json = NULL, *vrf_json = NULL;
+ struct pim_instance *pim;
+ struct pim_msdp_mg *mg;
+ struct vrf *vrf;
+
+ if (uj)
+ json = json_object_new_object();
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ vrf_json = json_object_new_object();
+ json_object_object_add(json, vrf->name, vrf_json);
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+
+ pim = vrf->info;
+ SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
+ ip_msdp_show_mesh_group(vty, mg, vrf_json);
+ }
+
+ if (uj)
+ vty_json(vty, json);
+
+
+ return CMD_SUCCESS;
+}
+
+static void ip_msdp_show_peers(struct pim_instance *pim, struct vty *vty,
+ bool uj)
+{
+ struct listnode *mpnode;
+ struct pim_msdp_peer *mp;
+ char peer_str[INET_ADDRSTRLEN];
+ char local_str[INET_ADDRSTRLEN];
+ char state_str[PIM_MSDP_STATE_STRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ int64_t now;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
+
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty,
+ "Peer Local State Uptime SaCnt\n");
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
+ if (mp->state == PIM_MSDP_ESTABLISHED) {
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(timebuf, sizeof(timebuf),
+ now - mp->uptime);
+ } else {
+ strlcpy(timebuf, "-", sizeof(timebuf));
+ }
+ pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
+ pim_inet4_dump("<local?>", mp->local, local_str,
+ sizeof(local_str));
+ pim_msdp_state_dump(mp->state, state_str, sizeof(state_str));
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "peer", peer_str);
+ json_object_string_add(json_row, "local", local_str);
+ json_object_string_add(json_row, "state", state_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_int_add(json_row, "saCount", mp->sa_cnt);
+ json_object_object_add(json, peer_str, json_row);
+ } else {
+ vty_out(vty, "%-15s %15s %11s %8s %6d\n", peer_str,
+ local_str, state_str, timebuf, mp->sa_cnt);
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty,
+ const char *peer, bool uj)
+{
+ struct listnode *mpnode;
+ struct pim_msdp_peer *mp;
+ char peer_str[INET_ADDRSTRLEN];
+ char local_str[INET_ADDRSTRLEN];
+ char state_str[PIM_MSDP_STATE_STRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ char katimer[PIM_MSDP_TIMER_STRLEN];
+ char crtimer[PIM_MSDP_TIMER_STRLEN];
+ char holdtimer[PIM_MSDP_TIMER_STRLEN];
+ int64_t now;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
+ pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
+ if (strcmp(peer, "detail") && strcmp(peer, peer_str))
+ continue;
+
+ if (mp->state == PIM_MSDP_ESTABLISHED) {
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(timebuf, sizeof(timebuf),
+ now - mp->uptime);
+ } else {
+ strlcpy(timebuf, "-", sizeof(timebuf));
+ }
+ pim_inet4_dump("<local?>", mp->local, local_str,
+ sizeof(local_str));
+ pim_msdp_state_dump(mp->state, state_str, sizeof(state_str));
+ pim_time_timer_to_hhmmss(katimer, sizeof(katimer),
+ mp->ka_timer);
+ pim_time_timer_to_hhmmss(crtimer, sizeof(crtimer),
+ mp->cr_timer);
+ pim_time_timer_to_hhmmss(holdtimer, sizeof(holdtimer),
+ mp->hold_timer);
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "peer", peer_str);
+ json_object_string_add(json_row, "local", local_str);
+ if (mp->flags & PIM_MSDP_PEERF_IN_GROUP)
+ json_object_string_add(json_row,
+ "meshGroupName",
+ mp->mesh_group_name);
+ json_object_string_add(json_row, "state", state_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_string_add(json_row, "keepAliveTimer",
+ katimer);
+ json_object_string_add(json_row, "connRetryTimer",
+ crtimer);
+ json_object_string_add(json_row, "holdTimer",
+ holdtimer);
+ json_object_string_add(json_row, "lastReset",
+ mp->last_reset);
+ json_object_int_add(json_row, "connAttempts",
+ mp->conn_attempts);
+ json_object_int_add(json_row, "establishedChanges",
+ mp->est_flaps);
+ json_object_int_add(json_row, "saCount", mp->sa_cnt);
+ json_object_int_add(json_row, "kaSent", mp->ka_tx_cnt);
+ json_object_int_add(json_row, "kaRcvd", mp->ka_rx_cnt);
+ json_object_int_add(json_row, "saSent", mp->sa_tx_cnt);
+ json_object_int_add(json_row, "saRcvd", mp->sa_rx_cnt);
+ json_object_object_add(json, peer_str, json_row);
+ } else {
+ vty_out(vty, "Peer : %s\n", peer_str);
+ vty_out(vty, " Local : %s\n", local_str);
+ if (mp->flags & PIM_MSDP_PEERF_IN_GROUP)
+ vty_out(vty, " Mesh Group : %s\n",
+ mp->mesh_group_name);
+ vty_out(vty, " State : %s\n", state_str);
+ vty_out(vty, " Uptime : %s\n", timebuf);
+
+ vty_out(vty, " Keepalive Timer : %s\n", katimer);
+ vty_out(vty, " Conn Retry Timer : %s\n", crtimer);
+ vty_out(vty, " Hold Timer : %s\n", holdtimer);
+ vty_out(vty, " Last Reset : %s\n",
+ mp->last_reset);
+ vty_out(vty, " Conn Attempts : %d\n",
+ mp->conn_attempts);
+ vty_out(vty, " Established Changes : %d\n",
+ mp->est_flaps);
+ vty_out(vty, " SA Count : %d\n",
+ mp->sa_cnt);
+ vty_out(vty, " Statistics :\n");
+ vty_out(vty,
+ " Sent Rcvd\n");
+ vty_out(vty, " Keepalives : %10d %10d\n",
+ mp->ka_tx_cnt, mp->ka_rx_cnt);
+ vty_out(vty, " SAs : %10d %10d\n",
+ mp->sa_tx_cnt, mp->sa_rx_cnt);
+ vty_out(vty, "\n");
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+DEFUN (show_ip_msdp_peer_detail,
+ show_ip_msdp_peer_detail_cmd,
+ "show ip msdp [vrf NAME] peer [detail|A.B.C.D] [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP peer information\n"
+ "Detailed output\n"
+ "peer ip address\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ char *arg = NULL;
+
+ if (argv_find(argv, argc, "detail", &idx))
+ arg = argv[idx]->text;
+ else if (argv_find(argv, argc, "A.B.C.D", &idx))
+ arg = argv[idx]->arg;
+
+ if (arg)
+ ip_msdp_show_peers_detail(vrf->info, vty, argv[idx]->arg, uj);
+ else
+ ip_msdp_show_peers(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_msdp_peer_detail_vrf_all,
+ show_ip_msdp_peer_detail_vrf_all_cmd,
+ "show ip msdp vrf all peer [detail|A.B.C.D] [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP peer information\n"
+ "Detailed output\n"
+ "peer ip address\n"
+ JSON_STR)
+{
+ int idx = 2;
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ if (argv_find(argv, argc, "detail", &idx)
+ || argv_find(argv, argc, "A.B.C.D", &idx))
+ ip_msdp_show_peers_detail(vrf->info, vty,
+ argv[idx]->arg, uj);
+ else
+ ip_msdp_show_peers(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
+static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ char rp_str[INET_ADDRSTRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ char spt_str[8];
+ char local_str[8];
+ int64_t now;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty,
+ "Source Group RP Local SPT Uptime\n");
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime);
+ if (sa->flags & PIM_MSDP_SAF_PEER) {
+ pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
+ if (sa->up) {
+ strlcpy(spt_str, "yes", sizeof(spt_str));
+ } else {
+ strlcpy(spt_str, "no", sizeof(spt_str));
+ }
+ } else {
+ strlcpy(rp_str, "-", sizeof(rp_str));
+ strlcpy(spt_str, "-", sizeof(spt_str));
+ }
+ if (sa->flags & PIM_MSDP_SAF_LOCAL) {
+ strlcpy(local_str, "yes", sizeof(local_str));
+ } else {
+ strlcpy(local_str, "no", sizeof(local_str));
+ }
+ if (uj) {
+ char src_str[PIM_ADDRSTRLEN];
+ char grp_str[PIM_ADDRSTRLEN];
+
+ snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
+ &sa->sg.grp);
+ snprintfrr(src_str, sizeof(src_str), "%pPAs",
+ &sa->sg.src);
+
+ 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);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "rp", rp_str);
+ json_object_string_add(json_row, "local", local_str);
+ json_object_string_add(json_row, "sptSetup", spt_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ vty_out(vty, "%-15pPAs %15pPAs %15s %5c %3c %8s\n",
+ &sa->sg.src, &sa->sg.grp, rp_str, local_str[0],
+ spt_str[0], timebuf);
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa,
+ const char *src_str,
+ const char *grp_str, struct vty *vty,
+ bool uj, json_object *json)
+{
+ char rp_str[INET_ADDRSTRLEN];
+ char peer_str[INET_ADDRSTRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ char spt_str[8];
+ char local_str[8];
+ char statetimer[PIM_MSDP_TIMER_STRLEN];
+ int64_t now;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime);
+ if (sa->flags & PIM_MSDP_SAF_PEER) {
+ 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) {
+ strlcpy(spt_str, "yes", sizeof(spt_str));
+ } else {
+ strlcpy(spt_str, "no", sizeof(spt_str));
+ }
+ } else {
+ 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) {
+ strlcpy(local_str, "yes", sizeof(local_str));
+ } else {
+ strlcpy(local_str, "no", sizeof(local_str));
+ }
+ pim_time_timer_to_hhmmss(statetimer, sizeof(statetimer),
+ sa->sa_state_timer);
+ 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);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "rp", rp_str);
+ json_object_string_add(json_row, "local", local_str);
+ json_object_string_add(json_row, "sptSetup", spt_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_string_add(json_row, "stateTimer", statetimer);
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ vty_out(vty, "SA : %s\n", sa->sg_str);
+ vty_out(vty, " RP : %s\n", rp_str);
+ vty_out(vty, " Peer : %s\n", peer_str);
+ vty_out(vty, " Local : %s\n", local_str);
+ vty_out(vty, " SPT Setup : %s\n", spt_str);
+ vty_out(vty, " Uptime : %s\n", timebuf);
+ vty_out(vty, " State Timer : %s\n", statetimer);
+ vty_out(vty, "\n");
+ }
+}
+
+static void ip_msdp_show_sa_detail(struct pim_instance *pim, struct vty *vty,
+ bool uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ json_object *json = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
+ char src_str[PIM_ADDRSTRLEN];
+ char grp_str[PIM_ADDRSTRLEN];
+
+ snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &sa->sg.grp);
+ snprintfrr(src_str, sizeof(src_str), "%pPAs", &sa->sg.src);
+
+ ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj,
+ json);
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+DEFUN (show_ip_msdp_sa_detail,
+ show_ip_msdp_sa_detail_cmd,
+ "show ip msdp [vrf NAME] sa detail [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP active-source information\n"
+ "Detailed output\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ ip_msdp_show_sa_detail(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_msdp_sa_detail_vrf_all,
+ show_ip_msdp_sa_detail_vrf_all_cmd,
+ "show ip msdp vrf all sa detail [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP active-source information\n"
+ "Detailed output\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ ip_msdp_show_sa_detail(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
+static void ip_msdp_show_sa_addr(struct pim_instance *pim, struct vty *vty,
+ const char *addr, bool uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ json_object *json = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
+ char src_str[PIM_ADDRSTRLEN];
+ char grp_str[PIM_ADDRSTRLEN];
+
+ snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &sa->sg.grp);
+ snprintfrr(src_str, sizeof(src_str), "%pPAs", &sa->sg.src);
+
+ if (!strcmp(addr, src_str) || !strcmp(addr, grp_str)) {
+ ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty,
+ uj, json);
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void ip_msdp_show_sa_sg(struct pim_instance *pim, struct vty *vty,
+ const char *src, const char *grp, bool uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ json_object *json = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
+ char src_str[PIM_ADDRSTRLEN];
+ char grp_str[PIM_ADDRSTRLEN];
+
+ snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &sa->sg.grp);
+ snprintfrr(src_str, sizeof(src_str), "%pPAs", &sa->sg.src);
+
+ if (!strcmp(src, src_str) && !strcmp(grp, grp_str)) {
+ ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty,
+ uj, json);
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+DEFUN (show_ip_msdp_sa_sg,
+ show_ip_msdp_sa_sg_cmd,
+ "show ip msdp [vrf NAME] sa [A.B.C.D [A.B.C.D]] [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP active-source information\n"
+ "source or group ip\n"
+ "group ip\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ int idx = 2;
+
+ vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ 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(vrf->info, vty, src_ip, grp_ip, uj);
+ else if (src_ip)
+ ip_msdp_show_sa_addr(vrf->info, vty, src_ip, uj);
+ else
+ ip_msdp_show_sa(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_msdp_sa_sg_vrf_all,
+ show_ip_msdp_sa_sg_vrf_all_cmd,
+ "show ip msdp vrf all sa [A.B.C.D [A.B.C.D]] [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ VRF_CMD_HELP_STR
+ "MSDP active-source information\n"
+ "source or group ip\n"
+ "group ip\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+ int idx = 2;
+
+ 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 (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+
+ if (src_ip && grp_ip)
+ ip_msdp_show_sa_sg(vrf->info, vty, src_ip, grp_ip, uj);
+ else if (src_ip)
+ ip_msdp_show_sa_addr(vrf->info, vty, src_ip, uj);
+ else
+ ip_msdp_show_sa(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
+struct pim_sg_cache_walk_data {
+ struct vty *vty;
+ json_object *json;
+ json_object *json_group;
+ struct in_addr addr;
+ bool addr_match;
+};
+
+static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
+ struct pim_sg_cache_walk_data *cwd)
+{
+ struct vty *vty = cwd->vty;
+ json_object *json = cwd->json;
+ json_object *json_row;
+ bool installed = (vxlan_sg->up) ? true : false;
+ const char *iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
+ const char *oif_name;
+
+ if (pim_vxlan_is_orig_mroute(vxlan_sg))
+ oif_name = vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
+ else
+ oif_name = vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
+
+ if (cwd->addr_match && pim_addr_cmp(vxlan_sg->sg.src, cwd->addr) &&
+ pim_addr_cmp(vxlan_sg->sg.grp, cwd->addr)) {
+ return;
+ }
+ if (json) {
+ char src_str[PIM_ADDRSTRLEN];
+ char grp_str[PIM_ADDRSTRLEN];
+
+ snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
+ &vxlan_sg->sg.grp);
+ snprintfrr(src_str, sizeof(src_str), "%pPAs",
+ &vxlan_sg->sg.src);
+
+ json_object_object_get_ex(json, grp_str, &cwd->json_group);
+
+ if (!cwd->json_group) {
+ cwd->json_group = json_object_new_object();
+ json_object_object_add(json, grp_str,
+ cwd->json_group);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "input", iif_name);
+ json_object_string_add(json_row, "output", oif_name);
+ if (installed)
+ json_object_boolean_true_add(json_row, "installed");
+ else
+ json_object_boolean_false_add(json_row, "installed");
+ json_object_object_add(cwd->json_group, src_str, json_row);
+ } else {
+ vty_out(vty, "%-15pPAs %-15pPAs %-15s %-15s %-5s\n",
+ &vxlan_sg->sg.src, &vxlan_sg->sg.grp, iif_name,
+ oif_name, installed ? "I" : "");
+ }
+}
+
+static void pim_show_vxlan_sg_hash_entry(struct hash_bucket *bucket, void *arg)
+{
+ pim_show_vxlan_sg_entry((struct pim_vxlan_sg *)bucket->data,
+ (struct pim_sg_cache_walk_data *)arg);
+}
+
+static void pim_show_vxlan_sg(struct pim_instance *pim,
+ struct vty *vty, bool uj)
+{
+ json_object *json = NULL;
+ struct pim_sg_cache_walk_data cwd;
+
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty, "Codes: I -> installed\n");
+ vty_out(vty,
+ "Source Group Input Output Flags\n");
+ }
+
+ memset(&cwd, 0, sizeof(cwd));
+ cwd.vty = vty;
+ cwd.json = json;
+ hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void pim_show_vxlan_sg_match_addr(struct pim_instance *pim,
+ struct vty *vty, char *addr_str,
+ bool uj)
+{
+ json_object *json = NULL;
+ struct pim_sg_cache_walk_data cwd;
+ int result = 0;
+
+ memset(&cwd, 0, sizeof(cwd));
+ result = inet_pton(AF_INET, addr_str, &cwd.addr);
+ if (result <= 0) {
+ vty_out(vty, "Bad address %s: errno=%d: %s\n", addr_str,
+ errno, safe_strerror(errno));
+ return;
+ }
+
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty, "Codes: I -> installed\n");
+ vty_out(vty,
+ "Source Group Input Output Flags\n");
+ }
+
+ cwd.vty = vty;
+ cwd.json = json;
+ cwd.addr_match = true;
+ hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+static void pim_show_vxlan_sg_one(struct pim_instance *pim,
+ struct vty *vty, char *src_str, char *grp_str,
+ bool uj)
+{
+ json_object *json = NULL;
+ pim_sgaddr sg;
+ int result = 0;
+ struct pim_vxlan_sg *vxlan_sg;
+ const char *iif_name;
+ bool installed;
+ const char *oif_name;
+
+ result = inet_pton(AF_INET, src_str, &sg.src);
+ if (result <= 0) {
+ vty_out(vty, "Bad src address %s: errno=%d: %s\n", src_str,
+ errno, safe_strerror(errno));
+ return;
+ }
+ result = inet_pton(AF_INET, grp_str, &sg.grp);
+ if (result <= 0) {
+ vty_out(vty, "Bad grp address %s: errno=%d: %s\n", grp_str,
+ errno, safe_strerror(errno));
+ return;
+ }
+
+ if (uj)
+ json = json_object_new_object();
+
+ vxlan_sg = pim_vxlan_sg_find(pim, &sg);
+ if (vxlan_sg) {
+ installed = (vxlan_sg->up) ? true : false;
+ iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
+
+ if (pim_vxlan_is_orig_mroute(vxlan_sg))
+ oif_name =
+ vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
+ else
+ oif_name =
+ vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
+
+ if (uj) {
+ json_object_string_add(json, "source", src_str);
+ json_object_string_add(json, "group", grp_str);
+ json_object_string_add(json, "input", iif_name);
+ json_object_string_add(json, "output", oif_name);
+ if (installed)
+ json_object_boolean_true_add(json, "installed");
+ else
+ json_object_boolean_false_add(json,
+ "installed");
+ } else {
+ vty_out(vty, "SG : %s\n", vxlan_sg->sg_str);
+ vty_out(vty, " Input : %s\n", iif_name);
+ vty_out(vty, " Output : %s\n", oif_name);
+ vty_out(vty, " installed : %s\n",
+ installed?"yes":"no");
+ }
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+DEFUN (show_ip_pim_vxlan_sg,
+ show_ip_pim_vxlan_sg_cmd,
+ "show ip pim [vrf NAME] vxlan-groups [A.B.C.D [A.B.C.D]] [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "VxLAN BUM groups\n"
+ "source or group ip\n"
+ "group ip\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ int idx = 2;
+
+ vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ 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)
+ pim_show_vxlan_sg_one(vrf->info, vty, src_ip, grp_ip, uj);
+ else if (src_ip)
+ pim_show_vxlan_sg_match_addr(vrf->info, vty, src_ip, uj);
+ else
+ pim_show_vxlan_sg(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+static void pim_show_vxlan_sg_work(struct pim_instance *pim,
+ struct vty *vty, bool uj)
+{
+ json_object *json = NULL;
+ struct pim_sg_cache_walk_data cwd;
+ struct listnode *node;
+ struct pim_vxlan_sg *vxlan_sg;
+
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty, "Codes: I -> installed\n");
+ vty_out(vty,
+ "Source Group Input Flags\n");
+ }
+
+ memset(&cwd, 0, sizeof(cwd));
+ cwd.vty = vty;
+ cwd.json = json;
+ for (ALL_LIST_ELEMENTS_RO(pim_vxlan_p->work_list, node, vxlan_sg))
+ pim_show_vxlan_sg_entry(vxlan_sg, &cwd);
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work,
+ show_ip_pim_vxlan_sg_work_cmd,
+ "show ip pim [vrf NAME] vxlan-work [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "VxLAN work list\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ int idx = 2;
+
+ vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim_show_vxlan_sg_work(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (no_ip_pim_mlag,
+ no_ip_pim_mlag_cmd,
+ "no ip pim mlag",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "MLAG\n")
+{
+ char mlag_xpath[XPATH_MAXLEN];
+
+ snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+ strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath));
+
+ nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL);
+
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_HIDDEN (ip_pim_mlag,
+ ip_pim_mlag_cmd,
+ "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D",
+ IP_STR
+ PIM_STR
+ "MLAG\n"
+ "peerlink sub interface\n"
+ "MLAG role\n"
+ "MLAG role primary\n"
+ "MLAG role secondary\n"
+ "peer session state\n"
+ "peer session state up\n"
+ "peer session state down\n"
+ "configure PIP\n"
+ "unique ip address\n")
+{
+ int idx;
+ char mlag_peerlink_rif_xpath[XPATH_MAXLEN];
+ char mlag_my_role_xpath[XPATH_MAXLEN];
+ char mlag_peer_state_xpath[XPATH_MAXLEN];
+ char mlag_reg_address_xpath[XPATH_MAXLEN];
+
+ snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+ strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif",
+ sizeof(mlag_peerlink_rif_xpath));
+
+ idx = 3;
+ nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY,
+ argv[idx]->arg);
+
+ snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+ strlcat(mlag_my_role_xpath, "/mlag/my-role",
+ sizeof(mlag_my_role_xpath));
+
+ idx += 2;
+ if (!strcmp(argv[idx]->arg, "primary")) {
+ nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY,
+ "MLAG_ROLE_PRIMARY");
+
+ } else if (!strcmp(argv[idx]->arg, "secondary")) {
+ nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY,
+ "MLAG_ROLE_SECONDARY");
+
+ } else {
+ vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg);
+ return CMD_WARNING;
+ }
+
+ snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+ strlcat(mlag_peer_state_xpath, "/mlag/peer-state",
+ sizeof(mlag_peer_state_xpath));
+
+ idx += 2;
+ if (!strcmp(argv[idx]->arg, "up")) {
+ nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY,
+ "true");
+
+ } else if (strcmp(argv[idx]->arg, "down")) {
+ nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY,
+ "false");
+
+ } else {
+ vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg);
+ return CMD_WARNING;
+ }
+
+ snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath),
+ FRR_PIM_VRF_XPATH,
+ "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+ strlcat(mlag_reg_address_xpath, "/mlag/reg-address",
+ sizeof(mlag_reg_address_xpath));
+
+ idx += 2;
+ nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY,
+ argv[idx]->arg);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void pim_cmd_init(void)
+{
+ if_cmd_init(pim_interface_config_write);
+
+ install_node(&debug_node);
+
+ install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd);
+
+ install_element(CONFIG_NODE, &ip_pim_rp_cmd);
+ install_element(VRF_NODE, &ip_pim_rp_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_rp_cmd);
+ install_element(VRF_NODE, &no_ip_pim_rp_cmd);
+ install_element(CONFIG_NODE, &ip_pim_rp_prefix_list_cmd);
+ install_element(VRF_NODE, &ip_pim_rp_prefix_list_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd);
+ install_element(VRF_NODE, &no_ip_pim_rp_prefix_list_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_cmd);
+ install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
+ install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
+ install_element(CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
+ install_element(VRF_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(VRF_NODE, &ip_pim_spt_switchover_infinity_cmd);
+ install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
+ install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
+ install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
+ install_element(CONFIG_NODE,
+ &no_ip_pim_spt_switchover_infinity_plist_cmd);
+ install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd);
+ install_element(CONFIG_NODE, &pim_register_accept_list_cmd);
+ install_element(VRF_NODE, &pim_register_accept_list_cmd);
+ install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
+ install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd);
+ install_element(VRF_NODE, &ip_pim_keep_alive_cmd);
+ install_element(CONFIG_NODE, &ip_pim_rp_keep_alive_cmd);
+ install_element(VRF_NODE, &ip_pim_rp_keep_alive_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_keep_alive_cmd);
+ install_element(VRF_NODE, &no_ip_pim_keep_alive_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_rp_keep_alive_cmd);
+ install_element(VRF_NODE, &no_ip_pim_rp_keep_alive_cmd);
+ install_element(CONFIG_NODE, &ip_pim_packets_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_packets_cmd);
+ install_element(CONFIG_NODE, &ip_pim_v6_secondary_cmd);
+ install_element(VRF_NODE, &ip_pim_v6_secondary_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd);
+ install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd);
+ install_element(CONFIG_NODE, &ip_ssmpingd_cmd);
+ install_element(VRF_NODE, &ip_ssmpingd_cmd);
+ install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd);
+ install_element(VRF_NODE, &no_ip_ssmpingd_cmd);
+ install_element(CONFIG_NODE, &ip_msdp_peer_cmd);
+ install_element(VRF_NODE, &ip_msdp_peer_cmd);
+ install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd);
+ install_element(VRF_NODE, &no_ip_msdp_peer_cmd);
+ install_element(CONFIG_NODE, &ip_pim_ecmp_cmd);
+ install_element(VRF_NODE, &ip_pim_ecmp_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd);
+ install_element(VRF_NODE, &no_ip_pim_ecmp_cmd);
+ install_element(CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd);
+ install_element(VRF_NODE, &ip_pim_ecmp_rebalance_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
+ install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd);
+ install_element(CONFIG_NODE, &ip_pim_mlag_cmd);
+ install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd);
+ install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd);
+ install_element(VRF_NODE, &ip_igmp_group_watermark_cmd);
+ install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd);
+ install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd);
+
+ install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_version_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_igmp_version_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd);
+ install_element(INTERFACE_NODE,
+ &interface_no_ip_igmp_query_interval_cmd);
+ install_element(INTERFACE_NODE,
+ &interface_ip_igmp_query_max_response_time_cmd);
+ install_element(INTERFACE_NODE,
+ &interface_no_ip_igmp_query_max_response_time_cmd);
+ install_element(INTERFACE_NODE,
+ &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(INTERFACE_NODE, &interface_ip_pim_sm_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_pim_sm_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_pim_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_pim_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_pim_drprio_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_pim_drprio_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_pim_hello_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_pim_hello_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_pim_boundary_oil_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_pim_boundary_oil_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_query_generate_cmd);
+
+ // Static mroutes NEB
+ install_element(INTERFACE_NODE, &interface_ip_mroute_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_mroute_cmd);
+
+ install_element(VIEW_NODE, &show_ip_igmp_interface_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_join_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_groups_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_sources_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_statistics_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_assert_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_assert_internal_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_assert_metric_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_interface_traffic_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_interface_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_interface_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_join_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_join_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_jp_agg_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_mlag_summary_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_mlag_up_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_mlag_up_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_neighbor_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_rpf_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_rpf_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_secondary_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_state_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_state_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_upstream_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_upstream_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_channel_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_upstream_join_desired_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_multicast_count_cmd);
+ install_element(VIEW_NODE, &show_ip_multicast_count_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_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_mroute_count_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, &clear_ip_pim_statistics_cmd);
+ install_element(ENABLE_NODE, &clear_ip_pim_bsr_db_cmd);
+
+ install_element(ENABLE_NODE, &show_debugging_pim_cmd);
+
+ install_element(ENABLE_NODE, &debug_igmp_cmd);
+ install_element(ENABLE_NODE, &no_debug_igmp_cmd);
+ install_element(ENABLE_NODE, &debug_igmp_events_cmd);
+ install_element(ENABLE_NODE, &no_debug_igmp_events_cmd);
+ install_element(ENABLE_NODE, &debug_igmp_packets_cmd);
+ install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd);
+ install_element(ENABLE_NODE, &debug_igmp_trace_cmd);
+ install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd);
+ install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd);
+ install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd);
+ install_element(ENABLE_NODE, &debug_mroute_cmd);
+ install_element(ENABLE_NODE, &debug_mroute_detail_cmd);
+ install_element(ENABLE_NODE, &no_debug_mroute_cmd);
+ install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd);
+ install_element(ENABLE_NODE, &debug_pim_static_cmd);
+ install_element(ENABLE_NODE, &no_debug_pim_static_cmd);
+ install_element(ENABLE_NODE, &debug_pim_cmd);
+ install_element(ENABLE_NODE, &debug_pim_nht_cmd);
+ install_element(ENABLE_NODE, &debug_pim_nht_det_cmd);
+ install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd);
+ install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd);
+ install_element(ENABLE_NODE, &debug_pim_events_cmd);
+ install_element(ENABLE_NODE, &debug_pim_packets_cmd);
+ install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd);
+ install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd);
+ install_element(ENABLE_NODE, &debug_pim_trace_cmd);
+ install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd);
+ install_element(ENABLE_NODE, &debug_ssmpingd_cmd);
+ install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd);
+ install_element(ENABLE_NODE, &debug_pim_zebra_cmd);
+ install_element(ENABLE_NODE, &debug_pim_mlag_cmd);
+ install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd);
+ install_element(ENABLE_NODE, &debug_pim_vxlan_cmd);
+ install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd);
+ install_element(ENABLE_NODE, &debug_msdp_cmd);
+ install_element(ENABLE_NODE, &no_debug_msdp_cmd);
+ install_element(ENABLE_NODE, &debug_msdp_events_cmd);
+ install_element(ENABLE_NODE, &no_debug_msdp_events_cmd);
+ install_element(ENABLE_NODE, &debug_msdp_packets_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, &debug_igmp_events_cmd);
+ install_element(CONFIG_NODE, &no_debug_igmp_events_cmd);
+ install_element(CONFIG_NODE, &debug_igmp_packets_cmd);
+ install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd);
+ install_element(CONFIG_NODE, &debug_igmp_trace_cmd);
+ install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd);
+ install_element(CONFIG_NODE, &debug_igmp_trace_detail_cmd);
+ install_element(CONFIG_NODE, &no_debug_igmp_trace_detail_cmd);
+ install_element(CONFIG_NODE, &debug_mroute_cmd);
+ install_element(CONFIG_NODE, &debug_mroute_detail_cmd);
+ install_element(CONFIG_NODE, &no_debug_mroute_cmd);
+ install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd);
+ install_element(CONFIG_NODE, &debug_pim_static_cmd);
+ install_element(CONFIG_NODE, &no_debug_pim_static_cmd);
+ install_element(CONFIG_NODE, &debug_pim_cmd);
+ install_element(CONFIG_NODE, &debug_pim_nht_cmd);
+ install_element(CONFIG_NODE, &debug_pim_nht_det_cmd);
+ install_element(CONFIG_NODE, &debug_pim_nht_rp_cmd);
+ install_element(CONFIG_NODE, &no_debug_pim_nht_rp_cmd);
+ install_element(CONFIG_NODE, &debug_pim_events_cmd);
+ install_element(CONFIG_NODE, &debug_pim_packets_cmd);
+ install_element(CONFIG_NODE, &debug_pim_packetdump_send_cmd);
+ install_element(CONFIG_NODE, &debug_pim_packetdump_recv_cmd);
+ install_element(CONFIG_NODE, &debug_pim_trace_cmd);
+ install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd);
+ install_element(CONFIG_NODE, &debug_ssmpingd_cmd);
+ install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
+ install_element(CONFIG_NODE, &debug_pim_zebra_cmd);
+ install_element(CONFIG_NODE, &debug_pim_mlag_cmd);
+ install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd);
+ install_element(CONFIG_NODE, &debug_pim_vxlan_cmd);
+ install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd);
+ install_element(CONFIG_NODE, &debug_msdp_cmd);
+ install_element(CONFIG_NODE, &no_debug_msdp_cmd);
+ install_element(CONFIG_NODE, &debug_msdp_events_cmd);
+ install_element(CONFIG_NODE, &no_debug_msdp_events_cmd);
+ install_element(CONFIG_NODE, &debug_msdp_packets_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_timers_cmd);
+ install_element(VRF_NODE, &ip_msdp_timers_cmd);
+ install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd);
+ install_element(VRF_NODE, &no_ip_msdp_timers_cmd);
+ install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd);
+ install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd);
+ install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd);
+ install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd);
+ install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd);
+ install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd);
+ install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd);
+ install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd);
+ install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd);
+ install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd);
+ install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_group_type_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_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);
+ install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd);
+ install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd);
+#if HAVE_BFDD == 0
+ install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd);
+#endif /* !HAVE_BFDD */
+}