#!/pkg/bin/ksh
# ---------------------------------------------------------------------
# platform_show_tech_mcast_spirit -- Runs eXR based ASR9K specific 
#     commands for 'show tech-support multicast' command.
#
# November 2015 - gcp-ipmc team
#
# Copyright (c) 2015-2017, 2020-2021 by Cisco Systems, Inc.
# All rights reserved.
#----------------------------------------------------------------------

#
# This script runs all the HFR specific mutlicast commands for show
# tech-support multicast. The script is invoked by show_tech_mcast.
# 
# Options:
#   -n nodeid         Run commands on specified node id.
#   -m nodename       Specify the printable node name of the node id.
#   -g group          Run route commands for specified group addr. (optional)
#   -s source         Run route commands for specified source addr. (optional)
#   

# *****************************************************************
#  Functions for formatting
#
#  All inherited from infra/showtech. They are supposed to convert 
#  some command libraries into script module, so the formatting 
#  will be in sync with other show tech output.#
# *****************************************************************

# Set address-family specific multicast addresses
# Also set address-family specific show commands.
ip2hex()
{
   set -A n2h 0 1 2 3 4 5 6 7 8 9 a b c d e f
   nib2hex() { echo -e -n ${n2h[$1]}; }

   for octet in $(IFS=.; echo -e $1); do
     nib2hex $((octet / 16))
     nib2hex $((octet % 16))
   done
   echo
}

ipv62hex()
{
   str=$1
   hex=""
        # blkptr and blkptr_end is used to point to the begining and end of
        # a 4 hex digit block
        typeset -i blkptr=1
        typeset -i blkptr_end

        # For each set of 4 digits
        while [ blkptr -lt 39 ] ; do
            blkptr_end=$blkptr+3
            v6_addr_part=$(echo -e ${str} | cut -c ${blkptr}-${blkptr_end})
            v6_hex="$hex$v6_addr_part"
            blkptr=$blkptr+5
        done

    # Strip all trailing :
    hex=${hex%%:*}
    echo -e $hex
}

#
# Attempts to determine what type of linecard we are executing
# on.
#
set_lc_type() {

   if [ -x $BIN_DIR/$PRM_EXEC_NAME_TR ] ||
      [ -x $BIN_DIR/$PRM_EXEC_NAME_TY ] ||
      [ -x $BIN_DIR/$PRM_EXEC_NAME_LS ] ||
      [ -x $BIN_DIR/$PRM_EXEC_NAME_TO ]; then
        lc_type="LC_NP"
   elif [ -x $BIN_DIR/$DPC_RM_SVR_NAME ]; then
        lc_type="LC_SS"
   else
        lc_type="UNKNOWN"
   fi
}

#
# Attempts to determine what kind of platform we are executing on
# Assume Viking by default
#
set_rp_type() {

    is_ss_rp=`/pkg/bin/show_platform_sysdb | grep IOSXRV9000 | wc -l`

    if [[ $is_ss_rp -gt 0 ]]; then
        rp_type="RP_SUNSTONE"
    else
        rp_type="RP_VIKING"
    fi
    echo -e "RP Type: $rp_type ($is_ss_rp)\n"
}

# ***************************
#  Function to run commands 
# ***************************

#
# execute_lc_command() prints the command description and issues the command.
# Commands with group option will get executed only if group is specified.
# 

exec_lc_command() {
    cmd=$1
    node_id=$2
    group_hex=$3
    source_hex=$4
    cmd_vrf_option=$5
    addr_family=$6  

    vkg_cmd=""
    if [[ $group != "" && $group != "unspecified" ]]; then
       vkg_cmd="$vkg_cmd -g $group_hex"
    fi
    if [[ $source != "" && $source != "unspecified" ]]; then
       vkg_cmd="$vkg_cmd -s $source_hex"
    fi
    if [[ -n "$cmd_vrf_option" ]]; then
       vkg_vrf="$vkg_vrf $cmd_vrf_option"
       vkg_cmd="$vkg_cmd $cmd_vrf_option"
    fi

    eval "$cmd $node_id $vkg_cmd"
    echo -e "\n##### end clock: \c"; iosclock -d 0
}


