mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 13:43:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			5690 lines
		
	
	
		
			147 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			5690 lines
		
	
	
		
			147 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * PIM for IPv6 FRR
 | 
						|
 * Copyright (C) 2022  Vmware, Inc.
 | 
						|
 *		       Mobashshera Rasool <mrasool@vmware.com>
 | 
						|
 *
 | 
						|
 * 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 "lib/srcdest_table.h"
 | 
						|
#include "lib/linklist.h"
 | 
						|
#include "termtable.h"
 | 
						|
 | 
						|
#include "pimd.h"
 | 
						|
#include "pim_instance.h"
 | 
						|
#include "pim_vty.h"
 | 
						|
#include "lib/northbound_cli.h"
 | 
						|
#include "pim_errors.h"
 | 
						|
#include "pim_nb.h"
 | 
						|
#include "pim_mroute.h"
 | 
						|
#include "pim_cmd.h"
 | 
						|
#include "pim6_cmd.h"
 | 
						|
#include "pim_cmd_common.h"
 | 
						|
#include "pim_time.h"
 | 
						|
#include "pim_zebra.h"
 | 
						|
#include "pim_zlookup.h"
 | 
						|
#include "pim_iface.h"
 | 
						|
#include "pim_macro.h"
 | 
						|
#include "pim_neighbor.h"
 | 
						|
#include "pim_nht.h"
 | 
						|
#include "pim_sock.h"
 | 
						|
#include "pim_ssm.h"
 | 
						|
#include "pim_static.h"
 | 
						|
#include "pim_addr.h"
 | 
						|
#include "pim_static.h"
 | 
						|
#include "pim_util.h"
 | 
						|
#include "pim6_mld.h"
 | 
						|
 | 
						|
/**
 | 
						|
 * Get current node VRF name.
 | 
						|
 *
 | 
						|
 * NOTE:
 | 
						|
 * In case of failure it will print error message to user.
 | 
						|
 *
 | 
						|
 * \returns name or NULL if failed to get VRF.
 | 
						|
 */
 | 
						|
const char *pim_cli_get_vrf_name(struct vty *vty)
 | 
						|
{
 | 
						|
	const struct lyd_node *vrf_node;
 | 
						|
 | 
						|
	/* Not inside any VRF context. */
 | 
						|
	if (vty->xpath_index == 0)
 | 
						|
		return VRF_DEFAULT_NAME;
 | 
						|
 | 
						|
	vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
 | 
						|
	if (vrf_node == NULL) {
 | 
						|
		vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return yang_dnode_get_string(vrf_node, "./name");
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str)
 | 
						|
{
 | 
						|
	char xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(xpath, "/join-prune-interval", sizeof(xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, jpi_str);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_join_prune_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	char xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(xpath, "/join-prune-interval", sizeof(xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_spt_switchover_infinity_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char spt_plist_xpath[XPATH_MAXLEN];
 | 
						|
	char spt_action_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
 | 
						|
		sizeof(spt_plist_xpath));
 | 
						|
 | 
						|
	snprintf(spt_action_xpath, sizeof(spt_action_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(spt_action_xpath, "/spt-switchover/spt-action",
 | 
						|
		sizeof(spt_action_xpath));
 | 
						|
 | 
						|
	if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
 | 
						|
		nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
 | 
						|
				      NULL);
 | 
						|
	nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
 | 
						|
			      "PIM_SPT_INFINITY");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty,
 | 
						|
					      const char *plist)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char spt_plist_xpath[XPATH_MAXLEN];
 | 
						|
	char spt_action_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
 | 
						|
		sizeof(spt_plist_xpath));
 | 
						|
 | 
						|
	snprintf(spt_action_xpath, sizeof(spt_action_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(spt_action_xpath, "/spt-switchover/spt-action",
 | 
						|
		sizeof(spt_action_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
 | 
						|
			      "PIM_SPT_INFINITY");
 | 
						|
	nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
 | 
						|
			      plist);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_spt_switchover_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char spt_plist_xpath[XPATH_MAXLEN];
 | 
						|
	char spt_action_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
 | 
						|
		sizeof(spt_plist_xpath));
 | 
						|
 | 
						|
	snprintf(spt_action_xpath, sizeof(spt_action_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(spt_action_xpath, "/spt-switchover/spt-action",
 | 
						|
		sizeof(spt_action_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
 | 
						|
	nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
 | 
						|
			      "PIM_SPT_IMMEDIATE");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_pim_packet_cmd(struct vty *vty, const char *packet)
 | 
						|
{
 | 
						|
	char xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(xpath, "/packets", sizeof(xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, packet);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_pim_packet_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	char xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(xpath, "/packets", sizeof(xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char ka_timer_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
 | 
						|
		 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
 | 
						|
			      kat);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_keepalivetimer_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char ka_timer_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
 | 
						|
		 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char rp_ka_timer_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
 | 
						|
		sizeof(rp_ka_timer_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
 | 
						|
			      rpkat);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_rp_kat_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char rp_ka_timer[6];
 | 
						|
	char rp_ka_timer_xpath[XPATH_MAXLEN];
 | 
						|
	uint v;
 | 
						|
	char rs_timer_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	snprintf(rs_timer_xpath, sizeof(rs_timer_xpath),
 | 
						|
		 FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(rs_timer_xpath, "/register-suppress-time",
 | 
						|
		sizeof(rs_timer_xpath));
 | 
						|
 | 
						|
	/* RFC4601 */
 | 
						|
	v = yang_dnode_get_uint16(vty->candidate_config->dnode, "%s",
 | 
						|
				  rs_timer_xpath);
 | 
						|
	v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT;
 | 
						|
	if (v > UINT16_MAX)
 | 
						|
		v = UINT16_MAX;
 | 
						|
	snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v);
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
 | 
						|
		sizeof(rp_ka_timer_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
 | 
						|
			      rp_ka_timer);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_register_suppress_cmd(struct vty *vty, const char *rst)
 | 
						|
{
 | 
						|
	char xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(xpath, "/register-suppress-time", sizeof(xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, rst);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_register_suppress_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	char xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(xpath, "/register-suppress-time", sizeof(xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ip_pim_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable)
 | 
						|
{
 | 
						|
	if (enable)
 | 
						|
		nb_cli_enqueue_change(vty, "./pim-passive-enable", NB_OP_MODIFY,
 | 
						|
				      "true");
 | 
						|
	else
 | 
						|
		nb_cli_enqueue_change(vty, "./pim-passive-enable", NB_OP_MODIFY,
 | 
						|
				      "false");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_ip_pim_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	const struct lyd_node *mld_enable_dnode;
 | 
						|
	char mld_if_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	int printed =
 | 
						|
		snprintf(mld_if_xpath, sizeof(mld_if_xpath),
 | 
						|
			 "%s/frr-gmp:gmp/address-family[address-family='%s']",
 | 
						|
			 VTY_CURR_XPATH, FRR_PIM_AF_XPATH_VAL);
 | 
						|
 | 
						|
	if (printed >= (int)(sizeof(mld_if_xpath))) {
 | 
						|
		vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
 | 
						|
			XPATH_MAXLEN);
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
	}
 | 
						|
 | 
						|
	mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
 | 
						|
					   FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
 | 
						|
					   FRR_PIM_AF_XPATH_VAL);
 | 
						|
 | 
						|
	if (!mld_enable_dnode) {
 | 
						|
		nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, NULL);
 | 
						|
		nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
 | 
						|
	} else {
 | 
						|
		if (!yang_dnode_get_bool(mld_enable_dnode, ".")) {
 | 
						|
			nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY,
 | 
						|
					      NULL);
 | 
						|
			nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
 | 
						|
		} else
 | 
						|
			nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
					      "false");
 | 
						|
	}
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
 | 
						|
			      drpriority_str);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_ip_pim_drprio_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str,
 | 
						|
				 const char *hold_str)
 | 
						|
{
 | 
						|
	const struct lyd_node *mld_enable_dnode;
 | 
						|
 | 
						|
	mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
 | 
						|
					   FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
 | 
						|
					   FRR_PIM_AF_XPATH_VAL);
 | 
						|
 | 
						|
	if (!mld_enable_dnode) {
 | 
						|
		nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
				      "true");
 | 
						|
	} else {
 | 
						|
		if (!yang_dnode_get_bool(mld_enable_dnode, "."))
 | 
						|
			nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
					      "true");
 | 
						|
	}
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, hello_str);
 | 
						|
 | 
						|
	if (hold_str)
 | 
						|
		nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY,
 | 
						|
				      hold_str);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_ip_pim_hello_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL);
 | 
						|
	nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no)
 | 
						|
{
 | 
						|
	if (no)
 | 
						|
		nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
 | 
						|
				      "false");
 | 
						|
	else {
 | 
						|
		nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
				      "true");
 | 
						|
 | 
						|
		nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
 | 
						|
				      "true");
 | 
						|
	}
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY,
 | 
						|
			      oil);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY,
 | 
						|
			      NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
 | 
						|
			      const char *group_str, const char *source_str)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, interface);
 | 
						|
 | 
						|
	if (!source_str) {
 | 
						|
		char buf[SRCDEST2STR_BUFFER];
 | 
						|
 | 
						|
		inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf));
 | 
						|
		return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
 | 
						|
					    FRR_PIM_AF_XPATH_VAL, buf,
 | 
						|
					    group_str);
 | 
						|
	}
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL, source_str,
 | 
						|
				    group_str);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface,
 | 
						|
				 const char *group_str, const char *source_str)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	if (!source_str) {
 | 
						|
		char buf[SRCDEST2STR_BUFFER];
 | 
						|
 | 
						|
		inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf));
 | 
						|
		return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
 | 
						|
					    FRR_PIM_AF_XPATH_VAL, buf,
 | 
						|
					    group_str);
 | 
						|
	}
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL, source_str,
 | 
						|
				    group_str);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_rp_cmd(struct vty *vty, const char *rp_str,
 | 
						|
		       const char *group_str)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char rp_group_xpath[XPATH_MAXLEN];
 | 
						|
	int result = 0;
 | 
						|
	struct prefix group;
 | 
						|
	pim_addr rp_addr;
 | 
						|
 | 
						|
	result = str2prefix(group_str, &group);
 | 
						|
	if (result) {
 | 
						|
		struct prefix temp;
 | 
						|
 | 
						|
		prefix_copy(&temp, &group);
 | 
						|
		apply_mask(&temp);
 | 
						|
		if (!prefix_same(&group, &temp)) {
 | 
						|
			vty_out(vty, "%% Inconsistent address and mask: %s\n",
 | 
						|
				group_str);
 | 
						|
			return CMD_WARNING_CONFIG_FAILED;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!result) {
 | 
						|
		vty_out(vty, "%% Bad group address specified: %s\n", group_str);
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
	}
 | 
						|
 | 
						|
	result = inet_pton(PIM_AF, rp_str, &rp_addr);
 | 
						|
	if (result <= 0) {
 | 
						|
		vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
	}
 | 
						|
 | 
						|
	if (pim_addr_is_any(rp_addr) || pim_addr_is_multicast(rp_addr)) {
 | 
						|
		vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
	}
 | 
						|
 | 
						|
#if PIM_IPV == 6
 | 
						|
	if (IN6_IS_ADDR_LINKLOCAL(&rp_addr)) {
 | 
						|
		vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(rp_group_xpath, sizeof(rp_group_xpath),
 | 
						|
		 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL, rp_str);
 | 
						|
	strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str,
 | 
						|
			  const char *group_str)
 | 
						|
{
 | 
						|
	char group_list_xpath[XPATH_MAXLEN];
 | 
						|
	char group_xpath[XPATH_MAXLEN];
 | 
						|
	char rp_xpath[XPATH_MAXLEN];
 | 
						|
	int printed;
 | 
						|
	const char *vrfname;
 | 
						|
	const struct lyd_node *group_dnode;
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
 | 
						|
		 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
 | 
						|
 | 
						|
	printed = snprintf(group_list_xpath, sizeof(group_list_xpath),
 | 
						|
			   "%s/group-list", rp_xpath);
 | 
						|
 | 
						|
	if (printed >= (int)(sizeof(group_list_xpath))) {
 | 
						|
		vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
 | 
						|
			XPATH_MAXLEN);
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
	}
 | 
						|
 | 
						|
	printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']",
 | 
						|
			   group_list_xpath, group_str);
 | 
						|
 | 
						|
	if (printed >= (int)(sizeof(group_xpath))) {
 | 
						|
		vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
 | 
						|
			XPATH_MAXLEN);
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
	}
 | 
						|
 | 
						|
	group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath);
 | 
						|
	if (!group_dnode) {
 | 
						|
		vty_out(vty, "%% Unable to find specified RP\n");
 | 
						|
		return NB_OK;
 | 
						|
	}
 | 
						|
 | 
						|
	if (yang_is_last_list_dnode(group_dnode))
 | 
						|
		nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
 | 
						|
	else
 | 
						|
		nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY,
 | 
						|
				      group_str);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str,
 | 
						|
			     const char *prefix_list)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char rp_plist_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(rp_plist_xpath, sizeof(rp_plist_xpath),
 | 
						|
		 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL, rp_str);
 | 
						|
	strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
 | 
						|
				const char *prefix_list)
 | 
						|
{
 | 
						|
	char rp_xpath[XPATH_MAXLEN];
 | 
						|
	char plist_xpath[XPATH_MAXLEN];
 | 
						|
	const char *vrfname;
 | 
						|
	const struct lyd_node *plist_dnode;
 | 
						|
	const char *plist;
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
 | 
						|
		 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
 | 
						|
 | 
						|
	snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH,
 | 
						|
		 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
 | 
						|
	strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath));
 | 
						|
 | 
						|
	plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath);
 | 
						|
	if (!plist_dnode) {
 | 
						|
		vty_out(vty, "%% Unable to find specified RP\n");
 | 
						|
		return NB_OK;
 | 
						|
	}
 | 
						|
 | 
						|
	plist = yang_dnode_get_string(plist_dnode, "%s", plist_xpath);
 | 
						|
	if (strcmp(prefix_list, plist)) {
 | 
						|
		vty_out(vty, "%% Unable to find specified RP\n");
 | 
						|
		return NB_OK;
 | 
						|
	}
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match)
 | 
						|
{
 | 
						|
	return (pim_addr_is_any(match.grp) ||
 | 
						|
		!pim_addr_cmp(match.grp, item.grp)) &&
 | 
						|
	       (pim_addr_is_any(match.src) ||
 | 
						|
		!pim_addr_cmp(match.src, item.src));
 | 
						|
}
 | 
						|
 | 
						|
void json_object_pim_ifp_add(struct json_object *json, struct interface *ifp)
 | 
						|
{
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
 | 
						|
	pim_ifp = ifp->info;
 | 
						|
	json_object_string_add(json, "name", ifp->name);
 | 
						|
	json_object_string_add(json, "state", if_is_up(ifp) ? "up" : "down");
 | 
						|
	json_object_string_addf(json, "address", "%pPA",
 | 
						|
				&pim_ifp->primary_address);
 | 
						|
	json_object_int_add(json, "index", ifp->ifindex);
 | 
						|
 | 
						|
	if (if_is_multicast(ifp))
 | 
						|
		json_object_boolean_true_add(json, "flagMulticast");
 | 
						|
 | 
						|
	if (if_is_broadcast(ifp))
 | 
						|
		json_object_boolean_true_add(json, "flagBroadcast");
 | 
						|
 | 
						|
	if (ifp->flags & IFF_ALLMULTI)
 | 
						|
		json_object_boolean_true_add(json, "flagAllMulticast");
 | 
						|
 | 
						|
	if (ifp->flags & IFF_PROMISC)
 | 
						|
		json_object_boolean_true_add(json, "flagPromiscuous");
 | 
						|
 | 
						|
	if (PIM_IF_IS_DELETED(ifp))
 | 
						|
		json_object_boolean_true_add(json, "flagDeleted");
 | 
						|
 | 
						|
	if (pim_if_lan_delay_enabled(ifp))
 | 
						|
		json_object_boolean_true_add(json, "lanDelayEnabled");
 | 
						|
}
 | 
						|
 | 
						|
void pim_print_ifp_flags(struct vty *vty, struct interface *ifp)
 | 
						|
{
 | 
						|
	vty_out(vty, "Flags\n");
 | 
						|
	vty_out(vty, "-----\n");
 | 
						|
	vty_out(vty, "All Multicast   : %s\n",
 | 
						|
		(ifp->flags & IFF_ALLMULTI) ? "yes" : "no");
 | 
						|
	vty_out(vty, "Broadcast       : %s\n",
 | 
						|
		if_is_broadcast(ifp) ? "yes" : "no");
 | 
						|
	vty_out(vty, "Deleted         : %s\n",
 | 
						|
		PIM_IF_IS_DELETED(ifp) ? "yes" : "no");
 | 
						|
	vty_out(vty, "Interface Index : %d\n", ifp->ifindex);
 | 
						|
	vty_out(vty, "Multicast       : %s\n",
 | 
						|
		if_is_multicast(ifp) ? "yes" : "no");
 | 
						|
	vty_out(vty, "Promiscuous     : %s\n",
 | 
						|
		(ifp->flags & IFF_PROMISC) ? "yes" : "no");
 | 
						|
	vty_out(vty, "\n");
 | 
						|
	vty_out(vty, "\n");
 | 
						|
}
 | 
						|
 | 
						|
void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up)
 | 
						|
{
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "drJoinDesired",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "drJoinDesiredUpdated",
 | 
						|
		CHECK_FLAG(up->flags,
 | 
						|
			   PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "firstHopRouter",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_FHR));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "sourceIgmp",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "sourcePim",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_PIM));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "sourceStream",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM));
 | 
						|
	/* XXX: need to print ths flag in the plain text display as well */
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "sourceMsdp",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_MSDP));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "sendSGRptPrune",
 | 
						|
		CHECK_FLAG(up->flags,
 | 
						|
			   PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "lastHopRouter",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_LHR));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "disableKATExpiry",
 | 
						|
		CHECK_FLAG(up->flags,
 | 
						|
			   PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "staticIncomingInterface",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_STATIC_IIF));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "allowIncomingInterfaceinOil",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "noPimRegistrationData",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "forcePimRegistration",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "sourceVxlanOrigination",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "sourceVxlanTermination",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "mlagVxlan",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN));
 | 
						|
	json_object_boolean_add(
 | 
						|
		json, "mlagNonDesignatedForwarder",
 | 
						|
		CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF));
 | 
						|
}
 | 
						|
 | 
						|
static const char *
 | 
						|
pim_upstream_state2brief_str(enum pim_upstream_state join_state,
 | 
						|
			     char *state_str, size_t state_str_len)
 | 
						|
{
 | 
						|
	switch (join_state) {
 | 
						|
	case PIM_UPSTREAM_NOTJOINED:
 | 
						|
		strlcpy(state_str, "NotJ", state_str_len);
 | 
						|
		break;
 | 
						|
	case PIM_UPSTREAM_JOINED:
 | 
						|
		strlcpy(state_str, "J", state_str_len);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		strlcpy(state_str, "Unk", state_str_len);
 | 
						|
	}
 | 
						|
	return state_str;
 | 
						|
}
 | 
						|
 | 
						|