# disp_lc_cmd_title() prints the command description.
# Commands with group/source option will get executed with group/source specified.
# 
# Argument $1: command_desc
# Argumnet $2: printable node name in the form of x/x/x
# Argument $3: group
# Argument $4: source
# Argument $5: vrf option
disp_lc_cmd_title() {
    cmd_desc=$1
    node_name=$2
    group=$3
    source=$4
    cmd_vrf_option=$5

    vkg_cmd=""
    if [[ $group != "" && $group != "unspecified" ]]; then
       vkg_cmd="$vkg_cmd -g $group"
    fi
    if [[ $source != "" && $source != "unspecified" ]]; then
       vkg_cmd="$vkg_cmd -s $source"
    fi
    if [[ -n "$cmd_vrf_option" ]]; then
       vkg_cmd="$vkg_cmd $cmd_vrf_option"
    fi

    print_heading "$cmd_desc $node_name $vkg_cmd" "-"
    echo -e "----------------------------------------------------------------\n"
    echo -e "$cmd_desc $node_name $vkg_cmd\n"
    echo -e "----------------------------------------------------------------\n"
    echo -e "##### start clock: \c"; iosclock -d 0
}

# ******************
#  Main starts here 
# ******************

. /pkg/bin/show_tech_main_fragment

#
# Set the default values for the argument variables.
#
card_type=`node_type`
addr_type="unspecified"
node_id="unspecified"
node_name="unspecified"
group="unspecified"
source="unspecified"
vrf_name="unspecified"
group_hex="unspecified"
source_hex="unspecified"

BIN_DIR=/pkg/bin
PRM_EXEC_NAME_TR="prm_server_tr"
PRM_EXEC_NAME_TY="prm_server_ty"
PRM_EXEC_NAME_TO="prm_server_to"
PRM_EXEC_NAME_LS="ls_prm_svr"
DPC_RM_SVR_NAME="dpc_rm_svr"

#
# Read in the arguments to the script. Node id must be in integer, node
# name must be in x/x/x format, group addr in dotted decimal format.
#
while [ $# -gt 0 ]; do
  case "$1" in 
     -c) card_type="$2"; shift 2;;
     -i) addr_type="$2"; shift 2;;
     -n) node_id="$2"; shift 2;;
     -m) node_name="$2"; shift 2;;
     -g) group="$2"; shift 2;;
     -s) source="$2"; shift 2;;
     -v) vrf_name="$2"; shift 2;; 
     -x) source_hex="$2"; shift 2;;
     -y) group_hex="$2"; shift 2;;
     -u) __tar_file_directory_on_node="$2"; shift 2;;
     -f) __tar_file_directory_on_node="$2"; shift 2;;
     node*) shift 1;;
     *)  echo -e "Invalid arguments to platform_show_tech_mcast _$2_"; shift 2;;
  esac
done


if [[ $addr_type == "unspecified" ]]; then
    echo -e "platform_show_tech_mcast_spirit: address family is not specified, use ipv4"
    addr_type="ipv4"
fi

if [[ $node_id == "unspecified" || $node_name == "unspecified" ]]; then
    echo -e "platform_show_tech_mcast_spirit: node name and node id are required args"
    exit
fi

if [[ $group != "unspecified" ]]; then
    if [[ $addr_type = "ipv6" ]]; then 
        if [[ $group != *:*:*:*:*:*:*:* ]]; then
        echo -e "platform_show_tech_mcast_spirit: invalid ipv6 group format $group"
        exit
        fi
    else
        if [[ $group != *.*.*.* ]]; then
        echo -e "platform_show_tech_mcast_spirit: invalid ipv4 group format $group"
        exit
        fi
    fi
fi

if [[ $source != "unspecified" ]]; then
    if [[ $addr_type = "ipv6" ]]; then 
        if [[ $source != *:*:*:*:*:*:*:* ]]; then
        echo -e "platform_show_tech_mcast_spirit: invalid ipv6 group format $source"
        exit
        fi
    else
        if [[ $source != *.*.*.* ]]; then
        echo -e "platform_show_tech_mcast_spirit: invalid ipv4 group format $source"
        exit
        fi
    fi
fi

if [[ $addr_type = "ipv4" ]] ;then 
    show_mrib_vkg_ltrace_ksh="mrib_show_ltrace_platf -A -Z"
    show_mrib_vkg_connections_ksh="mrib4_show_client -c -d"
    show_mrib_vkg_intf_all_ksh="mrib4_show_client -a -i -d"
    show_mrib_vkg_regdb_all_ksh="mrib4_show_client -r -a -d"
    show_mfwd_vkg_ltrace_ksh="ipv4_mfwd_show_ltrace"
    show_mfwd_hw_vkg_ksh="gcp_ipmc_ipv4_cmn_show_client -Z -l $node_id"
    show_mfwd_hw_vkg_connection_ksh="gcp_ipmc_ipv4_cmn_show_client -N -l $node_id"
    show_mfwd_hw_vkg_resource_counter_ksh="gcp_ipmc_ipv4_cmn_show_client -R -l $node_id -d"
    show_mfwd_hw_vkg_ltrace_ksh="gcp_ipmc_ipv4_cmn_show_ltrace -i $node_id"
    show_mfwd_hw_vkg_mlib_ksh="gcp_ipmc_ipv4_cmn_show_ltrace -B -i $node_id"
    mfwd_proc_name="ipv4_mfwd_partner"
    show_mrib_vkg_resources_nv_edge_ksh="mrib4_show_client -e -d"