static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
 | 
						|
					   char *state_str,
 | 
						|
					   size_t state_str_len)
 | 
						|
{
 | 
						|
	switch (reg_state) {
 | 
						|
	case PIM_REG_NOINFO:
 | 
						|
		strlcpy(state_str, "RegNI", state_str_len);
 | 
						|
		break;
 | 
						|
	case PIM_REG_JOIN:
 | 
						|
		strlcpy(state_str, "RegJ", state_str_len);
 | 
						|
		break;
 | 
						|
	case PIM_REG_JOIN_PENDING:
 | 
						|
	case PIM_REG_PRUNE:
 | 
						|
		strlcpy(state_str, "RegP", state_str_len);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	return state_str;
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_rpf_refresh_stats(struct vty *vty, struct pim_instance *pim,
 | 
						|
				time_t now, json_object *json)
 | 
						|
{
 | 
						|
	char refresh_uptime[10];
 | 
						|
 | 
						|
	pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now,
 | 
						|
			      pim->rpf_cache_refresh_last);
 | 
						|
 | 
						|
	if (json) {
 | 
						|
		json_object_int_add(json, "rpfCacheRefreshDelayMsecs",
 | 
						|
				    router->rpf_cache_refresh_delay_msec);
 | 
						|
		json_object_int_add(
 | 
						|
			json, "rpfCacheRefreshTimer",
 | 
						|
			pim_time_timer_remain_msec(pim->rpf_cache_refresher));
 | 
						|
		json_object_int_add(json, "rpfCacheRefreshRequests",
 | 
						|
				    pim->rpf_cache_refresh_requests);
 | 
						|
		json_object_int_add(json, "rpfCacheRefreshEvents",
 | 
						|
				    pim->rpf_cache_refresh_events);
 | 
						|
		json_object_string_add(json, "rpfCacheRefreshLast",
 | 
						|
				       refresh_uptime);
 | 
						|
		json_object_int_add(json, "nexthopLookups",
 | 
						|
				    pim->nexthop_lookups);
 | 
						|
		json_object_int_add(json, "nexthopLookupsAvoided",
 | 
						|
				    pim->nexthop_lookups_avoided);
 | 
						|
	} else {
 | 
						|
		vty_out(vty,
 | 
						|
			"RPF Cache Refresh Delay:    %ld msecs\n"
 | 
						|
			"RPF Cache Refresh Timer:    %ld msecs\n"
 | 
						|
			"RPF Cache Refresh Requests: %lld\n"
 | 
						|
			"RPF Cache Refresh Events:   %lld\n"
 | 
						|
			"RPF Cache Refresh Last:     %s\n"
 | 
						|
			"Nexthop Lookups:            %lld\n"
 | 
						|
			"Nexthop Lookups Avoided:    %lld\n",
 | 
						|
			router->rpf_cache_refresh_delay_msec,
 | 
						|
			pim_time_timer_remain_msec(pim->rpf_cache_refresher),
 | 
						|
			(long long)pim->rpf_cache_refresh_requests,
 | 
						|
			(long long)pim->rpf_cache_refresh_events,
 | 
						|
			refresh_uptime, (long long)pim->nexthop_lookups,
 | 
						|
			(long long)pim->nexthop_lookups_avoided);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json)
 | 
						|
{
 | 
						|
	struct pim_upstream *up;
 | 
						|
	time_t now = pim_time_monotonic_sec();
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	pim_show_rpf_refresh_stats(vty, pim, now, json);
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		vty_out(vty, "\n");
 | 
						|
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(
 | 
						|
			tt,
 | 
						|
			"Source|Group|RpfIface|RpfAddress|RibNextHop|Metric|Pref");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	frr_each (rb_pim_upstream, &pim->upstream_head, up) {
 | 
						|
		const char *rpf_ifname;
 | 
						|
		struct pim_rpf *rpf = &up->rpf;
 | 
						|
 | 
						|
		rpf_ifname =
 | 
						|
			rpf->source_nexthop.interface ? rpf->source_nexthop
 | 
						|
								.interface->name
 | 
						|
						      : "<ifname?>";
 | 
						|
 | 
						|
		if (json) {
 | 
						|
			char grp_str[PIM_ADDRSTRLEN];
 | 
						|
			char src_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
			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, "source", src_str);
 | 
						|
			json_object_string_add(json_row, "group", grp_str);
 | 
						|
			json_object_string_add(json_row, "rpfInterface",
 | 
						|
					       rpf_ifname);
 | 
						|
			json_object_string_addf(json_row, "rpfAddress", "%pPA",
 | 
						|
						&rpf->rpf_addr);
 | 
						|
			json_object_string_addf(
 | 
						|
				json_row, "ribNexthop", "%pPAs",
 | 
						|
				&rpf->source_nexthop.mrib_nexthop_addr);
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "routeMetric",
 | 
						|
				rpf->source_nexthop.mrib_route_metric);
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "routePreference",
 | 
						|
				rpf->source_nexthop.mrib_metric_preference);
 | 
						|
			json_object_object_add(json_group, src_str, json_row);
 | 
						|
 | 
						|
		} else {
 | 
						|
			ttable_add_row(
 | 
						|
				tt, "%pPAs|%pPAs|%s|%pPA|%pPAs|%d|%d",
 | 
						|
				&up->sg.src, &up->sg.grp, rpf_ifname,
 | 
						|
				&rpf->rpf_addr,
 | 
						|
				&rpf->source_nexthop.mrib_nexthop_addr,
 | 
						|
				rpf->source_nexthop.mrib_route_metric,
 | 
						|
				rpf->source_nexthop.mrib_metric_preference);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty)
 | 
						|
{
 | 
						|
	struct interface *ifp;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
 | 
						|
	/* Prepare table. */
 | 
						|
	tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
	ttable_add_row(tt, "Interface|Address|Neighbor|Secondary");
 | 
						|
	tt->style.cell.rpad = 2;
 | 
						|
	tt->style.corner = '+';
 | 
						|
	ttable_restyle(tt);
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		struct pim_interface *pim_ifp;
 | 
						|
		pim_addr ifaddr;
 | 
						|
		struct listnode *neighnode;
 | 
						|
		struct pim_neighbor *neigh;
 | 
						|
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (pim_ifp->pim_sock_fd < 0)
 | 
						|
			continue;
 | 
						|
 | 
						|
		ifaddr = pim_ifp->primary_address;
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
 | 
						|
					  neigh)) {
 | 
						|
			struct listnode *prefix_node;
 | 
						|
			struct prefix *p;
 | 
						|
 | 
						|
			if (!neigh->prefix_list)
 | 
						|
				continue;
 | 
						|
 | 
						|
			for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list,
 | 
						|
						  prefix_node, p))
 | 
						|
				ttable_add_row(tt, "%s|%pPAs|%pPAs|%pFX",
 | 
						|
					       ifp->name, &ifaddr,
 | 
						|
					       &neigh->source_addr, p);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	table = ttable_dump(tt, "\n");
 | 
						|
	vty_out(vty, "%s\n", table);
 | 
						|
	XFREE(MTYPE_TMP, table);
 | 
						|
	ttable_del(tt);
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_state(struct pim_instance *pim, struct vty *vty,
 | 
						|
		    const char *src_or_group, const char *group,
 | 
						|
		    json_object *json)
 | 
						|
{
 | 
						|
	struct channel_oil *c_oil;
 | 
						|
#if PIM_IPV != 4
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
#endif
 | 
						|
	char flag[50];
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_ifp_in = NULL;
 | 
						|
	json_object *json_ifp_out = NULL;
 | 
						|
	json_object *json_source = NULL;
 | 
						|
	time_t now;
 | 
						|
	int first_oif;
 | 
						|
 | 
						|
	now = pim_time_monotonic_sec();
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		vty_out(vty,
 | 
						|
			"Codes: J -> Pim Join, I -> " GM " Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted\n");
 | 
						|
#if PIM_IPV == 4
 | 
						|
		vty_out(vty,
 | 
						|
			"Active Source           Group            RPT  IIF               OIL\n");
 | 
						|
#else
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(tt, "Active|Source|Group|RPT|IIF|OIL");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
 | 
						|
		char src_str[PIM_ADDRSTRLEN];
 | 
						|
		char grp_str[PIM_ADDRSTRLEN];
 | 
						|
		char in_ifname[INTERFACE_NAMSIZ + 1];
 | 
						|
		char out_ifname[INTERFACE_NAMSIZ + 1];
 | 
						|
		int oif_vif_index;
 | 
						|
		struct interface *ifp_in;
 | 
						|
		bool isRpt;
 | 
						|
 | 
						|
		first_oif = 1;
 | 
						|
 | 
						|
		if ((c_oil->up &&
 | 
						|
		     PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
 | 
						|
		    pim_addr_is_any(*oil_origin(c_oil)))
 | 
						|
			isRpt = true;
 | 
						|
		else
 | 
						|
			isRpt = false;
 | 
						|
 | 
						|
		snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
 | 
						|
			   oil_mcastgrp(c_oil));
 | 
						|
		snprintfrr(src_str, sizeof(src_str), "%pPAs",
 | 
						|
			   oil_origin(c_oil));
 | 
						|
		ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
 | 
						|
 | 
						|
		if (ifp_in)
 | 
						|
			strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
 | 
						|
		else
 | 
						|
			strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
 | 
						|
 | 
						|
		if (src_or_group) {
 | 
						|
			if (strcmp(src_or_group, src_str) &&
 | 
						|
			    strcmp(src_or_group, grp_str))
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (group && strcmp(group, grp_str))
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (json) {
 | 
						|
 | 
						|
			/* Find the group, create it if it doesn't exist */
 | 
						|
			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);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Find the source nested under the group, create it if
 | 
						|
			 * it doesn't exist
 | 
						|
			 */
 | 
						|
			json_object_object_get_ex(json_group, src_str,
 | 
						|
						  &json_source);
 | 
						|
 | 
						|
			if (!json_source) {
 | 
						|
				json_source = json_object_new_object();
 | 
						|
				json_object_object_add(json_group, src_str,
 | 
						|
						       json_source);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Find the inbound interface nested under the source,
 | 
						|
			 * create it if it doesn't exist
 | 
						|
			 */
 | 
						|
			json_object_object_get_ex(json_source, in_ifname,
 | 
						|
						  &json_ifp_in);
 | 
						|
 | 
						|
			if (!json_ifp_in) {
 | 
						|
				json_ifp_in = json_object_new_object();
 | 
						|
				json_object_object_add(json_source, in_ifname,
 | 
						|
						       json_ifp_in);
 | 
						|
				json_object_int_add(json_source, "installed",
 | 
						|
						    c_oil->installed);
 | 
						|
				json_object_boolean_add(json_source, "isRpt",
 | 
						|
							isRpt);
 | 
						|
				json_object_int_add(json_source, "refCount",
 | 
						|
						    c_oil->oil_ref_count);
 | 
						|
				json_object_int_add(json_source, "oilListSize",
 | 
						|
						    c_oil->oil_size);
 | 
						|
				json_object_int_add(
 | 
						|
					json_source, "oilRescan",
 | 
						|
					c_oil->oil_inherited_rescan);
 | 
						|
				json_object_int_add(json_source, "lastUsed",
 | 
						|
						    c_oil->cc.lastused);
 | 
						|
				json_object_int_add(json_source, "packetCount",
 | 
						|
						    c_oil->cc.pktcnt);
 | 
						|
				json_object_int_add(json_source, "byteCount",
 | 
						|
						    c_oil->cc.bytecnt);
 | 
						|
				json_object_int_add(json_source,
 | 
						|
						    "wrongInterface",
 | 
						|
						    c_oil->cc.wrong_if);
 | 
						|
			}
 | 
						|
		}
 | 
						|
#if PIM_IPV == 4
 | 
						|
		else
 | 
						|
			vty_out(vty, "%-6d %-15pPAs  %-15pPAs  %-3s  %-16s  ",
 | 
						|
				c_oil->installed, oil_origin(c_oil),
 | 
						|
				oil_mcastgrp(c_oil), isRpt ? "y" : "n",
 | 
						|
				in_ifname);
 | 
						|
#endif
 | 
						|
 | 
						|
		for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
 | 
						|
		     ++oif_vif_index) {
 | 
						|
			struct interface *ifp_out;
 | 
						|
			char oif_uptime[10];
 | 
						|
			int ttl;
 | 
						|
 | 
						|
			ttl = oil_if_has(c_oil, oif_vif_index);
 | 
						|
			if (ttl < 1)
 | 
						|
				continue;
 | 
						|
 | 
						|
			ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
 | 
						|
			pim_time_uptime(
 | 
						|
				oif_uptime, sizeof(oif_uptime),
 | 
						|
				now - c_oil->oif_creation[oif_vif_index]);
 | 
						|
 | 
						|
			if (ifp_out)
 | 
						|
				strlcpy(out_ifname, ifp_out->name,
 | 
						|
					sizeof(out_ifname));
 | 
						|
			else
 | 
						|
				strlcpy(out_ifname, "<oif?>",
 | 
						|
					sizeof(out_ifname));
 | 
						|
 | 
						|
			if (json) {
 | 
						|
				json_ifp_out = json_object_new_object();
 | 
						|
				json_object_string_add(json_ifp_out, "source",
 | 
						|
						       src_str);
 | 
						|
				json_object_string_add(json_ifp_out, "group",
 | 
						|
						       grp_str);
 | 
						|
				json_object_string_add(json_ifp_out,
 | 
						|
						       "inboundInterface",
 | 
						|
						       in_ifname);
 | 
						|
				json_object_string_add(json_ifp_out,
 | 
						|
						       "outboundInterface",
 | 
						|
						       out_ifname);
 | 
						|
				json_object_int_add(json_ifp_out, "installed",
 | 
						|
						    c_oil->installed);
 | 
						|
 | 
						|
				json_object_object_add(json_ifp_in, out_ifname,
 | 
						|
						       json_ifp_out);
 | 
						|
			} else {
 | 
						|
				flag[0] = '\0';
 | 
						|
				snprintf(flag, sizeof(flag), "(%c%c%c%c%c)",
 | 
						|
					 (c_oil->oif_flags[oif_vif_index] &
 | 
						|
					  PIM_OIF_FLAG_PROTO_GM)
 | 
						|
						 ? 'I'
 | 
						|
						 : ' ',
 | 
						|
					 (c_oil->oif_flags[oif_vif_index] &
 | 
						|
					  PIM_OIF_FLAG_PROTO_PIM)
 | 
						|
						 ? 'J'
 | 
						|
						 : ' ',
 | 
						|
					 (c_oil->oif_flags[oif_vif_index] &
 | 
						|
					  PIM_OIF_FLAG_PROTO_VXLAN)
 | 
						|
						 ? 'V'
 | 
						|
						 : ' ',
 | 
						|
					 (c_oil->oif_flags[oif_vif_index] &
 | 
						|
					  PIM_OIF_FLAG_PROTO_STAR)
 | 
						|
						 ? '*'
 | 
						|
						 : ' ',
 | 
						|
					 (c_oil->oif_flags[oif_vif_index] &
 | 
						|
					  PIM_OIF_FLAG_MUTE)
 | 
						|
						 ? 'M'
 | 
						|
						 : ' ');
 | 
						|
 | 
						|
				if (first_oif) {
 | 
						|
					first_oif = 0;
 | 
						|
#if PIM_IPV == 4
 | 
						|
					vty_out(vty, "%s%s", out_ifname, flag);
 | 
						|
#else
 | 
						|
					ttable_add_row(
 | 
						|
						tt, "%d|%pPAs|%pPAs|%s|%s|%s%s",
 | 
						|
						c_oil->installed,
 | 
						|
						oil_origin(c_oil),
 | 
						|
						oil_mcastgrp(c_oil),
 | 
						|
						isRpt ? "y" : "n", in_ifname,
 | 
						|
						out_ifname, flag);
 | 
						|
#endif
 | 
						|
				} else {
 | 
						|
#if PIM_IPV == 4
 | 
						|
					vty_out(vty, ", %s%s", out_ifname,
 | 
						|
						flag);
 | 
						|
#else
 | 
						|
					ttable_add_row(tt,
 | 
						|
						       "%c|%c|%c|%c|%c|%s%s",
 | 
						|
						       ' ', ' ', ' ', ' ', ' ',
 | 
						|
						       out_ifname, flag);
 | 
						|
#endif
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
#if PIM_IPV == 4
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "\n");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
#if PIM_IPV == 4
 | 
						|
		vty_out(vty, "\n");
 | 
						|
#else
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* pim statistics - just adding only bsm related now.
 | 
						|
 * We can continue to add all pim related stats here.
 | 
						|
 */
 | 
						|
void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
 | 
						|
			 const char *ifname, bool uj)
 | 
						|
{
 | 
						|
	json_object *json = NULL;
 | 
						|
	struct interface *ifp;
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		json = json_object_new_object();
 | 
						|
		json_object_int_add(json, "bsmRx", pim->bsm_rcvd);
 | 
						|
		json_object_int_add(json, "bsmTx", pim->bsm_sent);
 | 
						|
		json_object_int_add(json, "bsmDropped", pim->bsm_dropped);
 | 
						|
	} else {
 | 
						|
		vty_out(vty, "BSM Statistics :\n");
 | 
						|
		vty_out(vty, "----------------\n");
 | 
						|
		vty_out(vty, "Number of Received BSMs : %" PRIu64 "\n",
 | 
						|
			pim->bsm_rcvd);
 | 
						|
		vty_out(vty, "Number of Forwared BSMs : %" PRIu64 "\n",
 | 
						|
			pim->bsm_sent);
 | 
						|
		vty_out(vty, "Number of Dropped BSMs  : %" PRIu64 "\n",
 | 
						|
			pim->bsm_dropped);
 | 
						|
	}
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
 | 
						|
	/* scan interfaces */
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		struct pim_interface *pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (ifname && strcmp(ifname, ifp->name))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (!uj) {
 | 
						|
			vty_out(vty, "Interface : %s\n", ifp->name);
 | 
						|
			vty_out(vty, "-------------------\n");
 | 
						|
			vty_out(vty,
 | 
						|
				"Number of BSMs dropped due to config miss : %u\n",
 | 
						|
				pim_ifp->pim_ifstat_bsm_cfg_miss);
 | 
						|
			vty_out(vty, "Number of unicast BSMs dropped : %u\n",
 | 
						|
				pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
 | 
						|
			vty_out(vty,
 | 
						|
				"Number of BSMs dropped due to invalid scope zone : %u\n",
 | 
						|
				pim_ifp->pim_ifstat_bsm_invalid_sz);
 | 
						|
		} else {
 | 
						|
 | 
						|
			json_object *json_row = NULL;
 | 
						|
 | 
						|
			json_row = json_object_new_object();
 | 
						|
 | 
						|
			json_object_string_add(json_row, "If Name", ifp->name);
 | 
						|
			json_object_int_add(json_row, "bsmDroppedConfig",
 | 
						|
					    pim_ifp->pim_ifstat_bsm_cfg_miss);
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "bsmDroppedUnicast",
 | 
						|
				pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
 | 
						|
			json_object_int_add(json_row,
 | 
						|
					    "bsmDroppedInvalidScopeZone",
 | 
						|
					    pim_ifp->pim_ifstat_bsm_invalid_sz);
 | 
						|
			json_object_object_add(json, ifp->name, json_row);
 | 
						|
		}
 | 
						|
		vty_out(vty, "\n");
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
 | 
						|
		       pim_sgaddr *sg, json_object *json)
 | 
						|
{
 | 
						|
	struct pim_upstream *up;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
	time_t now;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	now = pim_time_monotonic_sec();
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(
 | 
						|
			tt,
 | 
						|
			"Iif|Source|Group|State|Uptime|JoinTimer|RSTimer|KATimer|RefCnt");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	frr_each (rb_pim_upstream, &pim->upstream_head, up) {
 | 
						|
		char uptime[10];
 | 
						|
		char join_timer[10];
 | 
						|
		char rs_timer[10];
 | 
						|
		char ka_timer[10];
 | 
						|
		char msdp_reg_timer[10];
 | 
						|
		char state_str[PIM_REG_STATE_STR_LEN];
 | 
						|
 | 
						|
		if (!pim_sgaddr_match(up->sg, *sg))
 | 
						|
			continue;
 | 
						|
 | 
						|
		pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
				now - up->state_transition);
 | 
						|
		pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer),
 | 
						|
					 up->t_join_timer);
 | 
						|
 | 
						|
		/*
 | 
						|
		 * If the upstream is not dummy and it has a J/P timer for the
 | 
						|
		 * neighbor display that
 | 
						|
		 */
 | 
						|
		if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
 | 
						|
			struct pim_neighbor *nbr;
 | 
						|
 | 
						|
			nbr = pim_neighbor_find(
 | 
						|
				up->rpf.source_nexthop.interface,
 | 
						|
				up->rpf.rpf_addr);
 | 
						|
			if (nbr)
 | 
						|
				pim_time_timer_to_hhmmss(join_timer,
 | 
						|
							 sizeof(join_timer),
 | 
						|
							 nbr->jp_timer);
 | 
						|
		}
 | 
						|
 | 
						|
		pim_time_timer_to_hhmmss(rs_timer, sizeof(rs_timer),
 | 
						|
					 up->t_rs_timer);
 | 
						|
		pim_time_timer_to_hhmmss(ka_timer, sizeof(ka_timer),
 | 
						|
					 up->t_ka_timer);
 | 
						|
		pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
 | 
						|
					 up->t_msdp_reg_timer);
 | 
						|
 | 
						|
		pim_upstream_state2brief_str(up->join_state, state_str,
 | 
						|
					     sizeof(state_str));
 | 
						|
		if (up->reg_state != PIM_REG_NOINFO) {
 | 
						|
			char tmp_str[PIM_REG_STATE_STR_LEN];
 | 
						|
			char tmp[sizeof(state_str) + 1];
 | 
						|
 | 
						|
			snprintf(tmp, sizeof(tmp), ",%s",
 | 
						|
				 pim_reg_state2brief_str(up->reg_state, tmp_str,
 | 
						|
							 sizeof(tmp_str)));
 | 
						|
			strlcat(state_str, tmp, sizeof(state_str));
 | 
						|
		}
 | 
						|
 | 
						|
		if (json) {
 | 
						|
			char grp_str[PIM_ADDRSTRLEN];
 | 
						|
			char src_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
			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_pim_upstream_add(json_row, up);
 | 
						|
			json_object_string_add(
 | 
						|
				json_row, "inboundInterface",
 | 
						|
				up->rpf.source_nexthop.interface
 | 
						|
				? up->rpf.source_nexthop.interface->name
 | 
						|
				: "Unknown");
 | 
						|
 | 
						|
			/*
 | 
						|
			 * The RPF address we use is slightly different
 | 
						|
			 * based upon what we are looking up.
 | 
						|
			 * If we have a S, list that unless
 | 
						|
			 * we are the FHR, else we just put
 | 
						|
			 * the RP as the rpfAddress
 | 
						|
			 */
 | 
						|
			if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR ||
 | 
						|
			    pim_addr_is_any(up->sg.src)) {
 | 
						|
				struct pim_rpf *rpg;
 | 
						|
 | 
						|
				rpg = RP(pim, up->sg.grp);
 | 
						|
				json_object_string_addf(json_row, "rpfAddress",
 | 
						|
							"%pPA", &rpg->rpf_addr);
 | 
						|
			} else {
 | 
						|
				json_object_string_add(json_row, "rpfAddress",
 | 
						|
						       src_str);
 | 
						|
			}
 | 
						|
 | 
						|
			json_object_string_add(json_row, "source", src_str);
 | 
						|
			json_object_string_add(json_row, "group", grp_str);
 | 
						|
			json_object_string_add(json_row, "state", state_str);
 | 
						|
			json_object_string_add(
 | 
						|
				json_row, "joinState",
 | 
						|
				pim_upstream_state2str(up->join_state));
 | 
						|
			json_object_string_add(
 | 
						|
				json_row, "regState",
 | 
						|
				pim_reg_state2str(up->reg_state, state_str,
 | 
						|
						  sizeof(state_str)));
 | 
						|
			json_object_string_add(json_row, "upTime", uptime);
 | 
						|
			json_object_string_add(json_row, "joinTimer",
 | 
						|
					       join_timer);
 | 
						|
			json_object_string_add(json_row, "resetTimer",
 | 
						|
					       rs_timer);
 | 
						|
			json_object_string_add(json_row, "keepaliveTimer",
 | 
						|
					       ka_timer);
 | 
						|
			json_object_string_add(json_row, "msdpRegTimer",
 | 
						|
					       msdp_reg_timer);
 | 
						|
			json_object_int_add(json_row, "refCount",
 | 
						|
					    up->ref_count);
 | 
						|
			json_object_int_add(json_row, "sptBit", up->sptbit);
 | 
						|
			json_object_object_add(json_group, src_str, json_row);
 | 
						|
		} else {
 | 
						|
			ttable_add_row(tt,
 | 
						|
				"%s|%pPAs|%pPAs|%s|%s|%s|%s|%s|%d",
 | 
						|
				up->rpf.source_nexthop.interface
 | 
						|
				? up->rpf.source_nexthop.interface->name
 | 
						|
				: "Unknown",
 | 
						|
				&up->sg.src, &up->sg.grp, state_str, uptime,
 | 
						|
				join_timer, rs_timer, ka_timer, up->ref_count);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void pim_show_join_desired_helper(struct pim_instance *pim,
 | 
						|
					 struct vty *vty,
 | 
						|
					 struct pim_upstream *up,
 | 
						|
					 json_object *json, bool uj,
 | 
						|
					 struct ttable *tt)
 | 
						|
{
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		char grp_str[PIM_ADDRSTRLEN];
 | 
						|
		char src_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
		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_pim_upstream_add(json_row, up);
 | 
						|
		json_object_string_add(json_row, "source", src_str);
 | 
						|
		json_object_string_add(json_row, "group", grp_str);
 | 
						|
 | 
						|
		if (pim_upstream_evaluate_join_desired(pim, up))
 | 
						|
			json_object_boolean_true_add(json_row,
 | 
						|
						     "evaluateJoinDesired");
 | 
						|
 | 
						|
		json_object_object_add(json_group, src_str, json_row);
 | 
						|
 | 
						|
	} else {
 | 
						|
		ttable_add_row(tt, "%pPAs|%pPAs|%s", &up->sg.src, &up->sg.grp,
 | 
						|
			       pim_upstream_evaluate_join_desired(pim, up)
 | 
						|
				       ? "yes"
 | 
						|
				       : "no");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_upstream *up;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
 | 
						|
	json_object *json = NULL;
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		json = json_object_new_object();
 | 
						|
	else {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(tt, "Source|Group|EvalJD");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	frr_each (rb_pim_upstream, &pim->upstream_head, up) {
 | 
						|
		/* scan all interfaces */
 | 
						|
		pim_show_join_desired_helper(pim, vty, up, json, uj, tt);
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
	else {
 | 
						|
		/* Dump the generated table. */
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_upstream *up;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
	json_object *json = NULL;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		json = json_object_new_object();
 | 
						|
	else {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(tt,
 | 
						|
			       "Source|Group|RpfIface|RibNextHop|RpfAddress");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	frr_each (rb_pim_upstream, &pim->upstream_head, up) {
 | 
						|
		struct pim_rpf *rpf;
 | 
						|
		const char *rpf_ifname;
 | 
						|
 | 
						|
		rpf = &up->rpf;
 | 
						|
 | 
						|
		rpf_ifname =
 | 
						|
			rpf->source_nexthop.interface ? rpf->source_nexthop
 | 
						|
								.interface->name
 | 
						|
						      : "<ifname?>";
 | 
						|
 | 
						|
		if (uj) {
 | 
						|
			char grp_str[PIM_ADDRSTRLEN];
 | 
						|
			char src_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
			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_pim_upstream_add(json_row, up);
 | 
						|
			json_object_string_add(json_row, "source", src_str);
 | 
						|
			json_object_string_add(json_row, "group", grp_str);
 | 
						|
			json_object_string_add(json_row, "rpfInterface",
 | 
						|
					       rpf_ifname);
 | 
						|
			json_object_string_addf(
 | 
						|
				json_row, "ribNexthop", "%pPAs",
 | 
						|
				&rpf->source_nexthop.mrib_nexthop_addr);
 | 
						|
			json_object_string_addf(json_row, "rpfAddress", "%pPA",
 | 
						|
						&rpf->rpf_addr);
 | 
						|
			json_object_object_add(json_group, src_str, json_row);
 | 
						|
		} else {
 | 
						|
			ttable_add_row(tt, "%pPAs|%pPAs|%s|%pPA|%pPA",
 | 
						|
				       &up->sg.src, &up->sg.grp, rpf_ifname,
 | 
						|
				       &rpf->source_nexthop.mrib_nexthop_addr,
 | 
						|
				       &rpf->rpf_addr);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
	else {
 | 
						|
		/* Dump the generated table. */
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void pim_show_join_helper(struct pim_interface *pim_ifp,
 | 
						|
				 struct pim_ifchannel *ch, json_object *json,
 | 
						|
				 time_t now, struct ttable *tt)
 | 
						|
{
 | 
						|
	json_object *json_iface = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
	json_object *json_grp = NULL;
 | 
						|
	pim_addr ifaddr;
 | 
						|
	char uptime[10];
 | 
						|
	char expire[10];
 | 
						|
	char prune[10];
 | 
						|
 | 
						|
	ifaddr = pim_ifp->primary_address;
 | 
						|
 | 
						|
	pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation);
 | 
						|
	pim_time_timer_to_mmss(expire, sizeof(expire),
 | 
						|
			       ch->t_ifjoin_expiry_timer);
 | 
						|
	pim_time_timer_to_mmss(prune, sizeof(prune),
 | 
						|
			       ch->t_ifjoin_prune_pending_timer);
 | 
						|
 | 
						|
	if (json) {
 | 
						|
		char ch_grp_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
		json_object_object_get_ex(json, ch->interface->name,
 | 
						|
					  &json_iface);
 | 
						|
 | 
						|
		if (!json_iface) {
 | 
						|
			json_iface = json_object_new_object();
 | 
						|
			json_object_pim_ifp_add(json_iface, ch->interface);
 | 
						|
			json_object_object_add(json, ch->interface->name,
 | 
						|
					       json_iface);
 | 
						|
		}
 | 
						|
 | 
						|
		json_row = json_object_new_object();
 | 
						|
		json_object_string_addf(json_row, "source", "%pPAs",
 | 
						|
					&ch->sg.src);
 | 
						|
		json_object_string_addf(json_row, "group", "%pPAs",
 | 
						|
					&ch->sg.grp);
 | 
						|
		json_object_string_add(json_row, "upTime", uptime);
 | 
						|
		json_object_string_add(json_row, "expire", expire);
 | 
						|
		json_object_string_add(json_row, "prune", prune);
 | 
						|
		json_object_string_add(
 | 
						|
			json_row, "channelJoinName",
 | 
						|
			pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
 | 
						|
		if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
 | 
						|
			json_object_int_add(json_row, "sgRpt", 1);
 | 
						|
		if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
 | 
						|
			json_object_int_add(json_row, "protocolPim", 1);
 | 
						|
		if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
 | 
						|
			json_object_int_add(json_row, "protocolIgmp", 1);
 | 
						|
		snprintfrr(ch_grp_str, sizeof(ch_grp_str), "%pPAs",
 | 
						|
			   &ch->sg.grp);
 | 
						|
		json_object_object_get_ex(json_iface, ch_grp_str, &json_grp);
 | 
						|
		if (!json_grp) {
 | 
						|
			json_grp = json_object_new_object();
 | 
						|
			json_object_object_addf(json_grp, json_row, "%pPAs",
 | 
						|
						&ch->sg.src);
 | 
						|
			json_object_object_addf(json_iface, json_grp, "%pPAs",
 | 
						|
						&ch->sg.grp);
 | 
						|
		} else
 | 
						|
			json_object_object_addf(json_grp, json_row, "%pPAs",
 | 
						|
						&ch->sg.src);
 | 
						|
	} else {
 | 
						|
		ttable_add_row(
 | 
						|
			tt, "%s|%pPAs|%pPAs|%pPAs|%s|%s|%s|%s",
 | 
						|
			ch->interface->name, &ifaddr, &ch->sg.src, &ch->sg.grp,
 | 
						|
			pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
 | 
						|
			uptime, expire, prune);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_join_cmd_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
 | 
						|
			     pim_addr g, const char *json)
 | 
						|
{
 | 
						|
	pim_sgaddr sg = {};
 | 
						|
	struct vrf *v;
 | 
						|
	struct pim_instance *pim;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v) {
 | 
						|
		vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!pim_addr_is_any(s_or_g)) {
 | 
						|
		if (!pim_addr_is_any(g)) {
 | 
						|
			sg.src = s_or_g;
 | 
						|
			sg.grp = g;
 | 
						|
		} else
 | 
						|
			sg.grp = s_or_g;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	pim_show_join(pim, vty, &sg, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_join_vrf_all_cmd_helper(struct vty *vty, const char *json)
 | 
						|
{
 | 
						|
	pim_sgaddr sg = {0};
 | 
						|
	struct vrf *vrf_struct;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf_struct, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json_parent)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf_struct->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
		pim_show_join(vrf_struct->info, vty, &sg, json_vrf);
 | 
						|
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf_struct->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_WARNING;
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_join(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
 | 
						|
		   json_object *json)
 | 
						|
{
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct pim_ifchannel *ch;
 | 
						|
	struct interface *ifp;
 | 
						|
	time_t now;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
 | 
						|
	now = pim_time_monotonic_sec();
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(
 | 
						|
			tt,
 | 
						|
			"Interface|Address|Source|Group|State|Uptime|Expire|Prune");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	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 (!pim_sgaddr_match(ch->sg, *sg))
 | 
						|
				continue;
 | 
						|
 | 
						|
			pim_show_join_helper(pim_ifp, ch, json, now, tt);
 | 
						|
		} /* scan interface channels */
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void pim_show_jp_agg_helper(struct interface *ifp,
 | 
						|
				   struct pim_neighbor *neigh,
 | 
						|
				   struct pim_upstream *up, int is_join,
 | 
						|
				   struct ttable *tt)
 | 
						|
{
 | 
						|
	ttable_add_row(tt, "%s|%pPAs|%pPAs|%pPAs|%s", ifp->name,
 | 
						|
		       &neigh->source_addr, &up->sg.src, &up->sg.grp,
 | 
						|
		       is_join ? "J" : "P");
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_jp_agg_list_cmd_helper(const char *vrf, struct vty *vty)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
	struct pim_instance *pim;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v) {
 | 
						|
		vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_jp_agg_list(pim, vty);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
 | 
						|
{
 | 
						|
	struct interface *ifp;
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct listnode *n_node;
 | 
						|
	struct pim_neighbor *neigh;
 | 
						|
	struct listnode *jag_node;
 | 
						|
	struct pim_jp_agg_group *jag;
 | 
						|
	struct listnode *js_node;
 | 
						|
	struct pim_jp_sources *js;
 | 
						|
	struct ttable *tt;
 | 
						|
	char *table;
 | 
						|
 | 
						|
	/* Prepare table. */
 | 
						|
	tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
	ttable_add_row(tt, "Interface|RPF Nbr|Source|Group|State");
 | 
						|
	tt->style.cell.rpad = 2;
 | 
						|
	tt->style.corner = '+';
 | 
						|
	ttable_restyle(tt);
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, n_node,
 | 
						|
					  neigh)) {
 | 
						|
			for (ALL_LIST_ELEMENTS_RO(neigh->upstream_jp_agg,
 | 
						|
						  jag_node, jag)) {
 | 
						|
				for (ALL_LIST_ELEMENTS_RO(jag->sources, js_node,
 | 
						|
							  js)) {
 | 
						|
					pim_show_jp_agg_helper(ifp, neigh,
 | 
						|
							       js->up,
 | 
						|
							       js->is_join, tt);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Dump the generated table. */
 | 
						|
	table = ttable_dump(tt, "\n");
 | 
						|
	vty_out(vty, "%s\n", table);
 | 
						|
	XFREE(MTYPE_TMP, table);
 | 
						|
	ttable_del(tt);
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_membership_cmd_helper(const char *vrf, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim_show_membership(v->info, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static void pim_show_membership_helper(struct vty *vty,
 | 
						|
				       struct pim_interface *pim_ifp,
 | 
						|
				       struct pim_ifchannel *ch,
 | 
						|
				       struct json_object *json)
 | 
						|
{
 | 
						|
	json_object *json_iface = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	json_object_object_get_ex(json, ch->interface->name, &json_iface);
 | 
						|
	if (!json_iface) {
 | 
						|
		json_iface = json_object_new_object();
 | 
						|
		json_object_pim_ifp_add(json_iface, ch->interface);
 | 
						|
		json_object_object_add(json, ch->interface->name, json_iface);
 | 
						|
	}
 | 
						|
 | 
						|
	json_row = json_object_new_object();
 | 
						|
	json_object_string_addf(json_row, "source", "%pPAs", &ch->sg.src);
 | 
						|
	json_object_string_addf(json_row, "group", "%pPAs", &ch->sg.grp);
 | 
						|
	json_object_string_add(json_row, "localMembership",
 | 
						|
			       ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
 | 
						|
				       ? "NOINFO"
 | 
						|
				       : "INCLUDE");
 | 
						|
	json_object_object_addf(json_iface, json_row, "%pPAs", &ch->sg.grp);
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct pim_ifchannel *ch;
 | 
						|
	struct interface *ifp;
 | 
						|
	enum json_type type;
 | 
						|
	json_object *json = NULL;
 | 
						|
	json_object *json_tmp = NULL;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
 | 
						|
	json = json_object_new_object();
 | 
						|
 | 
						|
	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_membership_helper(vty, pim_ifp, ch, json);
 | 
						|
		} /* scan interface channels */
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		vty_json(vty, json);
 | 
						|
	} else {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(tt, "Interface|Address|Source|Group|Membership");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
 | 
						|
		/*
 | 
						|
		 * Example of the json data we are traversing
 | 
						|
		 *
 | 
						|
		 * {
 | 
						|
		 *   "swp3":{
 | 
						|
		 *     "name":"swp3",
 | 
						|
		 *     "state":"up",
 | 
						|
		 *     "address":"10.1.20.1",
 | 
						|
		 *     "index":5,
 | 
						|
		 *     "flagMulticast":true,
 | 
						|
		 *     "flagBroadcast":true,
 | 
						|
		 *     "lanDelayEnabled":true,
 | 
						|
		 *     "226.10.10.10":{
 | 
						|
		 *       "source":"*",
 | 
						|
		 *       "group":"226.10.10.10",
 | 
						|
		 *       "localMembership":"INCLUDE"
 | 
						|
		 *     }
 | 
						|
		 *   }
 | 
						|
		 * }
 | 
						|
		 */
 | 
						|
 | 
						|
		/* foreach interface */
 | 
						|
		json_object_object_foreach(json, key, val)
 | 
						|
		{
 | 
						|
 | 
						|
			/* Find all of the keys where the val is an object. In
 | 
						|
			 * the example
 | 
						|
			 * above the only one is 226.10.10.10
 | 
						|
			 */
 | 
						|
			json_object_object_foreach(val, if_field_key,
 | 
						|
						   if_field_val)
 | 
						|
			{
 | 
						|
				type = json_object_get_type(if_field_val);
 | 
						|
 | 
						|
				if (type == json_type_object) {
 | 
						|
					const char *address, *source,
 | 
						|
						*localMembership;
 | 
						|
 | 
						|
					json_object_object_get_ex(
 | 
						|
						val, "address", &json_tmp);
 | 
						|
					address = json_object_get_string(
 | 
						|
						json_tmp);
 | 
						|
 | 
						|
					json_object_object_get_ex(if_field_val,
 | 
						|
								  "source",
 | 
						|
								  &json_tmp);
 | 
						|
					source = json_object_get_string(
 | 
						|
						json_tmp);
 | 
						|
 | 
						|
					json_object_object_get_ex(
 | 
						|
						if_field_val, "localMembership",
 | 
						|
						&json_tmp);
 | 
						|
					localMembership =
 | 
						|
						json_object_get_string(
 | 
						|
							json_tmp);
 | 
						|
 | 
						|
					ttable_add_row(tt, "%s|%s|%s|%s|%s",
 | 
						|
						       key, address, source,
 | 
						|
						       if_field_key,
 | 
						|
						       localMembership);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		json_object_free(json);
 | 
						|
		/* Dump the generated table. */
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void pim_show_channel_helper(struct pim_instance *pim,
 | 
						|
				    struct pim_interface *pim_ifp,
 | 
						|
				    struct pim_ifchannel *ch, json_object *json,
 | 
						|
				    bool uj, struct ttable *tt)
 | 
						|
{
 | 
						|
	struct pim_upstream *up = ch->upstream;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		char grp_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
		snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
 | 
						|
		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_pim_upstream_add(json_row, up);
 | 
						|
		json_object_string_add(json_row, "interface",
 | 
						|
				       ch->interface->name);
 | 
						|
		json_object_string_addf(json_row, "source", "%pPAs",
 | 
						|
					&up->sg.src);
 | 
						|
		json_object_string_addf(json_row, "group", "%pPAs",
 | 
						|
					&up->sg.grp);
 | 
						|
 | 
						|
		if (pim_macro_ch_lost_assert(ch))
 | 
						|
			json_object_boolean_true_add(json_row, "lostAssert");
 | 
						|
 | 
						|
		if (pim_macro_chisin_joins(ch))
 | 
						|
			json_object_boolean_true_add(json_row, "joins");
 | 
						|
 | 
						|
		if (pim_macro_chisin_pim_include(ch))
 | 
						|
			json_object_boolean_true_add(json_row, "pimInclude");
 | 
						|
 | 
						|
		if (pim_upstream_evaluate_join_desired(pim, up))
 | 
						|
			json_object_boolean_true_add(json_row,
 | 
						|
						     "evaluateJoinDesired");
 | 
						|
 | 
						|
		json_object_object_addf(json_group, json_row, "%pPAs",
 | 
						|
					&up->sg.src);
 | 
						|
 | 
						|
	} else {
 | 
						|
		ttable_add_row(tt, "%s|%pPAs|%pPAs|%s|%s|%s|%s|%s",
 | 
						|
			       ch->interface->name, &up->sg.src, &up->sg.grp,
 | 
						|
			       pim_macro_ch_lost_assert(ch) ? "yes" : "no",
 | 
						|
			       pim_macro_chisin_joins(ch) ? "yes" : "no",
 | 
						|
			       pim_macro_chisin_pim_include(ch) ? "yes" : "no",
 | 
						|
			       PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags)
 | 
						|
				       ? "yes"
 | 
						|
				       : "no",
 | 
						|
			       pim_upstream_evaluate_join_desired(pim, up)
 | 
						|
				       ? "yes"
 | 
						|
				       : "no");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_channel(struct pim_instance *pim, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct pim_ifchannel *ch;
 | 
						|
	struct interface *ifp;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	json_object *json = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		json = json_object_new_object();
 | 
						|
	else {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(
 | 
						|
			tt,
 | 
						|
			"Interface|Source|Group|LostAssert|Joins|PimInclude|JoinDesired|EvalJD");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	/* scan per-interface (S,G) state */
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
 | 
						|
			/* scan all interfaces */
 | 
						|
			pim_show_channel_helper(pim, pim_ifp, ch, json, uj, tt);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
	else {
 | 
						|
		/* Dump the generated table. */
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_channel_cmd_helper(const char *vrf, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim_show_channel(v->info, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_interface_cmd_helper(const char *vrf, struct vty *vty, bool uj,
 | 
						|
				  bool mlag, const char *interface)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	if (interface)
 | 
						|
		pim_show_interfaces_single(v->info, vty, interface, mlag,
 | 
						|
					   json_parent);
 | 
						|
	else
 | 
						|
		pim_show_interfaces(v->info, vty, mlag, json_parent);
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_interface_vrf_all_cmd_helper(struct vty *vty, bool uj, bool mlag,
 | 
						|
					  const char *interface)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (v, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!uj)
 | 
						|
			vty_out(vty, "VRF: %s\n", v->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
 | 
						|
		if (interface)
 | 
						|
			pim_show_interfaces_single(v->info, vty, interface,
 | 
						|
						   mlag, json_vrf);
 | 
						|
		else
 | 
						|
			pim_show_interfaces(v->info, vty, mlag, json_vrf);
 | 
						|
 | 
						|
		if (uj)
 | 
						|
			json_object_object_add(json_parent, v->name, json_vrf);
 | 
						|
	}
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, bool mlag,
 | 
						|
			 json_object *json)
 | 
						|
{
 | 
						|
	struct interface *ifp;
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct pim_upstream *up;
 | 
						|
	int fhr = 0;
 | 
						|
	int pim_nbrs = 0;
 | 
						|
	int pim_ifchannels = 0;
 | 
						|
	bool uj = true;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
	json_object *json_tmp;
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		uj = false;
 | 
						|
		json = json_object_new_object();
 | 
						|
	}
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (mlag == true && pim_ifp->activeactive == false)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pim_nbrs = pim_ifp->pim_neighbor_list->count;
 | 
						|
		pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
 | 
						|
		fhr = 0;
 | 
						|
 | 
						|
		frr_each (rb_pim_upstream, &pim->upstream_head, up)
 | 
						|
			if (ifp == up->rpf.source_nexthop.interface)
 | 
						|
				if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
 | 
						|
					fhr++;
 | 
						|
 | 
						|
		json_row = json_object_new_object();
 | 
						|
		json_object_pim_ifp_add(json_row, ifp);
 | 
						|
		json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
 | 
						|
		json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
 | 
						|
		json_object_int_add(json_row, "firstHopRouterCount", fhr);
 | 
						|
		json_object_string_addf(json_row, "pimDesignatedRouter",
 | 
						|
					"%pPAs", &pim_ifp->pim_dr_addr);
 | 
						|
 | 
						|
		if (!pim_addr_cmp(pim_ifp->pim_dr_addr,
 | 
						|
				  pim_ifp->primary_address))
 | 
						|
			json_object_boolean_true_add(
 | 
						|
				json_row, "pimDesignatedRouterLocal");
 | 
						|
 | 
						|
		json_object_object_add(json, ifp->name, json_row);
 | 
						|
	}
 | 
						|
 | 
						|
	if (!uj) {
 | 
						|
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(
 | 
						|
			tt,
 | 
						|
			"Interface|State|Address|PIM Nbrs|PIM DR|FHR|IfChannels");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
 | 
						|
		json_object_object_foreach(json, key, val)
 | 
						|
		{
 | 
						|
			const char *state, *address, *pimdr;
 | 
						|
			int neighbors, firsthpr, pimifchnl;
 | 
						|
 | 
						|
			json_object_object_get_ex(val, "state", &json_tmp);
 | 
						|
			state = json_object_get_string(json_tmp);
 | 
						|
 | 
						|
			json_object_object_get_ex(val, "address", &json_tmp);
 | 
						|
			address = json_object_get_string(json_tmp);
 | 
						|
 | 
						|
			json_object_object_get_ex(val, "pimNeighbors",
 | 
						|
						  &json_tmp);
 | 
						|
			neighbors = json_object_get_int(json_tmp);
 | 
						|
 | 
						|
			if (json_object_object_get_ex(
 | 
						|
				    val, "pimDesignatedRouterLocal",
 | 
						|
				    &json_tmp)) {
 | 
						|
				pimdr = "local";
 | 
						|
			} else {
 | 
						|
				json_object_object_get_ex(
 | 
						|
					val, "pimDesignatedRouter", &json_tmp);
 | 
						|
				pimdr = json_object_get_string(json_tmp);
 | 
						|
			}
 | 
						|
 | 
						|
			json_object_object_get_ex(val, "firstHopRouter",
 | 
						|
						  &json_tmp);
 | 
						|
			firsthpr = json_object_get_int(json_tmp);
 | 
						|
 | 
						|
			json_object_object_get_ex(val, "pimIfChannels",
 | 
						|
						  &json_tmp);
 | 
						|
			pimifchnl = json_object_get_int(json_tmp);
 | 
						|
 | 
						|
			ttable_add_row(tt, "%s|%s|%s|%d|%s|%d|%d", key, state,
 | 
						|
				       address, neighbors, pimdr, firsthpr,
 | 
						|
				       pimifchnl);
 | 
						|
		}
 | 
						|
		json_object_free(json);
 | 
						|
 | 
						|
		/* Dump the generated table. */
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_interfaces_single(struct pim_instance *pim, struct vty *vty,
 | 
						|
				const char *ifname, bool mlag,
 | 
						|
				json_object *json)
 | 
						|
{
 | 
						|
	pim_addr ifaddr;
 | 
						|
	struct interface *ifp;
 | 
						|
	struct listnode *neighnode;
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct pim_neighbor *neigh;
 | 
						|
	struct pim_upstream *up;
 | 
						|
	time_t now;
 | 
						|
	char dr_str[PIM_ADDRSTRLEN];
 | 
						|
	char dr_uptime[10];
 | 
						|
	char expire[10];
 | 
						|
	char grp_str[PIM_ADDRSTRLEN];
 | 
						|
	char hello_period[10];
 | 
						|
	char hello_timer[10];
 | 
						|
	char neigh_src_str[PIM_ADDRSTRLEN];
 | 
						|
	char src_str[PIM_ADDRSTRLEN];
 | 
						|
	char stat_uptime[10];
 | 
						|
	char uptime[10];
 | 
						|
	int found_ifname = 0;
 | 
						|
	int print_header;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
	json_object *json_pim_neighbor = NULL;
 | 
						|
	json_object *json_pim_neighbors = NULL;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_group_source = NULL;
 | 
						|
	json_object *json_fhr_sources = NULL;
 | 
						|
	struct pim_secondary_addr *sec_addr;
 | 
						|
	struct listnode *sec_node;
 | 
						|
 | 
						|
	now = pim_time_monotonic_sec();
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (mlag == true && pim_ifp->activeactive == false)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
 | 
						|
			continue;
 | 
						|
 | 
						|
		found_ifname = 1;
 | 
						|
		ifaddr = pim_ifp->primary_address;
 | 
						|
		snprintfrr(dr_str, sizeof(dr_str), "%pPAs",
 | 
						|
			   &pim_ifp->pim_dr_addr);
 | 
						|
		pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now,
 | 
						|
				      pim_ifp->pim_dr_election_last);
 | 
						|
		pim_time_timer_to_hhmmss(hello_timer, sizeof(hello_timer),
 | 
						|
					 pim_ifp->t_pim_hello_timer);
 | 
						|
		pim_time_mmss(hello_period, sizeof(hello_period),
 | 
						|
			      pim_ifp->pim_hello_period);
 | 
						|
		pim_time_uptime(stat_uptime, sizeof(stat_uptime),
 | 
						|
				now - pim_ifp->pim_ifstat_start);
 | 
						|
 | 
						|
		if (json) {
 | 
						|
			json_row = json_object_new_object();
 | 
						|
			json_object_pim_ifp_add(json_row, ifp);
 | 
						|
 | 
						|
			if (!pim_addr_is_any(pim_ifp->update_source)) {
 | 
						|
				json_object_string_addf(
 | 
						|
					json_row, "useSource", "%pPAs",
 | 
						|
					&pim_ifp->update_source);
 | 
						|
			}
 | 
						|
			if (pim_ifp->sec_addr_list) {
 | 
						|
				json_object *sec_list = NULL;
 | 
						|
 | 
						|
				sec_list = json_object_new_array();
 | 
						|
				for (ALL_LIST_ELEMENTS_RO(
 | 
						|
					     pim_ifp->sec_addr_list, sec_node,
 | 
						|
					     sec_addr)) {
 | 
						|
					json_object_array_add(
 | 
						|
						sec_list,
 | 
						|
						json_object_new_stringf(
 | 
						|
							"%pFXh",
 | 
						|
							&sec_addr->addr));
 | 
						|
				}
 | 
						|
				json_object_object_add(json_row,
 | 
						|
						       "secondaryAddressList",
 | 
						|
						       sec_list);
 | 
						|
			}
 | 
						|
 | 
						|
			if (pim_ifp->pim_passive_enable)
 | 
						|
				json_object_boolean_true_add(json_row,
 | 
						|
							     "passive");
 | 
						|
 | 
						|
			/* PIM neighbors */
 | 
						|
			if (pim_ifp->pim_neighbor_list->count) {
 | 
						|
				json_pim_neighbors = json_object_new_object();
 | 
						|
 | 
						|
				for (ALL_LIST_ELEMENTS_RO(
 | 
						|
					     pim_ifp->pim_neighbor_list,
 | 
						|
					     neighnode, neigh)) {
 | 
						|
					json_pim_neighbor =
 | 
						|
						json_object_new_object();
 | 
						|
					snprintfrr(neigh_src_str,
 | 
						|
						   sizeof(neigh_src_str),
 | 
						|
						   "%pPAs",
 | 
						|
						   &neigh->source_addr);
 | 
						|
					pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
							now - neigh->creation);
 | 
						|
					pim_time_timer_to_hhmmss(
 | 
						|
						expire, sizeof(expire),
 | 
						|
						neigh->t_expire_timer);
 | 
						|
 | 
						|
					json_object_string_add(
 | 
						|
						json_pim_neighbor, "address",
 | 
						|
						neigh_src_str);
 | 
						|
					json_object_string_add(
 | 
						|
						json_pim_neighbor, "upTime",
 | 
						|
						uptime);
 | 
						|
					json_object_string_add(
 | 
						|
						json_pim_neighbor, "holdtime",
 | 
						|
						expire);
 | 
						|
 | 
						|
					json_object_object_add(
 | 
						|
						json_pim_neighbors,
 | 
						|
						neigh_src_str,
 | 
						|
						json_pim_neighbor);
 | 
						|
				}
 | 
						|
 | 
						|
				json_object_object_add(json_row, "neighbors",
 | 
						|
						       json_pim_neighbors);
 | 
						|
			}
 | 
						|
 | 
						|
			json_object_string_add(json_row, "drAddress", dr_str);
 | 
						|
			json_object_int_add(json_row, "drPriority",
 | 
						|
					    pim_ifp->pim_dr_priority);
 | 
						|
			json_object_string_add(json_row, "drUptime", dr_uptime);
 | 
						|
			json_object_int_add(json_row, "drElections",
 | 
						|
					    pim_ifp->pim_dr_election_count);
 | 
						|
			json_object_int_add(json_row, "drChanges",
 | 
						|
					    pim_ifp->pim_dr_election_changes);
 | 
						|
 | 
						|
			/* FHR */
 | 
						|
			frr_each (rb_pim_upstream, &pim->upstream_head, up) {
 | 
						|
				if (ifp != up->rpf.source_nexthop.interface)
 | 
						|
					continue;
 | 
						|
 | 
						|
				if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
 | 
						|
					continue;
 | 
						|
 | 
						|
				if (!json_fhr_sources)
 | 
						|
					json_fhr_sources =
 | 
						|
						json_object_new_object();
 | 
						|
 | 
						|
				snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
 | 
						|
					   &up->sg.grp);
 | 
						|
				snprintfrr(src_str, sizeof(src_str), "%pPAs",
 | 
						|
					   &up->sg.src);
 | 
						|
				pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
						now - up->state_transition);
 | 
						|
 | 
						|
				/*
 | 
						|
				 * Does this group live in json_fhr_sources?
 | 
						|
				 * If not create it.
 | 
						|
				 */
 | 
						|
				json_object_object_get_ex(json_fhr_sources,
 | 
						|
							  grp_str, &json_group);
 | 
						|
 | 
						|
				if (!json_group) {
 | 
						|
					json_group = json_object_new_object();
 | 
						|
					json_object_object_add(json_fhr_sources,
 | 
						|
							       grp_str,
 | 
						|
							       json_group);
 | 
						|
				}
 | 
						|
 | 
						|
				json_group_source = json_object_new_object();
 | 
						|
				json_object_string_add(json_group_source,
 | 
						|
						       "source", src_str);
 | 
						|
				json_object_string_add(json_group_source,
 | 
						|
						       "group", grp_str);
 | 
						|
				json_object_string_add(json_group_source,
 | 
						|
						       "upTime", uptime);
 | 
						|
				json_object_object_add(json_group, src_str,
 | 
						|
						       json_group_source);
 | 
						|
			}
 | 
						|
 | 
						|
			if (json_fhr_sources) {
 | 
						|
				json_object_object_add(json_row,
 | 
						|
						       "firstHopRouter",
 | 
						|
						       json_fhr_sources);
 | 
						|
			}
 | 
						|
 | 
						|
			json_object_int_add(json_row, "helloPeriod",
 | 
						|
					    pim_ifp->pim_hello_period);
 | 
						|
			json_object_int_add(json_row, "holdTime",
 | 
						|
					    PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
 | 
						|
			json_object_string_add(json_row, "helloTimer",
 | 
						|
					       hello_timer);
 | 
						|
			json_object_string_add(json_row, "helloStatStart",
 | 
						|
					       stat_uptime);
 | 
						|
			json_object_int_add(json_row, "helloReceived",
 | 
						|
					    pim_ifp->pim_ifstat_hello_recv);
 | 
						|
			json_object_int_add(json_row, "helloReceivedFailed",
 | 
						|
					    pim_ifp->pim_ifstat_hello_recvfail);
 | 
						|
			json_object_int_add(json_row, "helloSend",
 | 
						|
					    pim_ifp->pim_ifstat_hello_sent);
 | 
						|
			json_object_int_add(json_row, "hellosendFailed",
 | 
						|
					    pim_ifp->pim_ifstat_hello_sendfail);
 | 
						|
			json_object_int_add(json_row, "helloGenerationId",
 | 
						|
					    pim_ifp->pim_generation_id);
 | 
						|
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "effectivePropagationDelay",
 | 
						|
				pim_if_effective_propagation_delay_msec(ifp));
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "effectiveOverrideInterval",
 | 
						|
				pim_if_effective_override_interval_msec(ifp));
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "joinPruneOverrideInterval",
 | 
						|
				pim_if_jp_override_interval_msec(ifp));
 | 
						|
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "propagationDelay",
 | 
						|
				pim_ifp->pim_propagation_delay_msec);
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "propagationDelayHighest",
 | 
						|
				pim_ifp->pim_neighbors_highest_propagation_delay_msec);
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "overrideInterval",
 | 
						|
				pim_ifp->pim_override_interval_msec);
 | 
						|
			json_object_int_add(
 | 
						|
				json_row, "overrideIntervalHighest",
 | 
						|
				pim_ifp->pim_neighbors_highest_override_interval_msec);
 | 
						|
			if (pim_ifp->bsm_enable)
 | 
						|
				json_object_boolean_true_add(json_row,
 | 
						|
							     "bsmEnabled");
 | 
						|
			if (pim_ifp->ucast_bsm_accept)
 | 
						|
				json_object_boolean_true_add(json_row,
 | 
						|
							     "ucastBsmEnabled");
 | 
						|
			json_object_object_add(json, ifp->name, json_row);
 | 
						|
 | 
						|
		} else {
 | 
						|
			vty_out(vty, "Interface  : %s\n", ifp->name);
 | 
						|
			vty_out(vty, "State      : %s\n",
 | 
						|
				if_is_up(ifp) ? "up" : "down");
 | 
						|
			if (!pim_addr_is_any(pim_ifp->update_source)) {
 | 
						|
				vty_out(vty, "Use Source : %pPAs\n",
 | 
						|
					&pim_ifp->update_source);
 | 
						|
			}
 | 
						|
			if (pim_ifp->sec_addr_list) {
 | 
						|
				vty_out(vty, "Address    : %pPAs (primary)\n",
 | 
						|
					&ifaddr);
 | 
						|
				for (ALL_LIST_ELEMENTS_RO(
 | 
						|
					     pim_ifp->sec_addr_list, sec_node,
 | 
						|
					     sec_addr))
 | 
						|
					vty_out(vty, "             %pFX\n",
 | 
						|
						&sec_addr->addr);
 | 
						|
			} else {
 | 
						|
				vty_out(vty, "Address    : %pPAs\n", &ifaddr);
 | 
						|
			}
 | 
						|
 | 
						|
			if (pim_ifp->pim_passive_enable)
 | 
						|
				vty_out(vty, "Passive    : %s\n",
 | 
						|
					(pim_ifp->pim_passive_enable) ? "yes"
 | 
						|
								      : "no");
 | 
						|
 | 
						|
			vty_out(vty, "\n");
 | 
						|
 | 
						|
			/* PIM neighbors */
 | 
						|
			print_header = 1;
 | 
						|
 | 
						|
			for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
 | 
						|
						  neighnode, neigh)) {
 | 
						|
 | 
						|
				if (print_header) {
 | 
						|
					vty_out(vty, "PIM Neighbors\n");
 | 
						|
					vty_out(vty, "-------------\n");
 | 
						|
					print_header = 0;
 | 
						|
				}
 | 
						|
 | 
						|
				snprintfrr(neigh_src_str, sizeof(neigh_src_str),
 | 
						|
					   "%pPAs", &neigh->source_addr);
 | 
						|
				pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
						now - neigh->creation);
 | 
						|
				pim_time_timer_to_hhmmss(expire, sizeof(expire),
 | 
						|
							 neigh->t_expire_timer);
 | 
						|
				vty_out(vty,
 | 
						|
					"%-15s : up for %s, holdtime expires in %s\n",
 | 
						|
					neigh_src_str, uptime, expire);
 | 
						|
			}
 | 
						|
 | 
						|
			if (!print_header) {
 | 
						|
				vty_out(vty, "\n");
 | 
						|
				vty_out(vty, "\n");
 | 
						|
			}
 | 
						|
 | 
						|
			vty_out(vty, "Designated Router\n");
 | 
						|
			vty_out(vty, "-----------------\n");
 | 
						|
			vty_out(vty, "Address   : %s\n", dr_str);
 | 
						|
			vty_out(vty, "Priority  : %u(%d)\n",
 | 
						|
				pim_ifp->pim_dr_priority,
 | 
						|
				pim_ifp->pim_dr_num_nondrpri_neighbors);
 | 
						|
			vty_out(vty, "Uptime    : %s\n", dr_uptime);
 | 
						|
			vty_out(vty, "Elections : %d\n",
 | 
						|
				pim_ifp->pim_dr_election_count);
 | 
						|
			vty_out(vty, "Changes   : %d\n",
 | 
						|
				pim_ifp->pim_dr_election_changes);
 | 
						|
			vty_out(vty, "\n");
 | 
						|
			vty_out(vty, "\n");
 | 
						|
 | 
						|
			/* FHR */
 | 
						|
			print_header = 1;
 | 
						|
			frr_each (rb_pim_upstream, &pim->upstream_head, up) {
 | 
						|
				if (!up->rpf.source_nexthop.interface)
 | 
						|
					continue;
 | 
						|
 | 
						|
				if (strcmp(ifp->name,
 | 
						|
					   up->rpf.source_nexthop
 | 
						|
						   .interface->name) != 0)
 | 
						|
					continue;
 | 
						|
 | 
						|
				if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
 | 
						|
					continue;
 | 
						|
 | 
						|
				if (print_header) {
 | 
						|
					vty_out(vty,
 | 
						|
						"FHR - First Hop Router\n");
 | 
						|
					vty_out(vty,
 | 
						|
						"----------------------\n");
 | 
						|
					print_header = 0;
 | 
						|
				}
 | 
						|
 | 
						|
				pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
						now - up->state_transition);
 | 
						|
				vty_out(vty,
 | 
						|
					"%pPAs : %pPAs is a source, uptime is %s\n",
 | 
						|
					&up->sg.grp, &up->sg.src, uptime);
 | 
						|
			}
 | 
						|
 | 
						|
			if (!print_header) {
 | 
						|
				vty_out(vty, "\n");
 | 
						|
				vty_out(vty, "\n");
 | 
						|
			}
 | 
						|
 | 
						|
			vty_out(vty, "Hellos\n");
 | 
						|
			vty_out(vty, "------\n");
 | 
						|
			vty_out(vty, "Period         : %d\n",
 | 
						|
				pim_ifp->pim_hello_period);
 | 
						|
			vty_out(vty, "HoldTime       : %d\n",
 | 
						|
				PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
 | 
						|
			vty_out(vty, "Timer          : %s\n", hello_timer);
 | 
						|
			vty_out(vty, "StatStart      : %s\n", stat_uptime);
 | 
						|
			vty_out(vty, "Receive        : %d\n",
 | 
						|
				pim_ifp->pim_ifstat_hello_recv);
 | 
						|
			vty_out(vty, "Receive Failed : %d\n",
 | 
						|
				pim_ifp->pim_ifstat_hello_recvfail);
 | 
						|
			vty_out(vty, "Send           : %d\n",
 | 
						|
				pim_ifp->pim_ifstat_hello_sent);
 | 
						|
			vty_out(vty, "Send Failed    : %d\n",
 | 
						|
				pim_ifp->pim_ifstat_hello_sendfail);
 | 
						|
			vty_out(vty, "Generation ID  : %08x\n",
 | 
						|
				pim_ifp->pim_generation_id);
 | 
						|
			vty_out(vty, "\n");
 | 
						|
			vty_out(vty, "\n");
 | 
						|
 | 
						|
			pim_print_ifp_flags(vty, ifp);
 | 
						|
 | 
						|
			vty_out(vty, "Join Prune Interval\n");
 | 
						|
			vty_out(vty, "-------------------\n");
 | 
						|
			vty_out(vty, "LAN Delay                    : %s\n",
 | 
						|
				pim_if_lan_delay_enabled(ifp) ? "yes" : "no");
 | 
						|
			vty_out(vty, "Effective Propagation Delay  : %d msec\n",
 | 
						|
				pim_if_effective_propagation_delay_msec(ifp));
 | 
						|
			vty_out(vty, "Effective Override Interval  : %d msec\n",
 | 
						|
				pim_if_effective_override_interval_msec(ifp));
 | 
						|
			vty_out(vty, "Join Prune Override Interval : %d msec\n",
 | 
						|
				pim_if_jp_override_interval_msec(ifp));
 | 
						|
			vty_out(vty, "\n");
 | 
						|
			vty_out(vty, "\n");
 | 
						|
 | 
						|
			vty_out(vty, "LAN Prune Delay\n");
 | 
						|
			vty_out(vty, "---------------\n");
 | 
						|
			vty_out(vty, "Propagation Delay           : %d msec\n",
 | 
						|
				pim_ifp->pim_propagation_delay_msec);
 | 
						|
			vty_out(vty, "Propagation Delay (Highest) : %d msec\n",
 | 
						|
				pim_ifp->pim_neighbors_highest_propagation_delay_msec);
 | 
						|
			vty_out(vty, "Override Interval           : %d msec\n",
 | 
						|
				pim_ifp->pim_override_interval_msec);
 | 
						|
			vty_out(vty, "Override Interval (Highest) : %d msec\n",
 | 
						|
				pim_ifp->pim_neighbors_highest_override_interval_msec);
 | 
						|
			vty_out(vty, "\n");
 | 
						|
			vty_out(vty, "\n");
 | 
						|
 | 
						|
			vty_out(vty, "BSM Status\n");
 | 
						|
			vty_out(vty, "----------\n");
 | 
						|
			vty_out(vty, "Bsm Enabled          : %s\n",
 | 
						|
				pim_ifp->bsm_enable ? "yes" : "no");
 | 
						|
			vty_out(vty, "Unicast Bsm Enabled  : %s\n",
 | 
						|
				pim_ifp->ucast_bsm_accept ? "yes" : "no");
 | 
						|
			vty_out(vty, "\n");
 | 
						|
			vty_out(vty, "\n");
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!found_ifname)
 | 
						|
		vty_out(vty, "%% No such interface\n");
 | 
						|
}
 | 
						|
 | 
						|
void ip_pim_ssm_show_group_range(struct pim_instance *pim, struct vty *vty,
 | 
						|
				 bool uj)
 | 
						|
{
 | 
						|
	struct pim_ssm *ssm = pim->ssm_info;
 | 
						|
	const char *range_str =
 | 
						|
		ssm->plist_name ? ssm->plist_name : PIM_SSM_STANDARD_RANGE;
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		json_object *json;
 | 
						|
 | 
						|
		json = json_object_new_object();
 | 
						|
		json_object_string_add(json, "ssmGroups", range_str);
 | 
						|
		vty_json(vty, json);
 | 
						|
	} else
 | 
						|
		vty_out(vty, "SSM group range : %s\n", range_str);
 | 
						|
}
 | 
						|
 | 
						|
struct vty_pnc_cache_walk_data {
 | 
						|
	struct vty *vty;
 | 
						|
	struct pim_instance *pim;
 | 
						|
};
 | 
						|
 | 
						|
struct json_pnc_cache_walk_data {
 | 
						|
	json_object *json_obj;
 | 
						|
	struct pim_instance *pim;
 | 
						|
};
 | 
						|
 | 
						|
static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
 | 
						|
{
 | 
						|
	struct pim_nexthop_cache *pnc = bucket->data;
 | 
						|
	struct vty_pnc_cache_walk_data *cwd = arg;
 | 
						|
	struct vty *vty = cwd->vty;
 | 
						|
	struct pim_instance *pim = cwd->pim;
 | 
						|
	struct nexthop *nh_node = NULL;
 | 
						|
	ifindex_t first_ifindex;
 | 
						|
	struct interface *ifp = NULL;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
 | 
						|
	/* Prepare table. */
 | 
						|
	tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
	ttable_add_row(tt, "Address|Interface|Nexthop");
 | 
						|
	tt->style.cell.rpad = 2;
 | 
						|
	tt->style.corner = '+';
 | 
						|
	ttable_restyle(tt);
 | 
						|
 | 
						|
	for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
 | 
						|
		first_ifindex = nh_node->ifindex;
 | 
						|
 | 
						|
		ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
 | 
						|
 | 
						|
#if PIM_IPV == 4
 | 
						|
		ttable_add_row(tt, "%pPA|%s|%pI4", &pnc->rpf.rpf_addr,
 | 
						|
			       ifp ? ifp->name : "NULL", &nh_node->gate.ipv4);
 | 
						|
#else
 | 
						|
		ttable_add_row(tt, "%pPA|%s|%pI6", &pnc->rpf.rpf_addr,
 | 
						|
			       ifp ? ifp->name : "NULL", &nh_node->gate.ipv6);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	table = ttable_dump(tt, "\n");
 | 
						|
	vty_out(vty, "%s\n", table);
 | 
						|
	XFREE(MTYPE_TMP, table);
 | 
						|
	ttable_del(tt);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static int pim_print_json_pnc_cache_walkcb(struct hash_bucket *backet,
 | 
						|
					   void *arg)
 | 
						|
{
 | 
						|
	struct pim_nexthop_cache *pnc = backet->data;
 | 
						|
	struct json_pnc_cache_walk_data *cwd = arg;
 | 
						|
	struct pim_instance *pim = cwd->pim;
 | 
						|
	struct nexthop *nh_node = NULL;
 | 
						|
	ifindex_t first_ifindex;
 | 
						|
	struct interface *ifp = NULL;
 | 
						|
	char addr_str[PIM_ADDRSTRLEN];
 | 
						|
	json_object *json_row = NULL;
 | 
						|
	json_object *json_ifp = NULL;
 | 
						|
	json_object *json_arr = NULL;
 | 
						|
 | 
						|
	for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
 | 
						|
		first_ifindex = nh_node->ifindex;
 | 
						|
		ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
 | 
						|
		snprintfrr(addr_str, sizeof(addr_str), "%pPA",
 | 
						|
			   &pnc->rpf.rpf_addr);
 | 
						|
		json_object_object_get_ex(cwd->json_obj, addr_str, &json_row);
 | 
						|
		if (!json_row) {
 | 
						|
			json_row = json_object_new_object();
 | 
						|
			json_object_string_addf(json_row, "address", "%pPA",
 | 
						|
						&pnc->rpf.rpf_addr);
 | 
						|
			json_object_object_addf(cwd->json_obj, json_row, "%pPA",
 | 
						|
						&pnc->rpf.rpf_addr);
 | 
						|
			json_arr = json_object_new_array();
 | 
						|
			json_object_object_add(json_row, "nexthops", json_arr);
 | 
						|
		}
 | 
						|
		json_ifp = json_object_new_object();
 | 
						|
		json_object_string_add(json_ifp, "interface",
 | 
						|
				       ifp ? ifp->name : "NULL");
 | 
						|
#if PIM_IPV == 4
 | 
						|
		json_object_string_addf(json_ifp, "nexthop", "%pI4",
 | 
						|
					&nh_node->gate.ipv4);
 | 
						|
#else
 | 
						|
		json_object_string_addf(json_ifp, "nexthop", "%pI6",
 | 
						|
					&nh_node->gate.ipv6);
 | 
						|
#endif
 | 
						|
		json_object_array_add(json_arr, json_ifp);
 | 
						|
	}
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_nexthop_lookup_cmd_helper(const char *vrf, struct vty *vty,
 | 
						|
				       pim_addr source, pim_addr group)
 | 
						|
{
 | 
						|
	int result = 0;
 | 
						|
	pim_addr vif_source;
 | 
						|
	struct prefix grp;
 | 
						|
	struct pim_nexthop nexthop;
 | 
						|
	struct vrf *v;
 | 
						|
	char grp_str[PREFIX_STRLEN];
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
#if PIM_IPV == 4
 | 
						|
	if (pim_is_group_224_4(source)) {
 | 
						|
		vty_out(vty,
 | 
						|
			"Invalid argument. Expected Valid Source Address.\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!pim_is_group_224_4(group)) {
 | 
						|
		vty_out(vty,
 | 
						|
			"Invalid argument. Expected Valid Multicast Group Address.\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (!pim_rp_set_upstream_addr(v->info, &vif_source, source, group))
 | 
						|
		return CMD_SUCCESS;
 | 
						|
 | 
						|
	pim_addr_to_prefix(&grp, group);
 | 
						|
	memset(&nexthop, 0, sizeof(nexthop));
 | 
						|
 | 
						|
	result =
 | 
						|
		pim_ecmp_nexthop_lookup(v->info, &nexthop, vif_source, &grp, 0);
 | 
						|
 | 
						|
	if (!result) {
 | 
						|
		vty_out(vty,
 | 
						|
			"Nexthop Lookup failed, no usable routes returned.\n");
 | 
						|
		return CMD_SUCCESS;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_addr_dump("<grp?>", &grp, grp_str, sizeof(grp_str));
 | 
						|
 | 
						|
	vty_out(vty, "Group %s --- Nexthop %pPAs Interface %s\n", grp_str,
 | 
						|
		&nexthop.mrib_nexthop_addr, nexthop.interface->name);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim_show_nexthop(v->info, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct vty_pnc_cache_walk_data cwd;
 | 
						|
	struct json_pnc_cache_walk_data jcwd;
 | 
						|
 | 
						|
	cwd.vty = vty;
 | 
						|
	cwd.pim = pim;
 | 
						|
	jcwd.pim = pim;
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		jcwd.json_obj = json_object_new_object();
 | 
						|
	} else {
 | 
						|
		vty_out(vty, "Number of registered addresses: %lu\n",
 | 
						|
			pim->rpf_hash->count);
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		hash_walk(pim->rpf_hash, pim_print_json_pnc_cache_walkcb,
 | 
						|
			  &jcwd);
 | 
						|
		vty_json(vty, jcwd.json_obj);
 | 
						|
	} else
 | 
						|
		hash_walk(pim->rpf_hash, pim_print_vty_pnc_cache_walkcb, &cwd);
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_neighbors_cmd_helper(const char *vrf, struct vty *vty,
 | 
						|
				  const char *json, const char *interface)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	if (interface)
 | 
						|
		pim_show_neighbors_single(v->info, vty, interface, json_parent);
 | 
						|
	else
 | 
						|
		pim_show_neighbors(v->info, vty, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_neighbors_vrf_all_cmd_helper(struct vty *vty, const char *json,
 | 
						|
					  const char *interface)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
	RB_FOREACH (v, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", v->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
 | 
						|
		if (interface)
 | 
						|
			pim_show_neighbors_single(v->info, vty, interface,
 | 
						|
						  json_vrf);
 | 
						|
		else
 | 
						|
			pim_show_neighbors(v->info, vty, json_vrf);
 | 
						|
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, v->name, json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
 | 
						|
			       const char *neighbor, json_object *json)
 | 
						|
{
 | 
						|
	struct listnode *neighnode;
 | 
						|
	struct interface *ifp;
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct pim_neighbor *neigh;
 | 
						|
	time_t now;
 | 
						|
	int found_neighbor = 0;
 | 
						|
	int option_address_list;
 | 
						|
	int option_dr_priority;
 | 
						|
	int option_generation_id;
 | 
						|
	int option_holdtime;
 | 
						|
	int option_lan_prune_delay;
 | 
						|
	int option_t_bit;
 | 
						|
	char uptime[10];
 | 
						|
	char expire[10];
 | 
						|
	char neigh_src_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
	json_object *json_ifp = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	now = pim_time_monotonic_sec();
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (pim_ifp->pim_sock_fd < 0)
 | 
						|
			continue;
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
 | 
						|
					  neigh)) {
 | 
						|
			snprintfrr(neigh_src_str, sizeof(neigh_src_str),
 | 
						|
				   "%pPAs", &neigh->source_addr);
 | 
						|
 | 
						|
			/*
 | 
						|
			 * The user can specify either the interface name or the
 | 
						|
			 * PIM neighbor IP.
 | 
						|
			 * If this pim_ifp matches neither then skip.
 | 
						|
			 */
 | 
						|
			if (strcmp(neighbor, "detail") &&
 | 
						|
			    strcmp(neighbor, ifp->name) &&
 | 
						|
			    strcmp(neighbor, neigh_src_str))
 | 
						|
				continue;
 | 
						|
 | 
						|
			found_neighbor = 1;
 | 
						|
			pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
					now - neigh->creation);
 | 
						|
			pim_time_timer_to_hhmmss(expire, sizeof(expire),
 | 
						|
						 neigh->t_expire_timer);
 | 
						|
 | 
						|
			option_address_list = 0;
 | 
						|
			option_dr_priority = 0;
 | 
						|
			option_generation_id = 0;
 | 
						|
			option_holdtime = 0;
 | 
						|
			option_lan_prune_delay = 0;
 | 
						|
			option_t_bit = 0;
 | 
						|
 | 
						|
			if (PIM_OPTION_IS_SET(neigh->hello_options,
 | 
						|
					      PIM_OPTION_MASK_ADDRESS_LIST))
 | 
						|
				option_address_list = 1;
 | 
						|
 | 
						|
			if (PIM_OPTION_IS_SET(neigh->hello_options,
 | 
						|
					      PIM_OPTION_MASK_DR_PRIORITY))
 | 
						|
				option_dr_priority = 1;
 | 
						|
 | 
						|
			if (PIM_OPTION_IS_SET(neigh->hello_options,
 | 
						|
					      PIM_OPTION_MASK_GENERATION_ID))
 | 
						|
				option_generation_id = 1;
 | 
						|
 | 
						|
			if (PIM_OPTION_IS_SET(neigh->hello_options,
 | 
						|
					      PIM_OPTION_MASK_HOLDTIME))
 | 
						|
				option_holdtime = 1;
 | 
						|
 | 
						|
			if (PIM_OPTION_IS_SET(neigh->hello_options,
 | 
						|
					      PIM_OPTION_MASK_LAN_PRUNE_DELAY))
 | 
						|
				option_lan_prune_delay = 1;
 | 
						|
 | 
						|
			if (PIM_OPTION_IS_SET(
 | 
						|
				    neigh->hello_options,
 | 
						|
				    PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION))
 | 
						|
				option_t_bit = 1;
 | 
						|
 | 
						|
			if (json) {
 | 
						|
 | 
						|
				/* Does this ifp live in json? If not create it
 | 
						|
				 */
 | 
						|
				json_object_object_get_ex(json, ifp->name,
 | 
						|
							  &json_ifp);
 | 
						|
 | 
						|
				if (!json_ifp) {
 | 
						|
					json_ifp = json_object_new_object();
 | 
						|
					json_object_pim_ifp_add(json_ifp, ifp);
 | 
						|
					json_object_object_add(json, ifp->name,
 | 
						|
							       json_ifp);
 | 
						|
				}
 | 
						|
 | 
						|
				json_row = json_object_new_object();
 | 
						|
				json_object_string_add(json_row, "interface",
 | 
						|
						       ifp->name);
 | 
						|
				json_object_string_add(json_row, "address",
 | 
						|
						       neigh_src_str);
 | 
						|
				json_object_string_add(json_row, "upTime",
 | 
						|
						       uptime);
 | 
						|
				json_object_string_add(json_row, "holdtime",
 | 
						|
						       expire);
 | 
						|
				json_object_int_add(json_row, "drPriority",
 | 
						|
						    neigh->dr_priority);
 | 
						|
				json_object_int_add(json_row, "generationId",
 | 
						|
						    neigh->generation_id);
 | 
						|
 | 
						|
				if (option_address_list)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_row,
 | 
						|
						"helloOptionAddressList");
 | 
						|
 | 
						|
				if (option_dr_priority)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_row,
 | 
						|
						"helloOptionDrPriority");
 | 
						|
 | 
						|
				if (option_generation_id)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_row,
 | 
						|
						"helloOptionGenerationId");
 | 
						|
 | 
						|
				if (option_holdtime)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_row,
 | 
						|
						"helloOptionHoldtime");
 | 
						|
 | 
						|
				if (option_lan_prune_delay)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_row,
 | 
						|
						"helloOptionLanPruneDelay");
 | 
						|
 | 
						|
				if (option_t_bit)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_row, "helloOptionTBit");
 | 
						|
 | 
						|
				json_object_object_add(json_ifp, neigh_src_str,
 | 
						|
						       json_row);
 | 
						|
 | 
						|
			} else {
 | 
						|
				vty_out(vty, "Interface : %s\n", ifp->name);
 | 
						|
				vty_out(vty, "Neighbor  : %s\n", neigh_src_str);
 | 
						|
				vty_out(vty,
 | 
						|
					"    Uptime                         : %s\n",
 | 
						|
					uptime);
 | 
						|
				vty_out(vty,
 | 
						|
					"    Holdtime                       : %s\n",
 | 
						|
					expire);
 | 
						|
				vty_out(vty,
 | 
						|
					"    DR Priority                    : %d\n",
 | 
						|
					neigh->dr_priority);
 | 
						|
				vty_out(vty,
 | 
						|
					"    Generation ID                  : %08x\n",
 | 
						|
					neigh->generation_id);
 | 
						|
				vty_out(vty,
 | 
						|
					"    Override Interval (msec)       : %d\n",
 | 
						|
					neigh->override_interval_msec);
 | 
						|
				vty_out(vty,
 | 
						|
					"    Propagation Delay (msec)       : %d\n",
 | 
						|
					neigh->propagation_delay_msec);
 | 
						|
				vty_out(vty,
 | 
						|
					"    Hello Option - Address List    : %s\n",
 | 
						|
					option_address_list ? "yes" : "no");
 | 
						|
				vty_out(vty,
 | 
						|
					"    Hello Option - DR Priority     : %s\n",
 | 
						|
					option_dr_priority ? "yes" : "no");
 | 
						|
				vty_out(vty,
 | 
						|
					"    Hello Option - Generation ID   : %s\n",
 | 
						|
					option_generation_id ? "yes" : "no");
 | 
						|
				vty_out(vty,
 | 
						|
					"    Hello Option - Holdtime        : %s\n",
 | 
						|
					option_holdtime ? "yes" : "no");
 | 
						|
				vty_out(vty,
 | 
						|
					"    Hello Option - LAN Prune Delay : %s\n",
 | 
						|
					option_lan_prune_delay ? "yes" : "no");
 | 
						|
				vty_out(vty,
 | 
						|
					"    Hello Option - T-bit           : %s\n",
 | 
						|
					option_t_bit ? "yes" : "no");
 | 
						|
				bfd_sess_show(vty, json_ifp,
 | 
						|
					      neigh->bfd_session);
 | 
						|
				vty_out(vty, "\n");
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!found_neighbor)
 | 
						|
		vty_out(vty, "%% No such interface or neighbor\n");
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
 | 
						|
			json_object *json)
 | 
						|
{
 | 
						|
	struct listnode *neighnode;
 | 
						|
	struct interface *ifp;
 | 
						|
	struct pim_interface *pim_ifp;
 | 
						|
	struct pim_neighbor *neigh;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
	time_t now;
 | 
						|
	char uptime[10];
 | 
						|
	char expire[10];
 | 
						|
	char neigh_src_str[PIM_ADDRSTRLEN];
 | 
						|
	json_object *json_ifp_rows = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	now = pim_time_monotonic_sec();
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(tt, "Interface|Neighbor|Uptime|Holdtime|DR Pri");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (pim_ifp->pim_sock_fd < 0)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (json)
 | 
						|
			json_ifp_rows = json_object_new_object();
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
 | 
						|
					  neigh)) {
 | 
						|
			snprintfrr(neigh_src_str, sizeof(neigh_src_str),
 | 
						|
				   "%pPAs", &neigh->source_addr);
 | 
						|
			pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
					now - neigh->creation);
 | 
						|
			pim_time_timer_to_hhmmss(expire, sizeof(expire),
 | 
						|
						 neigh->t_expire_timer);
 | 
						|
 | 
						|
			if (json) {
 | 
						|
				json_row = json_object_new_object();
 | 
						|
				json_object_string_add(json_row, "interface",
 | 
						|
						       ifp->name);
 | 
						|
				json_object_string_add(json_row, "neighbor",
 | 
						|
						       neigh_src_str);
 | 
						|
				json_object_string_add(json_row, "upTime",
 | 
						|
						       uptime);
 | 
						|
				json_object_string_add(json_row, "holdTime",
 | 
						|
						       expire);
 | 
						|
				json_object_int_add(json_row, "holdTimeMax",
 | 
						|
						    neigh->holdtime);
 | 
						|
				json_object_int_add(json_row, "drPriority",
 | 
						|
						    neigh->dr_priority);
 | 
						|
				json_object_object_add(json_ifp_rows,
 | 
						|
						       neigh_src_str, json_row);
 | 
						|
 | 
						|
			} else {
 | 
						|
				ttable_add_row(tt, "%s|%pPAs|%s|%s|%d",
 | 
						|
					       ifp->name, &neigh->source_addr,
 | 
						|
					       uptime, expire,
 | 
						|
					       neigh->dr_priority);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (json) {
 | 
						|
			json_object_object_add(json, ifp->name, json_ifp_rows);
 | 
						|
			json_ifp_rows = NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int gm_process_query_max_response_time_cmd(struct vty *vty,
 | 
						|
					   const char *qmrt_str)
 | 
						|
{
 | 
						|
	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_PIM_AF_XPATH_VAL);
 | 
						|
 | 
						|
	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,
 | 
						|
			      qmrt_str);
 | 
						|
	return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int gm_process_no_query_max_response_time_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY,
 | 
						|
			      NULL);
 | 
						|
	return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int gm_process_last_member_query_count_cmd(struct vty *vty,
 | 
						|
					   const char *lmqc_str)
 | 
						|
{
 | 
						|
	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_PIM_AF_XPATH_VAL);
 | 
						|
	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, "./robustness-variable", NB_OP_MODIFY,
 | 
						|
			      lmqc_str);
 | 
						|
	return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int gm_process_no_last_member_query_count_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_DESTROY,
 | 
						|
			      NULL);
 | 
						|
	return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int gm_process_last_member_query_interval_cmd(struct vty *vty,
 | 
						|
					      const char *lmqi_str)
 | 
						|
{
 | 
						|
	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_PIM_AF_XPATH_VAL);
 | 
						|
	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, "./last-member-query-interval", NB_OP_MODIFY,
 | 
						|
			      lmqi_str);
 | 
						|
	return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int gm_process_no_last_member_query_interval_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./last-member-query-interval",
 | 
						|
			      NB_OP_DESTROY, NULL);
 | 
						|
	return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation,
 | 
						|
			     const char *src_str)
 | 
						|
{
 | 
						|
	const char *vrfname;
 | 
						|
	char ssmpingd_ip_xpath[XPATH_MAXLEN];
 | 
						|
 | 
						|
	vrfname = pim_cli_get_vrf_name(vty);
 | 
						|
	if (vrfname == NULL)
 | 
						|
		return CMD_WARNING_CONFIG_FAILED;
 | 
						|
 | 
						|
	snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
 | 
						|
		 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
 | 
						|
		 FRR_PIM_AF_XPATH_VAL);
 | 
						|
	strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
 | 
						|
		sizeof(ssmpingd_ip_xpath));
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, operation, src_str);
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_bsm_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	const struct lyd_node *gm_enable_dnode;
 | 
						|
 | 
						|
	gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
 | 
						|
					  FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
 | 
						|
					  FRR_PIM_AF_XPATH_VAL);
 | 
						|
	if (!gm_enable_dnode)
 | 
						|
		nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
				      "true");
 | 
						|
	else {
 | 
						|
		if (!yang_dnode_get_bool(gm_enable_dnode, "."))
 | 
						|
			nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
					      "true");
 | 
						|
	}
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_bsm_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_unicast_bsm_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	const struct lyd_node *gm_enable_dnode;
 | 
						|
 | 
						|
	gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
 | 
						|
					  FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
 | 
						|
					  FRR_PIM_AF_XPATH_VAL);
 | 
						|
	if (!gm_enable_dnode)
 | 
						|
		nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
				      "true");
 | 
						|
	else {
 | 
						|
		if (!yang_dnode_get_bool(gm_enable_dnode, "."))
 | 
						|
			nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
 | 
						|
					      "true");
 | 
						|
	}
 | 
						|
 | 
						|
	nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