else
    show_mrib_vkg_ltrace_ksh="mrib6_show_ltrace_platf -A -Z"
    show_mrib_vkg_connections_ksh="mrib6_show_client -c -d"
    show_mrib_vkg_intf_all_ksh="mrib6_show_client -a -i -d"
    show_mrib_vkg_regdb_all_ksh="mrib6_show_client -r -a -d"
    show_mfwd_vkg_ltrace_ksh="ipv6_mfwd_show_ltrace"
    show_mfwd_hw_vkg_ksh="gcp_ipmc_ipv6_cmn_show_client -Z -l $node_id"
    show_mfwd_hw_vkg_connection_ksh="gcp_ipmc_ipv6_cmn_show_client -N -l $node_id"
    show_mfwd_hw_vkg_resource_counter_ksh="gcp_ipmc_ipv6_cmn_show_client -R -l $node_id -d"
    show_mfwd_hw_vkg_ltrace_ksh="gcp_ipmc_ipv6_cmn_show_ltrace -i $node_id"
    show_mfwd_hw_vkg_mlib_ksh="gcp_ipmc_ipv6_cmn_show_ltrace -B -i $node_id"
    
    mfwd_proc_name="ipv6_mfwd_partner"
    show_mrib_vkg_resources_nv_edge_ksh="mrib6_show_client -e -d"
fi

mfwd_proc_pid=`sysmgr_show -o -p $mfwd_proc_name | grep -e PID | cut -c 27-`


# ***********************************************************
#  Show commands to be run by the show tech-support commands
# ***********************************************************

#
# For each command in the list, two mandatory variables are defined as:
# 1. <component>_command_desc[i] is the command that would be entered at the 
#    CLI. This is used as the headline for the command in the script output. 
# 2. <component>_command[i] is the executable obtained from "describe 
#    <show command>" at the CLI. Note that the location filter option must
#    be the last option in the string.
#
# The group filter is optional:
#
# 3. <component>_command_group[i] is the group filter option of the command.
#    Command with the group option will get executed only if a group addr
#    is specified, otherwise the show command is skipped.
#
# New commands may be added at any point in the list but the list must 
# remain numbered consecutively from 1 and must end with an empty command.
#
# To add a new command, first pick the right group it should go in --
# RP commands, LC commands that need a VRF option, LC commands that
# don't need VRF option, etc.  There are also sections for specific
# LC types.
#
# As described above, commands are specified in pairs of parallel
# arrays.  The *_exec[i] array has the command that the user
# would type at the CLI and the *__ksh[i] is the actual program
# and options that would get executed as a result of the user typing
# in that command at the CLI.
#
# So, find the right group to add to, copy/paste one of the existing
# pairs for that group, then update it for you new command.  Put it
# wherever you want the command output to appear within that group
# of commands.  Then, make sure that all of the pairs in that group
# are numbered consecutively and that the last entry in the
# *_command[last] entry is empty (it needs no companion description
# array entry.  It is simply the terminator of the list.
#
# Look for some commands similar to the one that you are adding
# and just mimic what is already there.
#

# Commands for sys
sys_exec[1]='show running-config'
sys__ksh[1]='nvgen -c -l 1 -t 1 -o 1'

sys_exec[2]='show logging'
sys__ksh[2]='show_logging'

sys_exec[3]=''
sys__ksh[3]=''

# Commands for RP only
rp_exec[1]="show platform"
rp__ksh[1]="show_sdr_sysdb -m"

rp_exec[2]="show version"
rp__ksh[2]="ng_show_version"

rp_exec[3]="Show build info"
rp__ksh[3]="cat /etc/build-info.txt"

rp_exec[4]="show install active"
rp__ksh[4]="sdr_instcmd show install active"

rp_exec[5]="show running-config"
rp__ksh[5]="nvgen -c -l 1 -t 1 -o 1"

rp_exec[6]="admin show inventory"
rp__ksh[6]="show_inventory -e"

rp_exec[7]="admin show running-config"
rp__ksh[7]="admin-cli-proxy-xr_run_cmd show running"

rp_exec[8]="show logging"
rp__ksh[8]="show_logging"

rp_exec[9]="show mrib platform trace all all"
rp__ksh[9]="$show_mrib_vkg_ltrace_ksh"

rp_exec[10]="show mrib platform connections detail"
rp__ksh[10]="$show_mrib_vkg_connections_ksh"

rp_exec[11]="show mrib platform interface all detail"
rp__ksh[11]="$show_mrib_vkg_intf_all_ksh"

rp_exec[12]="show mrib platform regdb all detail"
rp__ksh[12]="$show_mrib_vkg_regdb_all_ksh"

rp_exec[13]="show mrib mpls forwarding detail"
rp__ksh[13]="mrib_show_frr -p -D"

rp_exec[14]=''
rp__ksh[14]=''

#Viking only RP commands
vkg_rp_exec[1]="show mgid trace"
vkg_rp__ksh[1]="show_ltrace_mgid"

vkg_rp_exec[2]=''
vkg_rp__ksh[2]=''

#Sunstone only RP commands
ss_rp_exec[1]="show uidb index"
ss_rp__ksh[1]="sunstone_uidb_show index -a"

ss_rp_exec[2]=''
ss_rp__ksh[2]=''

# Commands to display state of the mfwd_partner process (All linecards)
lc_all_mfwd_proc_exec[1]="show processes blocked location"
lc_all_mfwd_proc__ksh[1]="sh_proc_ng_blocked"

lc_all_mfwd_proc_exec[2]="show process $mfwd_proc_name location $node_name"
lc_all_mfwd_proc__ksh[2]="sysmgr_show -o -p $mfwd_proc_name -n"

lc_all_mfwd_proc_exec[3]="follow process $mfwd_proc_pid iteration 1 location $node_name"
lc_all_mfwd_proc__ksh[3]="attach_process -p $mfwd_proc_pid -i 1 -n"

lc_all_mfwd_proc_exec[4]=''
lc_all_mfwd_proc__ksh[4]=''


# MFIB PD per-VRF commands at LC (All linecards)
#This is a hidden XR command. Command cannot be invoked from exec prompt, but kshell CLI can be
#executed from LC shell.
lc_all_mfwd_vrf_exec[1]="show mfib platform aggregator location $node_name"
lc_all_mfwd_vrf__ksh[1]="$show_mfwd_hw_vkg_ksh"

lc_all_mfwd_vrf_exec[2]=''
lc_all_mfwd_vrf__ksh[2]=''


# MFIB PD commands at LC (All linecards)
lc_all_mfwd_exec[1]="show mfib platform connection location $node_name"
lc_all_mfwd__ksh[1]="$show_mfwd_hw_vkg_connection_ksh"

lc_all_mfwd_exec[2]="show mfib platform resource-counter detail location $node_name"
lc_all_mfwd__ksh[2]="$show_mfwd_hw_vkg_resource_counter_ksh"

lc_all_mfwd_exec[3]=''
lc_all_mfwd__ksh[3]=''

# MFIB PD trace commands at LC (All linecards)
lc_all_mfwd_trace_exec[1]="show mfib platform ltrace location $node_name"
lc_all_mfwd_trace__ksh[1]="$show_mfwd_hw_vkg_ltrace_ksh"

lc_all_mfwd_trace_exec[2]="show mlib trace location $node_name"
lc_all_mfwd_trace__ksh[2]="$show_mfwd_hw_vkg_mlib_ksh"

lc_all_mfwd_trace_exec[3]=''
lc_all_mfwd_trace__ksh[3]=''

# Misc commands for LC (All linecards)
lc_all_exec[1]="show lpts pifib hardware entry statistics location $node_name"
lc_all__ksh[1]="platform_show_pifib -z 0x3 -i $node_id"

lc_all_exec[2]="show im database brief location $node_name"
lc_all__ksh[2]="im_show database -l 0x1 -h $node_id"

lc_all_exec[3]="show controllers mgidlib trace client 1 ops location $node_name"
lc_all__ksh[3]="show_ltrace_mgidlib -i $node_id -C 1 -V"

lc_all_exec[4]="show controllers mgidlib trace client 2 ops location $node_name"
lc_all__ksh[4]="show_ltrace_mgidlib -i $node_id -C 2 -V"