int pim_process_no_unicast_bsm_cmd(struct vty *vty)
 | 
						|
{
 | 
						|
	nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
 | 
						|
 | 
						|
	return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
 | 
						|
				    FRR_PIM_AF_XPATH_VAL);
 | 
						|
}
 | 
						|
 | 
						|
static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
 | 
						|
				time_t now)
 | 
						|
{
 | 
						|
	char uptime_scan_oil[10];
 | 
						|
	char uptime_mroute_add[10];
 | 
						|
	char uptime_mroute_del[10];
 | 
						|
 | 
						|
	pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now,
 | 
						|
			      pim->scan_oil_last);
 | 
						|
	pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now,
 | 
						|
			      pim->mroute_add_last);
 | 
						|
	pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now,
 | 
						|
			      pim->mroute_del_last);
 | 
						|
 | 
						|
	vty_out(vty,
 | 
						|
		"Scan OIL - Last: %s  Events: %lld\n"
 | 
						|
		"MFC Add  - Last: %s  Events: %lld\n"
 | 
						|
		"MFC Del  - Last: %s  Events: %lld\n",
 | 
						|
		uptime_scan_oil, (long long)pim->scan_oil_events,
 | 
						|
		uptime_mroute_add, (long long)pim->mroute_add_events,
 | 
						|
		uptime_mroute_del, (long long)pim->mroute_del_events);
 | 
						|
}
 | 
						|
 | 
						|
void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty,
 | 
						|
			       json_object *json)
 | 
						|
{
 | 
						|
	struct interface *ifp;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(
 | 
						|
			tt,
 | 
						|
			"Interface|Address|ifi|Vif|PktsIn|PktsOut|BytesIn|BytesOut");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		struct pim_interface *pim_ifp;
 | 
						|
#if PIM_IPV == 4
 | 
						|
		struct sioc_vif_req vreq;
 | 
						|
#else
 | 
						|
		struct sioc_mif_req6 vreq;
 | 
						|
#endif
 | 
						|
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		memset(&vreq, 0, sizeof(vreq));
 | 
						|
#if PIM_IPV == 4
 | 
						|
		vreq.vifi = pim_ifp->mroute_vif_index;
 | 
						|
		if (ioctl(pim->mroute_socket, SIOCGETVIFCNT, &vreq)) {
 | 
						|
			zlog_warn(
 | 
						|
				"ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
 | 
						|
				(unsigned long)SIOCGETVIFCNT, ifp->name,
 | 
						|
				pim_ifp->mroute_vif_index, errno,
 | 
						|
				safe_strerror(errno));
 | 
						|
		}
 | 
						|
#else
 | 
						|
		vreq.mifi = pim_ifp->mroute_vif_index;
 | 
						|
		if (ioctl(pim->mroute_socket, SIOCGETMIFCNT_IN6, &vreq)) {
 | 
						|
			zlog_warn(
 | 
						|
				"ioctl(SIOCGETMIFCNT_IN6=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
 | 
						|
				(unsigned long)SIOCGETMIFCNT_IN6, ifp->name,
 | 
						|
				pim_ifp->mroute_vif_index, errno,
 | 
						|
				safe_strerror(errno));
 | 
						|
		}
 | 
						|
#endif
 | 
						|
 | 
						|
		if (json) {
 | 
						|
			json_row = json_object_new_object();
 | 
						|
			json_object_string_add(json_row, "name", ifp->name);
 | 
						|
			json_object_string_add(json_row, "state",
 | 
						|
					       if_is_up(ifp) ? "up" : "down");
 | 
						|
			json_object_string_addf(json_row, "address", "%pPA",
 | 
						|
						&pim_ifp->primary_address);
 | 
						|
			json_object_int_add(json_row, "ifIndex", ifp->ifindex);
 | 
						|
			json_object_int_add(json_row, "vif",
 | 
						|
					    pim_ifp->mroute_vif_index);
 | 
						|
			json_object_int_add(json_row, "pktsIn",
 | 
						|
					    (unsigned long)vreq.icount);
 | 
						|
			json_object_int_add(json_row, "pktsOut",
 | 
						|
					    (unsigned long)vreq.ocount);
 | 
						|
			json_object_int_add(json_row, "bytesIn",
 | 
						|
					    (unsigned long)vreq.ibytes);
 | 
						|
			json_object_int_add(json_row, "bytesOut",
 | 
						|
					    (unsigned long)vreq.obytes);
 | 
						|
			json_object_object_add(json, ifp->name, json_row);
 | 
						|
		} else {
 | 
						|
			ttable_add_row(tt, "%s|%pPAs|%d|%d|%lu|%lu|%lu|%lu",
 | 
						|
				       ifp->name, &pim_ifp->primary_address,
 | 
						|
				       ifp->ifindex, pim_ifp->mroute_vif_index,
 | 
						|
				       (unsigned long)vreq.icount,
 | 
						|
				       (unsigned long)vreq.ocount,
 | 
						|
				       (unsigned long)vreq.ibytes,
 | 
						|
				       (unsigned long)vreq.obytes);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, struct vty *vty)
 | 
						|
{
 | 
						|
	struct vrf *vrf = pim->vrf;
 | 
						|
	time_t now = pim_time_monotonic_sec();
 | 
						|
	char uptime[10];
 | 
						|
	char mlag_role[80];
 | 
						|
 | 
						|
	pim = vrf->info;
 | 
						|
 | 
						|
	vty_out(vty, "Router MLAG Role: %s\n",
 | 
						|
		mlag_role2str(router->mlag_role, mlag_role, sizeof(mlag_role)));
 | 
						|
	vty_out(vty, "Mroute socket descriptor:");
 | 
						|
 | 
						|
	vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name);
 | 
						|
	vty_out(vty, "PIM Register socket descriptor:");
 | 
						|
	vty_out(vty, " %d(%s)\n", pim->reg_sock, vrf->name);
 | 
						|
 | 
						|
	pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
			now - pim->mroute_socket_creation);
 | 
						|
	vty_out(vty, "Mroute socket uptime: %s\n", uptime);
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
 | 
						|
	pim_zebra_zclient_update(vty);
 | 
						|
	pim_zlookup_show_ip_multicast(vty);
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
	vty_out(vty, "Maximum highest VifIndex: %d\n", PIM_MAX_USABLE_VIFS);
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
	vty_out(vty, "Upstream Join Timer: %d secs\n", router->t_periodic);
 | 
						|
	vty_out(vty, "Join/Prune Holdtime: %d secs\n", PIM_JP_HOLDTIME);
 | 
						|
	vty_out(vty, "PIM ECMP: %s\n", pim->ecmp_enable ? "Enable" : "Disable");
 | 
						|
	vty_out(vty, "PIM ECMP Rebalance: %s\n",
 | 
						|
		pim->ecmp_rebalance_enable ? "Enable" : "Disable");
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
 | 
						|
	pim_show_rpf_refresh_stats(vty, pim, now, NULL);
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
 | 
						|
	show_scan_oil_stats(pim, vty, now);
 | 
						|
 | 
						|
	show_multicast_interfaces(pim, vty, NULL);
 | 
						|
}
 | 
						|
 | 
						|