lc_all_exec[5]="show controllers mgidlib trace client 7 ops location $node_name"
lc_all__ksh[5]="show_ltrace_mgidlib -i $node_id -C 7 -V"

lc_all_exec[6]=''
lc_all__ksh[6]=''

# NP (Trident/Typhoon) LC specific commands
lc_np_exec[1]="show controller np ports all location $node_name"
lc_np__ksh[1]="prm_np_show ports -s $node_id"

lc_np_exec[2]="show controller np counters all location $node_name"
lc_np__ksh[2]="prm_np_show counters -s $node_id"

lc_np_exec[3]="show prm stats summary location $node_name"
lc_np__ksh[3]="prm_stats_show summary -s $node_id"

lc_np_exec[4]="show prm stats client all location $node_name"
lc_np__ksh[4]="prm_stats_show client -c 0x0 -s $node_id"

lc_np_exec[5]="show prm server trace error location $node_name"
lc_np__ksh[5]="show_prm_server_ltrace -E -i $node_id"

lc_np_exec[6]="show uidb index location $node_name"
lc_np__ksh[6]="uidb_show index -s $node_id"

lc_np_exec[7]="ship_show -c asr9k-ipmcast"
lc_np__ksh[7]="ship_show -c asr9k-ipmcast"

lc_np_exec[8]=''
lc_np__ksh[8]=''

# Sunstone LC specific commands (Non-DPA specific)
lc_ss_exec[1]="show controllers dpc rm trace all location $node_name"
lc_ss__ksh[1]="show_dpc_rm_svr_ltrace -i $node_id"

lc_ss_exec[2]="show controllers dpc rm resource table location $node_name"
lc_ss__ksh[2]="dpc_rm_svr_show table -l $node_id"

lc_ss_exec[3]="ship_show -c asr9k-ipmcast"
lc_ss__ksh[3]="ship_show -c asr9k-ipmcast"

lc_ss_exec[4]=''
lc_ss__ksh[4]=''

# Sunstone LC specific commands (DPA specific)
lc_ss_dpa_exec[1]="show controllers dpa uptime"
lc_ss_dpa__ksh[1]="dpa_exec -l default show dpa uptime"

lc_ss_dpa_exec[2]="show controllers dpa version"
lc_ss_dpa__ksh[2]="dpa_exec -l default show version"

lc_ss_dpa_exec[3]="show controllers dpa statistics global"
lc_ss_dpa__ksh[3]="dpa_exec -l default show dpa stat global"

lc_ss_dpa_exec[4]="show controllers dpa statistics connection"
lc_ss_dpa__ksh[4]="dpa_exec -l default show dpa connection"

lc_ss_dpa_exec[5]="show controllers dpa logging"
lc_ss_dpa__ksh[5]="dpa_exec -l default show dpa logging"

lc_ss_dpa_exec[6]=''
lc_ss_dpa__ksh[6]=''

execute_lc_commands() {
    exec_commands lc_all_mfwd_proc
    exec_commands lc_all_mfwd
    exec_commands lc_all_mfwd_vrf
    exec_commands lc_all_mfwd_trace
    exec_commands lc_all
}

display() {    
    if [[ $card_type == "SYS" ]]; then
        exec_commands sys
    else
        if [[ $card_type == "RP" ]]; then
            #
            # Do commands applicable to all RPs
            #
            
            exec_commands rp

            # Set the rp_type variable
            set_rp_type

            #
            # Now any RP specific commands
            #
            case $rp_type in
                "RP_SUNSTONE")
                    exec_commands ss_rp
                    ;;
                "RP_VIKING")
                    exec_commands vkg_rp
                    ;;
                *)
                    ;;
            esac
        fi #  [[ $card_type == "RP" ]]

        if [[ $card_type == "LC" ]]; then 

            vrf_opt=""

            if [[ $vrf_name != "" && $vrf_name != "unspecified" ]]; then
                vrf_opt="-v $vrf_name"
            fi

            #
            # Do commands applicable to all linecards
            #
            execute_lc_commands

            # Sets the 'lc_type' variable
            set_lc_type

            #
            # Now any card specific commands
            #
            case $lc_type in
                "LC_NP")
                    exec_commands lc_np
                    ;;
                "LC_SS")
                    exec_commands lc_ss
                    ;;
                *)
                    ;;
            esac

        fi # [[ $card_type == "LC" ]]
    fi        
}

# This function calls the display() function and sends the output to file if
# the file option has been set.
. /pkg/bin/show_tech_file_fragment