void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
 | 
						|
		 bool fill, json_object *json)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct channel_oil *c_oil;
 | 
						|
	struct static_route *s_route;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
	time_t now;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_source = NULL;
 | 
						|
	json_object *json_oil = NULL;
 | 
						|
	json_object *json_ifp_out = NULL;
 | 
						|
	int found_oif;
 | 
						|
	int first;
 | 
						|
	char grp_str[PIM_ADDRSTRLEN];
 | 
						|
	char src_str[PIM_ADDRSTRLEN];
 | 
						|
	char in_ifname[INTERFACE_NAMSIZ + 1];
 | 
						|
	char out_ifname[INTERFACE_NAMSIZ + 1];
 | 
						|
	int oif_vif_index;
 | 
						|
	struct interface *ifp_in;
 | 
						|
	char proto[100];
 | 
						|
	char state_str[PIM_REG_STATE_STR_LEN];
 | 
						|
	char mroute_uptime[10];
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		vty_out(vty, "IP Multicast Routing Table\n");
 | 
						|
		vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
 | 
						|
		vty_out(vty,
 | 
						|
			"       R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
 | 
						|
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(
 | 
						|
			tt, "Source|Group|Flags|Proto|Input|Output|TTL|Uptime");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	now = pim_time_monotonic_sec();
 | 
						|
 | 
						|
	/* print list of PIM and IGMP routes */
 | 
						|
	frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
 | 
						|
		found_oif = 0;
 | 
						|
		first = 1;
 | 
						|
		if (!c_oil->installed)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (!pim_addr_is_any(sg->grp) &&
 | 
						|
		    pim_addr_cmp(sg->grp, *oil_mcastgrp(c_oil)))
 | 
						|
			continue;
 | 
						|
		if (!pim_addr_is_any(sg->src) &&
 | 
						|
		    pim_addr_cmp(sg->src, *oil_origin(c_oil)))
 | 
						|
			continue;
 | 
						|
 | 
						|
		snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
 | 
						|
			   oil_mcastgrp(c_oil));
 | 
						|
		snprintfrr(src_str, sizeof(src_str), "%pPAs",
 | 
						|
			   oil_origin(c_oil));
 | 
						|
 | 
						|
		strlcpy(state_str, "S", sizeof(state_str));
 | 
						|
		/* When a non DR receives a igmp join, it creates a (*,G)
 | 
						|
		 * channel_oil without any upstream creation
 | 
						|
		 */
 | 
						|
		if (c_oil->up) {
 | 
						|
			if (PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(c_oil->up->flags))
 | 
						|
				strlcat(state_str, "C", sizeof(state_str));
 | 
						|
			if (pim_upstream_is_sg_rpt(c_oil->up))
 | 
						|
				strlcat(state_str, "R", sizeof(state_str));
 | 
						|
			if (PIM_UPSTREAM_FLAG_TEST_FHR(c_oil->up->flags))
 | 
						|
				strlcat(state_str, "F", sizeof(state_str));
 | 
						|
			if (c_oil->up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
 | 
						|
				strlcat(state_str, "T", sizeof(state_str));
 | 
						|
		}
 | 
						|
		if (pim_channel_oil_empty(c_oil))
 | 
						|
			strlcat(state_str, "P", sizeof(state_str));
 | 
						|
 | 
						|
		ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
 | 
						|
 | 
						|
		if (ifp_in)
 | 
						|
			strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
 | 
						|
		else
 | 
						|
			strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
 | 
						|
 | 
						|
 | 
						|
		pim_time_uptime(mroute_uptime, sizeof(mroute_uptime),
 | 
						|
				now - c_oil->mroute_creation);
 | 
						|
 | 
						|
		if (json) {
 | 
						|
 | 
						|
			/* Find the group, create it if it doesn't exist */
 | 
						|
			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);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Find the source nested under the group, create it if
 | 
						|
			 * it doesn't exist
 | 
						|
			 */
 | 
						|
			json_object_object_get_ex(json_group, src_str,
 | 
						|
						  &json_source);
 | 
						|
 | 
						|
			if (!json_source) {
 | 
						|
				json_source = json_object_new_object();
 | 
						|
				json_object_object_add(json_group, src_str,
 | 
						|
						       json_source);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Find the inbound interface nested under the source,
 | 
						|
			 * create it if it doesn't exist
 | 
						|
			 */
 | 
						|
			json_object_string_add(json_source, "source", src_str);
 | 
						|
			json_object_string_add(json_source, "group", grp_str);
 | 
						|
			json_object_int_add(json_source, "installed",
 | 
						|
					    c_oil->installed);
 | 
						|
			json_object_int_add(json_source, "refCount",
 | 
						|
					    c_oil->oil_ref_count);
 | 
						|
			json_object_int_add(json_source, "oilSize",
 | 
						|
					    c_oil->oil_size);
 | 
						|
			json_object_int_add(json_source, "oilInheritedRescan",
 | 
						|
					    c_oil->oil_inherited_rescan);
 | 
						|
			json_object_string_add(json_source, "iif", in_ifname);
 | 
						|
			json_object_string_add(json_source, "upTime",
 | 
						|
					       mroute_uptime);
 | 
						|
			json_oil = NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
 | 
						|
		     ++oif_vif_index) {
 | 
						|
			struct interface *ifp_out;
 | 
						|
			int ttl;
 | 
						|
 | 
						|
			ttl = oil_if_has(c_oil, oif_vif_index);
 | 
						|
			if (ttl < 1)
 | 
						|
				continue;
 | 
						|
 | 
						|
			/* do not display muted OIFs */
 | 
						|
			if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_MUTE)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (*oil_parent(c_oil) == oif_vif_index &&
 | 
						|
			    !pim_mroute_allow_iif_in_oil(c_oil, oif_vif_index))
 | 
						|
				continue;
 | 
						|
 | 
						|
			ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
 | 
						|
			found_oif = 1;
 | 
						|
 | 
						|
			if (ifp_out)
 | 
						|
				strlcpy(out_ifname, ifp_out->name,
 | 
						|
					sizeof(out_ifname));
 | 
						|
			else
 | 
						|
				strlcpy(out_ifname, "<oif?>",
 | 
						|
					sizeof(out_ifname));
 | 
						|
 | 
						|
			if (json) {
 | 
						|
				json_ifp_out = json_object_new_object();
 | 
						|
				json_object_string_add(json_ifp_out, "source",
 | 
						|
						       src_str);
 | 
						|
				json_object_string_add(json_ifp_out, "group",
 | 
						|
						       grp_str);
 | 
						|
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_PIM)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_ifp_out, "protocolPim");
 | 
						|
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_GM)
 | 
						|
#if PIM_IPV == 4
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_ifp_out, "protocolIgmp");
 | 
						|
#else
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_ifp_out, "protocolMld");
 | 
						|
#endif
 | 
						|
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_VXLAN)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_ifp_out, "protocolVxlan");
 | 
						|
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_STAR)
 | 
						|
					json_object_boolean_true_add(
 | 
						|
						json_ifp_out,
 | 
						|
						"protocolInherited");
 | 
						|
 | 
						|
				json_object_string_add(json_ifp_out,
 | 
						|
						       "inboundInterface",
 | 
						|
						       in_ifname);
 | 
						|
				json_object_int_add(json_ifp_out, "iVifI",
 | 
						|
						    *oil_parent(c_oil));
 | 
						|
				json_object_string_add(json_ifp_out,
 | 
						|
						       "outboundInterface",
 | 
						|
						       out_ifname);
 | 
						|
				json_object_int_add(json_ifp_out, "oVifI",
 | 
						|
						    oif_vif_index);
 | 
						|
				json_object_int_add(json_ifp_out, "ttl", ttl);
 | 
						|
				json_object_string_add(json_ifp_out, "upTime",
 | 
						|
						       mroute_uptime);
 | 
						|
				json_object_string_add(json_source, "flags",
 | 
						|
						       state_str);
 | 
						|
				if (!json_oil) {
 | 
						|
					json_oil = json_object_new_object();
 | 
						|
					json_object_object_add(json_source,
 | 
						|
							       "oil", json_oil);
 | 
						|
				}
 | 
						|
				json_object_object_add(json_oil, out_ifname,
 | 
						|
						       json_ifp_out);
 | 
						|
			} else {
 | 
						|
				proto[0] = '\0';
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_PIM) {
 | 
						|
					strlcpy(proto, "PIM", sizeof(proto));
 | 
						|
				}
 | 
						|
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_GM) {
 | 
						|
#if PIM_IPV == 4
 | 
						|
					strlcpy(proto, "IGMP", sizeof(proto));
 | 
						|
#else
 | 
						|
					strlcpy(proto, "MLD", sizeof(proto));
 | 
						|
#endif
 | 
						|
				}
 | 
						|
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_VXLAN) {
 | 
						|
					strlcpy(proto, "VxLAN", sizeof(proto));
 | 
						|
				}
 | 
						|
 | 
						|
				if (c_oil->oif_flags[oif_vif_index] &
 | 
						|
				    PIM_OIF_FLAG_PROTO_STAR) {
 | 
						|
					strlcpy(proto, "STAR", sizeof(proto));
 | 
						|
				}
 | 
						|
 | 
						|
				ttable_add_row(tt, "%s|%s|%s|%s|%s|%s|%d|%s",
 | 
						|
					       src_str, grp_str, state_str,
 | 
						|
					       proto, in_ifname, out_ifname,
 | 
						|
					       ttl, mroute_uptime);
 | 
						|
 | 
						|
				if (first) {
 | 
						|
					src_str[0] = '\0';
 | 
						|
					grp_str[0] = '\0';
 | 
						|
					in_ifname[0] = '\0';
 | 
						|
					state_str[0] = '\0';
 | 
						|
					mroute_uptime[0] = '\0';
 | 
						|
					first = 0;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (!json && !found_oif) {
 | 
						|
			ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
 | 
						|
				       oil_origin(c_oil), oil_mcastgrp(c_oil),
 | 
						|
				       state_str, "none", in_ifname, "none", 0,
 | 
						|
				       "--:--:--");
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Print list of static routes */
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
 | 
						|
		first = 1;
 | 
						|
 | 
						|
		if (!s_route->c_oil.installed)
 | 
						|
			continue;
 | 
						|
 | 
						|
		snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &s_route->group);
 | 
						|
		snprintfrr(src_str, sizeof(src_str), "%pPAs", &s_route->source);
 | 
						|
		ifp_in = pim_if_find_by_vif_index(pim, s_route->iif);
 | 
						|
		found_oif = 0;
 | 
						|
 | 
						|
		if (ifp_in)
 | 
						|
			strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
 | 
						|
		else
 | 
						|
			strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
 | 
						|
 | 
						|
		if (json) {
 | 
						|
 | 
						|
			/* Find the group, create it if it doesn't exist */
 | 
						|
			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);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Find the source nested under the group, create it if
 | 
						|
			 * it doesn't exist
 | 
						|
			 */
 | 
						|
			json_object_object_get_ex(json_group, src_str,
 | 
						|
						  &json_source);
 | 
						|
 | 
						|
			if (!json_source) {
 | 
						|
				json_source = json_object_new_object();
 | 
						|
				json_object_object_add(json_group, src_str,
 | 
						|
						       json_source);
 | 
						|
			}
 | 
						|
 | 
						|
			json_object_string_add(json_source, "iif", in_ifname);
 | 
						|
			json_oil = NULL;
 | 
						|
		} else {
 | 
						|
			strlcpy(proto, "STATIC", sizeof(proto));
 | 
						|
		}
 | 
						|
 | 
						|
		for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
 | 
						|
		     ++oif_vif_index) {
 | 
						|
			struct interface *ifp_out;
 | 
						|
			char oif_uptime[10];
 | 
						|
			int ttl;
 | 
						|
 | 
						|
			ttl = s_route->oif_ttls[oif_vif_index];
 | 
						|
			if (ttl < 1)
 | 
						|
				continue;
 | 
						|
 | 
						|
			ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
 | 
						|
			pim_time_uptime(
 | 
						|
				oif_uptime, sizeof(oif_uptime),
 | 
						|
				now - s_route->c_oil
 | 
						|
						.oif_creation[oif_vif_index]);
 | 
						|
			found_oif = 1;
 | 
						|
 | 
						|
			if (ifp_out)
 | 
						|
				strlcpy(out_ifname, ifp_out->name,
 | 
						|
					sizeof(out_ifname));
 | 
						|
			else
 | 
						|
				strlcpy(out_ifname, "<oif?>",
 | 
						|
					sizeof(out_ifname));
 | 
						|
 | 
						|
			if (json) {
 | 
						|
				json_ifp_out = json_object_new_object();
 | 
						|
				json_object_string_add(json_ifp_out, "source",
 | 
						|
						       src_str);
 | 
						|
				json_object_string_add(json_ifp_out, "group",
 | 
						|
						       grp_str);
 | 
						|
				json_object_boolean_true_add(json_ifp_out,
 | 
						|
							     "protocolStatic");
 | 
						|
				json_object_string_add(json_ifp_out,
 | 
						|
						       "inboundInterface",
 | 
						|
						       in_ifname);
 | 
						|
				json_object_int_add(
 | 
						|
					json_ifp_out, "iVifI",
 | 
						|
					*oil_parent(&s_route->c_oil));
 | 
						|
				json_object_string_add(json_ifp_out,
 | 
						|
						       "outboundInterface",
 | 
						|
						       out_ifname);
 | 
						|
				json_object_int_add(json_ifp_out, "oVifI",
 | 
						|
						    oif_vif_index);
 | 
						|
				json_object_int_add(json_ifp_out, "ttl", ttl);
 | 
						|
				json_object_string_add(json_ifp_out, "upTime",
 | 
						|
						       oif_uptime);
 | 
						|
				if (!json_oil) {
 | 
						|
					json_oil = json_object_new_object();
 | 
						|
					json_object_object_add(json_source,
 | 
						|
							       "oil", json_oil);
 | 
						|
				}
 | 
						|
				json_object_object_add(json_oil, out_ifname,
 | 
						|
						       json_ifp_out);
 | 
						|
			} else {
 | 
						|
				ttable_add_row(
 | 
						|
					tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
 | 
						|
					&s_route->source, &s_route->group, "-",
 | 
						|
					proto, in_ifname, out_ifname, ttl,
 | 
						|
					oif_uptime);
 | 
						|
				if (first && !fill) {
 | 
						|
					src_str[0] = '\0';
 | 
						|
					grp_str[0] = '\0';
 | 
						|
					in_ifname[0] = '\0';
 | 
						|
					first = 0;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (!json && !found_oif) {
 | 
						|
			ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
 | 
						|
				       &s_route->source, &s_route->group, "-",
 | 
						|
				       proto, in_ifname, "none", 0, "--:--:--");
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void show_mroute_count_per_channel_oil(struct channel_oil *c_oil,
 | 
						|
					      json_object *json,
 | 
						|
					      struct ttable *tt)
 | 
						|
{
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_source = NULL;
 | 
						|
 | 
						|
	if (!c_oil->installed)
 | 
						|
		return;
 | 
						|
 | 
						|
	pim_mroute_update_counters(c_oil);
 | 
						|
 | 
						|
	if (json) {
 | 
						|
		char group_str[PIM_ADDRSTRLEN];
 | 
						|
		char source_str[PIM_ADDRSTRLEN];
 | 
						|
 | 
						|
		snprintfrr(group_str, sizeof(group_str), "%pPAs",
 | 
						|
			   oil_mcastgrp(c_oil));
 | 
						|
		snprintfrr(source_str, sizeof(source_str), "%pPAs",
 | 
						|
			   oil_origin(c_oil));
 | 
						|
 | 
						|
		json_object_object_get_ex(json, group_str, &json_group);
 | 
						|
 | 
						|
		if (!json_group) {
 | 
						|
			json_group = json_object_new_object();
 | 
						|
			json_object_object_add(json, group_str, json_group);
 | 
						|
		}
 | 
						|
 | 
						|
		json_source = json_object_new_object();
 | 
						|
		json_object_object_add(json_group, source_str, json_source);
 | 
						|
		json_object_int_add(json_source, "lastUsed",
 | 
						|
				    c_oil->cc.lastused / 100);
 | 
						|
		json_object_int_add(json_source, "packets", c_oil->cc.pktcnt);
 | 
						|
		json_object_int_add(json_source, "bytes", c_oil->cc.bytecnt);
 | 
						|
		json_object_int_add(json_source, "wrongIf", c_oil->cc.wrong_if);
 | 
						|
 | 
						|
	} else {
 | 
						|
		ttable_add_row(tt, "%pPAs|%pPAs|%llu|%ld|%ld|%ld",
 | 
						|
			       oil_origin(c_oil), oil_mcastgrp(c_oil),
 | 
						|
			       c_oil->cc.lastused / 100,
 | 
						|
			       c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
 | 
						|
			       c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
 | 
						|
			       c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void show_mroute_count(struct pim_instance *pim, struct vty *vty,
 | 
						|
		       json_object *json)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct channel_oil *c_oil;
 | 
						|
	struct static_route *sr;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
	char *table = NULL;
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		vty_out(vty, "\n");
 | 
						|
 | 
						|
		/* Prepare table. */
 | 
						|
		tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
		ttable_add_row(tt,
 | 
						|
			       "Source|Group|LastUsed|Packets|Bytes|WrongIf");
 | 
						|
		tt->style.cell.rpad = 2;
 | 
						|
		tt->style.corner = '+';
 | 
						|
		ttable_restyle(tt);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Print PIM and IGMP route counts */
 | 
						|
	frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
 | 
						|
		show_mroute_count_per_channel_oil(c_oil, json, tt);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr))
 | 
						|
		show_mroute_count_per_channel_oil(&sr->c_oil, json, tt);
 | 
						|
 | 
						|
	/* Dump the generated table. */
 | 
						|
	if (!json) {
 | 
						|
		table = ttable_dump(tt, "\n");
 | 
						|
		vty_out(vty, "%s\n", table);
 | 
						|
		XFREE(MTYPE_TMP, table);
 | 
						|
		ttable_del(tt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
 | 
						|
			 json_object *json)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct channel_oil *c_oil;
 | 
						|
	struct static_route *s_route;
 | 
						|
	uint32_t starg_sw_mroute_cnt = 0;
 | 
						|
	uint32_t sg_sw_mroute_cnt = 0;
 | 
						|
	uint32_t starg_hw_mroute_cnt = 0;
 | 
						|
	uint32_t sg_hw_mroute_cnt = 0;
 | 
						|
	json_object *json_starg = NULL;
 | 
						|
	json_object *json_sg = NULL;
 | 
						|
 | 
						|
	if (!json)
 | 
						|
		vty_out(vty, "Mroute Type    Installed/Total\n");
 | 
						|
 | 
						|
	frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
 | 
						|
		if (!c_oil->installed) {
 | 
						|
			if (pim_addr_is_any(*oil_origin(c_oil)))
 | 
						|
				starg_sw_mroute_cnt++;
 | 
						|
			else
 | 
						|
				sg_sw_mroute_cnt++;
 | 
						|
		} else {
 | 
						|
			if (pim_addr_is_any(*oil_origin(c_oil)))
 | 
						|
				starg_hw_mroute_cnt++;
 | 
						|
			else
 | 
						|
				sg_hw_mroute_cnt++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
 | 
						|
		if (!s_route->c_oil.installed) {
 | 
						|
			if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
 | 
						|
				starg_sw_mroute_cnt++;
 | 
						|
			else
 | 
						|
				sg_sw_mroute_cnt++;
 | 
						|
		} else {
 | 
						|
			if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
 | 
						|
				starg_hw_mroute_cnt++;
 | 
						|
			else
 | 
						|
				sg_hw_mroute_cnt++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!json) {
 | 
						|
		vty_out(vty, "%-20s %u/%u\n", "(*, G)", starg_hw_mroute_cnt,
 | 
						|
			starg_sw_mroute_cnt + starg_hw_mroute_cnt);
 | 
						|
		vty_out(vty, "%-20s %u/%u\n", "(S, G)", sg_hw_mroute_cnt,
 | 
						|
			sg_sw_mroute_cnt + sg_hw_mroute_cnt);
 | 
						|
		vty_out(vty, "------\n");
 | 
						|
		vty_out(vty, "%-20s %u/%u\n", "Total",
 | 
						|
			(starg_hw_mroute_cnt + sg_hw_mroute_cnt),
 | 
						|
			(starg_sw_mroute_cnt + starg_hw_mroute_cnt +
 | 
						|
			 sg_sw_mroute_cnt + sg_hw_mroute_cnt));
 | 
						|
	} else {
 | 
						|
		/* (*,G) route details */
 | 
						|
		json_starg = json_object_new_object();
 | 
						|
		json_object_object_add(json, "wildcardGroup", json_starg);
 | 
						|
 | 
						|
		json_object_int_add(json_starg, "installed",
 | 
						|
				    starg_hw_mroute_cnt);
 | 
						|
		json_object_int_add(json_starg, "total",
 | 
						|
				    starg_sw_mroute_cnt + starg_hw_mroute_cnt);
 | 
						|
 | 
						|
		/* (S, G) route details */
 | 
						|
		json_sg = json_object_new_object();
 | 
						|
		json_object_object_add(json, "sourceGroup", json_sg);
 | 
						|
 | 
						|
		json_object_int_add(json_sg, "installed", sg_hw_mroute_cnt);
 | 
						|
		json_object_int_add(json_sg, "total",
 | 
						|
				    sg_sw_mroute_cnt + sg_hw_mroute_cnt);
 | 
						|
 | 
						|
		json_object_int_add(json, "totalNumOfInstalledMroutes",
 | 
						|
				    starg_hw_mroute_cnt + sg_hw_mroute_cnt);
 | 
						|
		json_object_int_add(json, "totalNumOfMroutes",
 | 
						|
				    starg_sw_mroute_cnt + starg_hw_mroute_cnt +
 | 
						|
					    sg_sw_mroute_cnt +
 | 
						|
					    sg_hw_mroute_cnt);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int clear_ip_mroute_count_command(struct vty *vty, const char *name)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct channel_oil *c_oil;
 | 
						|
	struct static_route *sr;
 | 
						|
	struct vrf *v = pim_cmd_lookup(vty, name);
 | 
						|
	struct pim_instance *pim;
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
	frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
 | 
						|
		if (!c_oil->installed)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pim_mroute_update_counters(c_oil);
 | 
						|
		c_oil->cc.origpktcnt = c_oil->cc.pktcnt;
 | 
						|
		c_oil->cc.origbytecnt = c_oil->cc.bytecnt;
 | 
						|
		c_oil->cc.origwrong_if = c_oil->cc.wrong_if;
 | 
						|
	}
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr)) {
 | 
						|
		if (!sr->c_oil.installed)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pim_mroute_update_counters(&sr->c_oil);
 | 
						|
 | 
						|
		sr->c_oil.cc.origpktcnt = sr->c_oil.cc.pktcnt;
 | 
						|
		sr->c_oil.cc.origbytecnt = sr->c_oil.cc.bytecnt;
 | 
						|
		sr->c_oil.cc.origwrong_if = sr->c_oil.cc.wrong_if;
 | 
						|
	}
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
struct vrf *pim_cmd_lookup(struct vty *vty, const char *name)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
 | 
						|
	if (name)
 | 
						|
		vrf = vrf_lookup_by_name(name);
 | 
						|
	else
 | 
						|
		vrf = vrf_lookup_by_id(VRF_DEFAULT);
 | 
						|
 | 
						|
	if (!vrf)
 | 
						|
		vty_out(vty, "Specified VRF: %s does not exist\n", name);
 | 
						|
 | 
						|
	return vrf;
 | 
						|
}
 | 
						|
 | 
						|
void clear_mroute(struct pim_instance *pim)
 | 
						|
{
 | 
						|
	struct pim_upstream *up;
 | 
						|
	struct interface *ifp;
 | 
						|
 | 
						|
	/* scan interfaces */
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		struct pim_interface *pim_ifp = ifp->info;
 | 
						|
		struct pim_ifchannel *ch;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* deleting all ifchannels */
 | 
						|
		while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
 | 
						|
			ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
 | 
						|
 | 
						|
			pim_ifchannel_delete(ch);
 | 
						|
		}
 | 
						|
 | 
						|
#if PIM_IPV == 4
 | 
						|
		/* clean up all igmp groups */
 | 
						|
		struct gm_group *grp;
 | 
						|
 | 
						|
		if (pim_ifp->gm_group_list) {
 | 
						|
			while (pim_ifp->gm_group_list->count) {
 | 
						|
				grp = listnode_head(pim_ifp->gm_group_list);
 | 
						|
				igmp_group_delete(grp);
 | 
						|
			}
 | 
						|
		}
 | 
						|
#else
 | 
						|
		struct gm_if *gm_ifp;
 | 
						|
 | 
						|
		gm_ifp = pim_ifp->mld;
 | 
						|
		if (gm_ifp)
 | 
						|
			gm_group_delete(gm_ifp);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	/* clean up all upstreams*/
 | 
						|
	while ((up = rb_pim_upstream_first(&pim->upstream_head)))
 | 
						|
		pim_upstream_del(pim, up, __func__);
 | 
						|
}
 | 
						|
 | 
						|
void clear_pim_statistics(struct pim_instance *pim)
 | 
						|
{
 | 
						|
	struct interface *ifp;
 | 
						|
 | 
						|
	pim->bsm_rcvd = 0;
 | 
						|
	pim->bsm_sent = 0;
 | 
						|
	pim->bsm_dropped = 0;
 | 
						|
 | 
						|
	/* scan interfaces */
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		struct pim_interface *pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
 | 
						|
		pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
 | 
						|
		pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int clear_pim_interface_traffic(const char *vrf, struct vty *vty)
 | 
						|
{
 | 
						|
	struct interface *ifp = NULL;
 | 
						|
	struct pim_interface *pim_ifp = NULL;
 | 
						|
 | 
						|
	struct vrf *v = pim_cmd_lookup(vty, vrf);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (v, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pim_ifp->pim_ifstat_hello_recv = 0;
 | 
						|
		pim_ifp->pim_ifstat_hello_sent = 0;
 | 
						|
		pim_ifp->pim_ifstat_join_recv = 0;
 | 
						|
		pim_ifp->pim_ifstat_join_send = 0;
 | 
						|
		pim_ifp->pim_ifstat_prune_recv = 0;
 | 
						|
		pim_ifp->pim_ifstat_prune_send = 0;
 | 
						|
		pim_ifp->pim_ifstat_reg_recv = 0;
 | 
						|
		pim_ifp->pim_ifstat_reg_send = 0;
 | 
						|
		pim_ifp->pim_ifstat_reg_stop_recv = 0;
 | 
						|
		pim_ifp->pim_ifstat_reg_stop_send = 0;
 | 
						|
		pim_ifp->pim_ifstat_assert_recv = 0;
 | 
						|
		pim_ifp->pim_ifstat_assert_send = 0;
 | 
						|
		pim_ifp->pim_ifstat_bsm_rx = 0;
 | 
						|
		pim_ifp->pim_ifstat_bsm_tx = 0;
 | 
						|
#if PIM_IPV == 4
 | 
						|
		pim_ifp->igmp_ifstat_joins_sent = 0;
 | 
						|
		pim_ifp->igmp_ifstat_joins_failed = 0;
 | 
						|
		pim_ifp->igmp_peak_group_count = 0;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_debug_pim_cmd(void)
 | 
						|
{
 | 
						|
	PIM_DO_DEBUG_PIM_EVENTS;
 | 
						|
	PIM_DO_DEBUG_PIM_PACKETS;
 | 
						|
	PIM_DO_DEBUG_PIM_TRACE;
 | 
						|
	PIM_DO_DEBUG_MSDP_EVENTS;
 | 
						|
	PIM_DO_DEBUG_MSDP_PACKETS;
 | 
						|
	PIM_DO_DEBUG_BSM;
 | 
						|
	PIM_DO_DEBUG_VXLAN;
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_no_debug_pim_cmd(void)
 | 
						|
{
 | 
						|
	PIM_DONT_DEBUG_PIM_EVENTS;
 | 
						|
	PIM_DONT_DEBUG_PIM_PACKETS;
 | 
						|
	PIM_DONT_DEBUG_PIM_TRACE;
 | 
						|
	PIM_DONT_DEBUG_MSDP_EVENTS;
 | 
						|
	PIM_DONT_DEBUG_MSDP_PACKETS;
 | 
						|
 | 
						|
	PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
 | 
						|
	PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
 | 
						|
	PIM_DONT_DEBUG_BSM;
 | 
						|
	PIM_DONT_DEBUG_VXLAN;
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_debug_pim_packets_cmd(const char *hello, const char *joins,
 | 
						|
			      const char *registers, struct vty *vty)
 | 
						|
{
 | 
						|
	if (hello) {
 | 
						|
		PIM_DO_DEBUG_PIM_HELLO;
 | 
						|
		vty_out(vty, "PIM Hello debugging is on\n");
 | 
						|
	} else if (joins) {
 | 
						|
		PIM_DO_DEBUG_PIM_J_P;
 | 
						|
		vty_out(vty, "PIM Join/Prune debugging is on\n");
 | 
						|
	} else if (registers) {
 | 
						|
		PIM_DO_DEBUG_PIM_REG;
 | 
						|
		vty_out(vty, "PIM Register debugging is on\n");
 | 
						|
	} else {
 | 
						|
		PIM_DO_DEBUG_PIM_PACKETS;
 | 
						|
		vty_out(vty, "PIM Packet debugging is on\n");
 | 
						|
	}
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_no_debug_pim_packets_cmd(const char *hello, const char *joins,
 | 
						|
				 const char *registers, struct vty *vty)
 | 
						|
{
 | 
						|
	if (hello) {
 | 
						|
		PIM_DONT_DEBUG_PIM_HELLO;
 | 
						|
		vty_out(vty, "PIM Hello debugging is off\n");
 | 
						|
	} else if (joins) {
 | 
						|
		PIM_DONT_DEBUG_PIM_J_P;
 | 
						|
		vty_out(vty, "PIM Join/Prune debugging is off\n");
 | 
						|
	} else if (registers) {
 | 
						|
		PIM_DONT_DEBUG_PIM_REG;
 | 
						|
		vty_out(vty, "PIM Register debugging is off\n");
 | 
						|
	} else {
 | 
						|
		PIM_DONT_DEBUG_PIM_PACKETS;
 | 
						|
		vty_out(vty, "PIM Packet debugging is off\n");
 | 
						|
	}
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_rpf_helper(const char *vrf, struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	pim_show_rpf(pim, vty, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_rpf_vrf_all_helper(struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
		pim_show_rpf(vrf->info, vty, json_vrf);
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_rp_helper(const char *vrf, struct vty *vty, const char *group_str,
 | 
						|
		       const struct prefix *group, bool json)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	struct prefix *range = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (group_str) {
 | 
						|
		range = prefix_new();
 | 
						|
		prefix_copy(range, group);
 | 
						|
		apply_mask(range);
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	pim_rp_show_information(pim, range, vty, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	prefix_free(&range);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_rp_vrf_all_helper(struct vty *vty, const char *group_str,
 | 
						|
			       const struct prefix *group, bool json)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
	struct prefix *range = NULL;
 | 
						|
 | 
						|
	if (group_str) {
 | 
						|
		range = prefix_new();
 | 
						|
		prefix_copy(range, group);
 | 
						|
		apply_mask(range);
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
		pim_rp_show_information(vrf->info, range, vty, json_vrf);
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	prefix_free(&range);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_secondary_helper(const char *vrf, struct vty *vty)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_neighbors_secondary(pim, vty);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_statistics_helper(const char *vrf, struct vty *vty,
 | 
						|
			       const char *word, bool uj)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (word)
 | 
						|
		pim_show_statistics(pim, vty, word, uj);
 | 
						|
	else
 | 
						|
		pim_show_statistics(pim, vty, NULL, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_upstream_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
 | 
						|
			     pim_addr g, bool json)
 | 
						|
{
 | 
						|
	pim_sgaddr sg = {0};
 | 
						|
	struct vrf *v;
 | 
						|
	struct pim_instance *pim;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v) {
 | 
						|
		vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	if (!pim_addr_is_any(s_or_g)) {
 | 
						|
		if (!pim_addr_is_any(g)) {
 | 
						|
			sg.src = s_or_g;
 | 
						|
			sg.grp = g;
 | 
						|
		} else
 | 
						|
			sg.grp = s_or_g;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_upstream(pim, vty, &sg, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_upstream_vrf_all_helper(struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	pim_sgaddr sg = {0};
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
		pim_show_upstream(vrf->info, vty, &sg, json_vrf);
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_upstream_join_desired_helper(const char *vrf, struct vty *vty,
 | 
						|
					  bool uj)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_join_desired(pim, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_upstream_rpf_helper(const char *vrf, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_upstream_rpf(pim, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_state_helper(const char *vrf, struct vty *vty,
 | 
						|
			  const char *s_or_g_str, const char *g_str, bool json)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	pim_show_state(pim, vty, s_or_g_str, g_str, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_state_vrf_all_helper(struct vty *vty, const char *s_or_g_str,
 | 
						|
				  const char *g_str, bool json)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
		pim_show_state(vrf->info, vty, s_or_g_str, g_str, json_vrf);
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_multicast_helper(const char *vrf, struct vty *vty)
 | 
						|
{
 | 
						|
	struct vrf *v;
 | 
						|
	struct pim_instance *pim;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_cmd_show_ip_multicast_helper(pim, vty);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_multicast_vrf_all_helper(struct vty *vty)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		pim_cmd_show_ip_multicast_helper(vrf->info, vty);
 | 
						|
	}
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_multicast_count_helper(const char *vrf, struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	show_multicast_interfaces(pim, vty, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_multicast_count_vrf_all_helper(struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
 | 
						|
		show_multicast_interfaces(vrf->info, vty, json_vrf);
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_mroute_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
 | 
						|
			   pim_addr g, bool fill, bool json)
 | 
						|
{
 | 
						|
	pim_sgaddr sg = {0};
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	if (!pim_addr_is_any(s_or_g)) {
 | 
						|
		if (!pim_addr_is_any(g)) {
 | 
						|
			sg.src = s_or_g;
 | 
						|
			sg.grp = g;
 | 
						|
		} else
 | 
						|
			sg.grp = s_or_g;
 | 
						|
	}
 | 
						|
 | 
						|
	show_mroute(pim, vty, &sg, fill, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_mroute_vrf_all_helper(struct vty *vty, bool fill, bool json)
 | 
						|
{
 | 
						|
	pim_sgaddr sg = {0};
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
		show_mroute(vrf->info, vty, &sg, fill, json_vrf);
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_mroute_count_helper(const char *vrf, struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	show_mroute_count(pim, vty, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_mroute_count_vrf_all_helper(struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
 | 
						|
		show_mroute_count(vrf->info, vty, json_vrf);
 | 
						|
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_mroute_summary_helper(const char *vrf, struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	show_mroute_summary(pim, vty, json_parent);
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_mroute_summary_vrf_all_helper(struct vty *vty, bool json)
 | 
						|
{
 | 
						|
	struct vrf *vrf;
 | 
						|
	json_object *json_parent = NULL;
 | 
						|
	json_object *json_vrf = NULL;
 | 
						|
 | 
						|
	if (json)
 | 
						|
		json_parent = json_object_new_object();
 | 
						|
 | 
						|
	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
 | 
						|
		if (!json)
 | 
						|
			vty_out(vty, "VRF: %s\n", vrf->name);
 | 
						|
		else
 | 
						|
			json_vrf = json_object_new_object();
 | 
						|
 | 
						|
		show_mroute_summary(vrf->info, vty, json_vrf);
 | 
						|
 | 
						|
		if (json)
 | 
						|
			json_object_object_add(json_parent, vrf->name,
 | 
						|
					       json_vrf);
 | 
						|
	}
 | 
						|
 | 
						|
	if (json)
 | 
						|
		vty_json(vty, json_parent);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_interface_traffic(struct pim_instance *pim, struct vty *vty,
 | 
						|
				bool uj)
 | 
						|
{
 | 
						|
	struct interface *ifp = NULL;
 | 
						|
	struct pim_interface *pim_ifp = NULL;
 | 
						|
	json_object *json = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		json = json_object_new_object();
 | 
						|
	else {
 | 
						|
		vty_out(vty, "\n");
 | 
						|
		vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
 | 
						|
			"Interface", "       HELLO", "       JOIN",
 | 
						|
			"      PRUNE", "   REGISTER", "REGISTER-STOP",
 | 
						|
			"  ASSERT", "  BSM");
 | 
						|
		vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
 | 
						|
			"       Rx/Tx", "       Rx/Tx", "      Rx/Tx",
 | 
						|
			"      Rx/Tx", "     Rx/Tx", "    Rx/Tx", "   Rx/Tx");
 | 
						|
		vty_out(vty,
 | 
						|
			"---------------------------------------------------------------------------------------------------------------\n");
 | 
						|
	}
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (uj) {
 | 
						|
			json_row = json_object_new_object();
 | 
						|
			json_object_pim_ifp_add(json_row, ifp);
 | 
						|
			json_object_int_add(json_row, "helloRx",
 | 
						|
					    pim_ifp->pim_ifstat_hello_recv);
 | 
						|
			json_object_int_add(json_row, "helloTx",
 | 
						|
					    pim_ifp->pim_ifstat_hello_sent);
 | 
						|
			json_object_int_add(json_row, "joinRx",
 | 
						|
					    pim_ifp->pim_ifstat_join_recv);
 | 
						|
			json_object_int_add(json_row, "joinTx",
 | 
						|
					    pim_ifp->pim_ifstat_join_send);
 | 
						|
			json_object_int_add(json_row, "pruneRx",
 | 
						|
					    pim_ifp->pim_ifstat_prune_recv);
 | 
						|
			json_object_int_add(json_row, "pruneTx",
 | 
						|
					    pim_ifp->pim_ifstat_prune_send);
 | 
						|
			json_object_int_add(json_row, "registerRx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_recv);
 | 
						|
			json_object_int_add(json_row, "registerTx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_send);
 | 
						|
			json_object_int_add(json_row, "registerStopRx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_stop_recv);
 | 
						|
			json_object_int_add(json_row, "registerStopTx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_stop_send);
 | 
						|
			json_object_int_add(json_row, "assertRx",
 | 
						|
					    pim_ifp->pim_ifstat_assert_recv);
 | 
						|
			json_object_int_add(json_row, "assertTx",
 | 
						|
					    pim_ifp->pim_ifstat_assert_send);
 | 
						|
			json_object_int_add(json_row, "bsmRx",
 | 
						|
					    pim_ifp->pim_ifstat_bsm_rx);
 | 
						|
			json_object_int_add(json_row, "bsmTx",
 | 
						|
					    pim_ifp->pim_ifstat_bsm_tx);
 | 
						|
			json_object_object_add(json, ifp->name, json_row);
 | 
						|
		} else {
 | 
						|
			vty_out(vty,
 | 
						|
				"%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
 | 
						|
				"/%-7" PRIu64 "\n",
 | 
						|
				ifp->name, pim_ifp->pim_ifstat_hello_recv,
 | 
						|
				pim_ifp->pim_ifstat_hello_sent,
 | 
						|
				pim_ifp->pim_ifstat_join_recv,
 | 
						|
				pim_ifp->pim_ifstat_join_send,
 | 
						|
				pim_ifp->pim_ifstat_prune_recv,
 | 
						|
				pim_ifp->pim_ifstat_prune_send,
 | 
						|
				pim_ifp->pim_ifstat_reg_recv,
 | 
						|
				pim_ifp->pim_ifstat_reg_send,
 | 
						|
				pim_ifp->pim_ifstat_reg_stop_recv,
 | 
						|
				pim_ifp->pim_ifstat_reg_stop_send,
 | 
						|
				pim_ifp->pim_ifstat_assert_recv,
 | 
						|
				pim_ifp->pim_ifstat_assert_send,
 | 
						|
				pim_ifp->pim_ifstat_bsm_rx,
 | 
						|
				pim_ifp->pim_ifstat_bsm_tx);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_interface_traffic_single(struct pim_instance *pim,
 | 
						|
				       struct vty *vty, const char *ifname,
 | 
						|
				       bool uj)
 | 
						|
{
 | 
						|
	struct interface *ifp = NULL;
 | 
						|
	struct pim_interface *pim_ifp = NULL;
 | 
						|
	json_object *json = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
	uint8_t found_ifname = 0;
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		json = json_object_new_object();
 | 
						|
	else {
 | 
						|
		vty_out(vty, "\n");
 | 
						|
		vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
 | 
						|
			"Interface", "    HELLO", "    JOIN", "   PRUNE",
 | 
						|
			"   REGISTER", "  REGISTER-STOP", "  ASSERT",
 | 
						|
			"    BSM");
 | 
						|
		vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
 | 
						|
			"      Rx/Tx", "     Rx/Tx", "    Rx/Tx", "    Rx/Tx",
 | 
						|
			"     Rx/Tx", "    Rx/Tx", "    Rx/Tx");
 | 
						|
		vty_out(vty,
 | 
						|
			"-------------------------------------------------------------------------------------------------------------------------------\n");
 | 
						|
	}
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		if (strcmp(ifname, ifp->name))
 | 
						|
			continue;
 | 
						|
 | 
						|
		pim_ifp = ifp->info;
 | 
						|
 | 
						|
		if (!pim_ifp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		found_ifname = 1;
 | 
						|
		if (uj) {
 | 
						|
			json_row = json_object_new_object();
 | 
						|
			json_object_pim_ifp_add(json_row, ifp);
 | 
						|
			json_object_int_add(json_row, "helloRx",
 | 
						|
					    pim_ifp->pim_ifstat_hello_recv);
 | 
						|
			json_object_int_add(json_row, "helloTx",
 | 
						|
					    pim_ifp->pim_ifstat_hello_sent);
 | 
						|
			json_object_int_add(json_row, "joinRx",
 | 
						|
					    pim_ifp->pim_ifstat_join_recv);
 | 
						|
			json_object_int_add(json_row, "joinTx",
 | 
						|
					    pim_ifp->pim_ifstat_join_send);
 | 
						|
			json_object_int_add(json_row, "pruneRx",
 | 
						|
					    pim_ifp->pim_ifstat_prune_recv);
 | 
						|
			json_object_int_add(json_row, "pruneTx",
 | 
						|
					    pim_ifp->pim_ifstat_prune_send);
 | 
						|
			json_object_int_add(json_row, "registerRx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_recv);
 | 
						|
			json_object_int_add(json_row, "registerTx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_send);
 | 
						|
			json_object_int_add(json_row, "registerStopRx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_stop_recv);
 | 
						|
			json_object_int_add(json_row, "registerStopTx",
 | 
						|
					    pim_ifp->pim_ifstat_reg_stop_send);
 | 
						|
			json_object_int_add(json_row, "assertRx",
 | 
						|
					    pim_ifp->pim_ifstat_assert_recv);
 | 
						|
			json_object_int_add(json_row, "assertTx",
 | 
						|
					    pim_ifp->pim_ifstat_assert_send);
 | 
						|
			json_object_int_add(json_row, "bsmRx",
 | 
						|
					    pim_ifp->pim_ifstat_bsm_rx);
 | 
						|
			json_object_int_add(json_row, "bsmTx",
 | 
						|
					    pim_ifp->pim_ifstat_bsm_tx);
 | 
						|
 | 
						|
			json_object_object_add(json, ifp->name, json_row);
 | 
						|
		} else {
 | 
						|
			vty_out(vty,
 | 
						|
				"%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
 | 
						|
				"/%-7" PRIu64 "\n",
 | 
						|
				ifp->name, pim_ifp->pim_ifstat_hello_recv,
 | 
						|
				pim_ifp->pim_ifstat_hello_sent,
 | 
						|
				pim_ifp->pim_ifstat_join_recv,
 | 
						|
				pim_ifp->pim_ifstat_join_send,
 | 
						|
				pim_ifp->pim_ifstat_prune_recv,
 | 
						|
				pim_ifp->pim_ifstat_prune_send,
 | 
						|
				pim_ifp->pim_ifstat_reg_recv,
 | 
						|
				pim_ifp->pim_ifstat_reg_send,
 | 
						|
				pim_ifp->pim_ifstat_reg_stop_recv,
 | 
						|
				pim_ifp->pim_ifstat_reg_stop_send,
 | 
						|
				pim_ifp->pim_ifstat_assert_recv,
 | 
						|
				pim_ifp->pim_ifstat_assert_send,
 | 
						|
				pim_ifp->pim_ifstat_bsm_rx,
 | 
						|
				pim_ifp->pim_ifstat_bsm_tx);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
	else if (!found_ifname)
 | 
						|
		vty_out(vty, "%% No such interface\n");
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_interface_traffic_helper(const char *vrf, const char *if_name,
 | 
						|
				      struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	if (if_name)
 | 
						|
		pim_show_interface_traffic_single(v->info, vty, if_name, uj);
 | 
						|
	else
 | 
						|
		pim_show_interface_traffic(v->info, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void clear_pim_interfaces(struct pim_instance *pim)
 | 
						|
{
 | 
						|
	struct interface *ifp;
 | 
						|
 | 
						|
	FOR_ALL_INTERFACES (pim->vrf, ifp) {
 | 
						|
		if (ifp->info)
 | 
						|
			pim_neighbor_delete_all(ifp, "interface cleared");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	char uptime[10];
 | 
						|
	char last_bsm_seen[10];
 | 
						|
	time_t now;
 | 
						|
	char bsr_state[20];
 | 
						|
	json_object *json = NULL;
 | 
						|
 | 
						|
	if (pim_addr_is_any(pim->global_scope.current_bsr)) {
 | 
						|
		pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
				pim->global_scope.current_bsr_first_ts);
 | 
						|
		pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
 | 
						|
				pim->global_scope.current_bsr_last_ts);
 | 
						|
	}
 | 
						|
 | 
						|
	else {
 | 
						|
		now = pim_time_monotonic_sec();
 | 
						|
		pim_time_uptime(uptime, sizeof(uptime),
 | 
						|
				(now - pim->global_scope.current_bsr_first_ts));
 | 
						|
		pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
 | 
						|
				now - pim->global_scope.current_bsr_last_ts);
 | 
						|
	}
 | 
						|
 | 
						|
	switch (pim->global_scope.state) {
 | 
						|
	case NO_INFO:
 | 
						|
		strlcpy(bsr_state, "NO_INFO", sizeof(bsr_state));
 | 
						|
		break;
 | 
						|
	case ACCEPT_ANY:
 | 
						|
		strlcpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
 | 
						|
		break;
 | 
						|
	case ACCEPT_PREFERRED:
 | 
						|
		strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		strlcpy(bsr_state, "", sizeof(bsr_state));
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		json = json_object_new_object();
 | 
						|
		json_object_string_addf(json, "bsr", "%pPA",
 | 
						|
					&pim->global_scope.current_bsr);
 | 
						|
		json_object_int_add(json, "priority",
 | 
						|
				    pim->global_scope.current_bsr_prio);
 | 
						|
		json_object_int_add(json, "fragmentTag",
 | 
						|
				    pim->global_scope.bsm_frag_tag);
 | 
						|
		json_object_string_add(json, "state", bsr_state);
 | 
						|
		json_object_string_add(json, "upTime", uptime);
 | 
						|
		json_object_string_add(json, "lastBsmSeen", last_bsm_seen);
 | 
						|
	}
 | 
						|
 | 
						|
	else {
 | 
						|
		vty_out(vty, "PIMv2 Bootstrap information\n");
 | 
						|
		vty_out(vty, "Current preferred BSR address: %pPA\n",
 | 
						|
			&pim->global_scope.current_bsr);
 | 
						|
		vty_out(vty,
 | 
						|
			"Priority        Fragment-Tag       State           UpTime\n");
 | 
						|
		vty_out(vty, "  %-12d    %-12d    %-13s    %7s\n",
 | 
						|
			pim->global_scope.current_bsr_prio,
 | 
						|
			pim->global_scope.bsm_frag_tag, bsr_state, uptime);
 | 
						|
		vty_out(vty, "Last BSM seen: %s\n", last_bsm_seen);
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = pim_get_pim_instance(v->vrf_id);
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_bsr(v->info, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/*Display the group-rp mappings */
 | 
						|
static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
 | 
						|
					    struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct bsgrp_node *bsgrp;
 | 
						|
	struct bsm_rpinfo *bsm_rp;
 | 
						|
	struct route_node *rn;
 | 
						|
	json_object *json = NULL;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
	struct ttable *tt = NULL;
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		json = json_object_new_object();
 | 
						|
		json_object_string_addf(json, "BSR Address", "%pPA",
 | 
						|
					&pim->global_scope.current_bsr);
 | 
						|
	} else
 | 
						|
		vty_out(vty, "BSR Address  %pPA\n",
 | 
						|
			&pim->global_scope.current_bsr);
 | 
						|
 | 
						|
	for (rn = route_top(pim->global_scope.bsrp_table); rn;
 | 
						|
	     rn = route_next(rn)) {
 | 
						|
		bsgrp = (struct bsgrp_node *)rn->info;
 | 
						|
 | 
						|
		if (!bsgrp)
 | 
						|
			continue;
 | 
						|
 | 
						|
		char grp_str[PREFIX_STRLEN];
 | 
						|
 | 
						|
		prefix2str(&bsgrp->group, grp_str, sizeof(grp_str));
 | 
						|
 | 
						|
		if (uj) {
 | 
						|
			json_object_object_get_ex(json, grp_str, &json_group);
 | 
						|
			if (!json_group) {
 | 
						|
				json_group = json_object_new_object();
 | 
						|
				json_object_object_add(json, grp_str,
 | 
						|
						       json_group);
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			vty_out(vty, "Group Address %pFX\n", &bsgrp->group);
 | 
						|
			vty_out(vty, "--------------------------\n");
 | 
						|
			/* Prepare table. */
 | 
						|
			tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
			ttable_add_row(tt, "Rp Address|priority|Holdtime|Hash");
 | 
						|
			tt->style.cell.rpad = 2;
 | 
						|
			tt->style.corner = '+';
 | 
						|
			ttable_restyle(tt);
 | 
						|
 | 
						|
			ttable_add_row(tt, "%s|%c|%c|%c", "(ACTIVE)", ' ', ' ',
 | 
						|
				       ' ');
 | 
						|
		}
 | 
						|
 | 
						|
		frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
 | 
						|
			if (uj) {
 | 
						|
				json_row = json_object_new_object();
 | 
						|
				json_object_string_addf(json_row, "Rp Address",
 | 
						|
							"%pPA",
 | 
						|
							&bsm_rp->rp_address);
 | 
						|
				json_object_int_add(json_row, "Rp HoldTime",
 | 
						|
						    bsm_rp->rp_holdtime);
 | 
						|
				json_object_int_add(json_row, "Rp Priority",
 | 
						|
						    bsm_rp->rp_prio);
 | 
						|
				json_object_int_add(json_row, "Hash Val",
 | 
						|
						    bsm_rp->hash);
 | 
						|
				json_object_object_addf(json_group, json_row,
 | 
						|
							"%pPA",
 | 
						|
							&bsm_rp->rp_address);
 | 
						|
 | 
						|
			} else {
 | 
						|
				ttable_add_row(
 | 
						|
					tt, "%pPA|%u|%u|%u",
 | 
						|
					&bsm_rp->rp_address, bsm_rp->rp_prio,
 | 
						|
					bsm_rp->rp_holdtime, bsm_rp->hash);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		/* Dump the generated table. */
 | 
						|
		if (tt) {
 | 
						|
			char *table = NULL;
 | 
						|
 | 
						|
			table = ttable_dump(tt, "\n");
 | 
						|
			vty_out(vty, "%s\n", table);
 | 
						|
			XFREE(MTYPE_TMP, table);
 | 
						|
			ttable_del(tt);
 | 
						|
			tt = NULL;
 | 
						|
		}
 | 
						|
		if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
 | 
						|
			vty_out(vty, "Active List is empty.\n");
 | 
						|
 | 
						|
		if (uj) {
 | 
						|
			json_object_int_add(json_group, "Pending RP count",
 | 
						|
					    bsgrp->pend_rp_cnt);
 | 
						|
		} else {
 | 
						|
			vty_out(vty, "(PENDING)\n");
 | 
						|
			vty_out(vty, "Pending RP count :%d\n",
 | 
						|
				bsgrp->pend_rp_cnt);
 | 
						|
			if (bsgrp->pend_rp_cnt) {
 | 
						|
				/* Prepare table. */
 | 
						|
				tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
 | 
						|
				ttable_add_row(
 | 
						|
					tt,
 | 
						|
					"Rp Address|priority|Holdtime|Hash");
 | 
						|
				tt->style.cell.rpad = 2;
 | 
						|
				tt->style.corner = '+';
 | 
						|
				ttable_restyle(tt);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
 | 
						|
			if (uj) {
 | 
						|
				json_row = json_object_new_object();
 | 
						|
				json_object_string_addf(json_row, "Rp Address",
 | 
						|
							"%pPA",
 | 
						|
							&bsm_rp->rp_address);
 | 
						|
				json_object_int_add(json_row, "Rp HoldTime",
 | 
						|
						    bsm_rp->rp_holdtime);
 | 
						|
				json_object_int_add(json_row, "Rp Priority",
 | 
						|
						    bsm_rp->rp_prio);
 | 
						|
				json_object_int_add(json_row, "Hash Val",
 | 
						|
						    bsm_rp->hash);
 | 
						|
				json_object_object_addf(json_group, json_row,
 | 
						|
							"%pPA",
 | 
						|
							&bsm_rp->rp_address);
 | 
						|
			} else {
 | 
						|
				ttable_add_row(
 | 
						|
					tt, "%pPA|%u|%u|%u",
 | 
						|
					&bsm_rp->rp_address, bsm_rp->rp_prio,
 | 
						|
					bsm_rp->rp_holdtime, bsm_rp->hash);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		/* Dump the generated table. */
 | 
						|
		if (tt) {
 | 
						|
			char *table = NULL;
 | 
						|
 | 
						|
			table = ttable_dump(tt, "\n");
 | 
						|
			vty_out(vty, "%s\n", table);
 | 
						|
			XFREE(MTYPE_TMP, table);
 | 
						|
			ttable_del(tt);
 | 
						|
		}
 | 
						|
		if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
 | 
						|
			vty_out(vty, "Partial List is empty\n");
 | 
						|
 | 
						|
		if (!uj)
 | 
						|
			vty_out(vty, "\n");
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_group_rp_mappings_info_helper(const char *vrf, struct vty *vty,
 | 
						|
					   bool uj)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_group_rp_mappings_info(v->info, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/* Display the bsm database details */
 | 
						|
static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	int count = 0;
 | 
						|
	int fragment = 1;
 | 
						|
	struct bsm_frag *bsfrag;
 | 
						|
	json_object *json = NULL;
 | 
						|
	json_object *json_group = NULL;
 | 
						|
	json_object *json_row = NULL;
 | 
						|
 | 
						|
	count = bsm_frags_count(pim->global_scope.bsm_frags);
 | 
						|
 | 
						|
	if (uj) {
 | 
						|
		json = json_object_new_object();
 | 
						|
		json_object_int_add(json, "Number of the fragments", count);
 | 
						|
	} else {
 | 
						|
		vty_out(vty, "Scope Zone: Global\n");
 | 
						|
		vty_out(vty, "Number of the fragments: %d\n", count);
 | 
						|
		vty_out(vty, "\n");
 | 
						|
	}
 | 
						|
 | 
						|
	frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
 | 
						|
		char grp_str[PREFIX_STRLEN];
 | 
						|
		struct bsmmsg_grpinfo *group;
 | 
						|
		struct bsmmsg_rpinfo *bsm_rpinfo;
 | 
						|
		struct prefix grp;
 | 
						|
		struct bsm_hdr *hdr;
 | 
						|
		pim_addr bsr_addr;
 | 
						|
		uint32_t offset = 0;
 | 
						|
		uint8_t *buf;
 | 
						|
		uint32_t len = 0;
 | 
						|
		uint32_t frag_rp_cnt = 0;
 | 
						|
 | 
						|
		buf = bsfrag->data;
 | 
						|
		len = bsfrag->size;
 | 
						|
 | 
						|
		/* skip pim header */
 | 
						|
		buf += PIM_MSG_HEADER_LEN;
 | 
						|
		len -= PIM_MSG_HEADER_LEN;
 | 
						|
 | 
						|
		hdr = (struct bsm_hdr *)buf;
 | 
						|
		/* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
 | 
						|
		memcpy(&bsr_addr, &hdr->bsr_addr.addr, sizeof(bsr_addr));
 | 
						|
 | 
						|
		/* BSM starts with bsr header */
 | 
						|
		buf += sizeof(struct bsm_hdr);
 | 
						|
		len -= sizeof(struct bsm_hdr);
 | 
						|
 | 
						|
		if (uj) {
 | 
						|
			json_object_string_addf(json, "BSR address", "%pPA",
 | 
						|
						&bsr_addr);
 | 
						|
			json_object_int_add(json, "BSR priority",
 | 
						|
					    hdr->bsr_prio);
 | 
						|
			json_object_int_add(json, "Hashmask Length",
 | 
						|
					    hdr->hm_len);
 | 
						|
			json_object_int_add(json, "Fragment Tag",
 | 
						|
					    ntohs(hdr->frag_tag));
 | 
						|
		} else {
 | 
						|
			vty_out(vty, "BSM Fragment : %d\n", fragment);
 | 
						|
			vty_out(vty, "------------------\n");
 | 
						|
			vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
 | 
						|
				"BSR-Priority", "Hashmask-len", "Fragment-Tag");
 | 
						|
			vty_out(vty, "%-15pPA %-15d %-15d %-15d\n", &bsr_addr,
 | 
						|
				hdr->bsr_prio, hdr->hm_len,
 | 
						|
				ntohs(hdr->frag_tag));
 | 
						|
		}
 | 
						|
 | 
						|
		vty_out(vty, "\n");
 | 
						|
 | 
						|
		while (offset < len) {
 | 
						|
			group = (struct bsmmsg_grpinfo *)buf;
 | 
						|
 | 
						|
			if (group->group.family == PIM_MSG_ADDRESS_FAMILY_IPV4)
 | 
						|
				grp.family = AF_INET;
 | 
						|
			else if (group->group.family ==
 | 
						|
				 PIM_MSG_ADDRESS_FAMILY_IPV6)
 | 
						|
				grp.family = AF_INET6;
 | 
						|
 | 
						|
			grp.prefixlen = group->group.mask;
 | 
						|
#if PIM_IPV == 4
 | 
						|
			grp.u.prefix4 = group->group.addr;
 | 
						|
#else
 | 
						|
			grp.u.prefix6 = group->group.addr;
 | 
						|
#endif
 | 
						|
 | 
						|
			prefix2str(&grp, grp_str, sizeof(grp_str));
 | 
						|
 | 
						|
			buf += sizeof(struct bsmmsg_grpinfo);
 | 
						|
			offset += sizeof(struct bsmmsg_grpinfo);
 | 
						|
 | 
						|
			if (uj) {
 | 
						|
				json_object_object_get_ex(json, grp_str,
 | 
						|
							  &json_group);
 | 
						|
				if (!json_group) {
 | 
						|
					json_group = json_object_new_object();
 | 
						|
					json_object_int_add(json_group,
 | 
						|
							    "Rp Count",
 | 
						|
							    group->rp_count);
 | 
						|
					json_object_int_add(
 | 
						|
						json_group, "Fragment Rp count",
 | 
						|
						group->frag_rp_count);
 | 
						|
					json_object_object_add(json, grp_str,
 | 
						|
							       json_group);
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				vty_out(vty, "Group : %s\n", grp_str);
 | 
						|
				vty_out(vty, "-------------------\n");
 | 
						|
				vty_out(vty, "Rp Count:%d\n", group->rp_count);
 | 
						|
				vty_out(vty, "Fragment Rp Count : %d\n",
 | 
						|
					group->frag_rp_count);
 | 
						|
			}
 | 
						|
 | 
						|
			frag_rp_cnt = group->frag_rp_count;
 | 
						|
 | 
						|
			if (!frag_rp_cnt)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (!uj)
 | 
						|
				vty_out(vty,
 | 
						|
					"RpAddress     HoldTime     Priority\n");
 | 
						|
 | 
						|
			while (frag_rp_cnt--) {
 | 
						|
				pim_addr rp_addr;
 | 
						|
 | 
						|
				bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
 | 
						|
				/* unaligned, again */
 | 
						|
				memcpy(&rp_addr, &bsm_rpinfo->rpaddr.addr,
 | 
						|
				       sizeof(rp_addr));
 | 
						|
 | 
						|
				buf += sizeof(struct bsmmsg_rpinfo);
 | 
						|
				offset += sizeof(struct bsmmsg_rpinfo);
 | 
						|
 | 
						|
				if (uj) {
 | 
						|
					json_row = json_object_new_object();
 | 
						|
					json_object_string_addf(
 | 
						|
						json_row, "Rp Address", "%pPA",
 | 
						|
						&rp_addr);
 | 
						|
					json_object_int_add(
 | 
						|
						json_row, "Rp HoldTime",
 | 
						|
						ntohs(bsm_rpinfo->rp_holdtime));
 | 
						|
					json_object_int_add(json_row,
 | 
						|
							    "Rp Priority",
 | 
						|
							    bsm_rpinfo->rp_pri);
 | 
						|
					json_object_object_addf(
 | 
						|
						json_group, json_row, "%pPA",
 | 
						|
						&rp_addr);
 | 
						|
				} else {
 | 
						|
					vty_out(vty, "%-15pPA %-12d %d\n",
 | 
						|
						&rp_addr,
 | 
						|
						ntohs(bsm_rpinfo->rp_holdtime),
 | 
						|
						bsm_rpinfo->rp_pri);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			vty_out(vty, "\n");
 | 
						|
		}
 | 
						|
 | 
						|
		fragment++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (uj)
 | 
						|
		vty_json(vty, json);
 | 
						|
}
 | 
						|
 | 
						|
int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj)
 | 
						|
{
 | 
						|
	struct pim_instance *pim;
 | 
						|
	struct vrf *v;
 | 
						|
 | 
						|
	v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
 | 
						|
 | 
						|
	if (!v)
 | 
						|
		return CMD_WARNING;
 | 
						|
 | 
						|
	pim = v->info;
 | 
						|
 | 
						|
	if (!pim) {
 | 
						|
		vty_out(vty, "%% Unable to find pim instance\n");
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	pim_show_bsm_db(v->info, vty, uj);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 |