#!/bin/bash
#
# calvados/zermatt_pkg/boot/scripts/pd-functions
# This script provides PD functions to other scripts.
#
# Copyright (c) 2014-2021 by Cisco Systems, Inc.
# All rights reserved.

# source PD-function library
if [ -f /etc/init.d/load_kernel_modules.sh ]; then
    source /etc/init.d/load_kernel_modules.sh
fi

CALV_ACTIVE_PART_FILE=/misc/config/calvados_launch_path_active.txt

#
# Get the file size in bytes, cross os
#
function filesize
{
    local file=$1
    size=`stat -c %s $file 2>/dev/null` # linux
    if [ $? -eq 0 ]; then
        echo $size
        return 0
    fi

    eval $(stat -s $file) # macos
    if [ $? -eq 0 ]; then
        echo $st_size
        return 0
    fi

    echo 0
    return -1
}

#
# Check if pd_funcions should be skipped
#
function skip_pd_functions {
    local install=$(cat /proc/cmdline | grep install=)
    if [ -n "${install}" ]; then
        return 1
    fi
    local sim=$(cat /proc/cmdline | grep simulator=)
    if [ -n "${sim}" ]; then
        return 1
    fi
    return 0
}

#
# Which TTY should calvados con use
#
function platform_enable_calvados_con
{
    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi
    ACTIVE_SERIAL='/dev/pts/0'
    declare -F platform_log &>/dev/null && platform_log "Calvados console on $ACTIVE_SERIAL"
    echo "Calvados console on $ACTIVE_SERIAL"
}

#
# Which TTY should calvados aux use
#
function platform_enable_calvados_aux
{
    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi
    ACTIVE_SERIAL='/dev/pts/1'
    declare -F platform_log &>/dev/null && platform_log "Calvados aux on $ACTIVE_SERIAL"
    echo "Calvados aux on $ACTIVE_SERIAL"
}

#
# Which TTY should XR con use
#
function platform_enable_xr_con
{
    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi
    ACTIVE_SERIAL_XR_CON="pts/0"
    declare -F platform_log &>/dev/null && platform_log "XR console on $ACTIVE_SERIAL_XR_CON"
    echo "XR console on $ACTIVE_SERIAL_XR_CON"
}

#
# Which TTY should XR aux use
#
function platform_enable_xr_aux
{
    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi
    ACTIVE_SERIAL_XR_AUX="pts/1"
    declare -F platform_log &>/dev/null && platform_log "XR aux on $ACTIVE_SERIAL_XR_AUX"
    echo "XR aux on $ACTIVE_SERIAL_XR_AUX"
}


#
# Should we allow the first serial port to have a tty login?
#
function platform_enable_host_login_on_first_serial
{
    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi
    ACTIVE_SERIAL=''
}

# Do we want to enable host access on extra ttys? Good for development but
# is a security risk to leave host access visible.
#
function platform_starts_serial
{
    local pd_card_inst

    # Allow starts-serial to start serial login
    # If no active serial set, and on hostos, start serial on ttyS0 and ttyS1

    if [ "$VMTYPE" == "hostos" ]; then
        if [ -f /etc/init.d/spirit_pd.sh ]; then
           source /etc/init.d/spirit_pd.sh
        fi
        pd_get_card_inst pd_card_inst > /dev/null
        if [ "${pd_card_inst}" == "TORTIN-RP" ] || 
            [ "${pd_card_inst}" == "TURINCR-RP" ] || 
            [ "${pd_card_inst}" == "BIFROSTT-RP" ] || 
            [ "${pd_card_inst}" == "PYKE-RP" ] || 
            [ "${pd_card_inst}" == "PEYTO-RP" ] ; then
            /* Tortin has only 1 UART for console, 2nd one is for GNSS */
            [ -z "$ACTIVE_SERIAL" ] && ACTIVE_SERIAL=/dev/ttyS[0]
        else 
            [ -z "$ACTIVE_SERIAL" ] && ACTIVE_SERIAL=/dev/ttyS[01]
        fi
    else
        [ "${BOARDTYPE}" == "LC" ] && ACTIVE_SERIAL=/dev/pts/[01]
    fi

    SPEED=`grep -o "console[^[:space:]]*" /proc/cmdline | cut -d ',' -f2`
}

#
# Check we have somewhere to write logs to. At early boot we might not have
# /var/log, so use /tmp until then
#
function platform_log_choose_log_file
{
    #
    # Where to log shell script output to. If /var/log is not available, use
    # /tmp which surely must be usable.
    #
    local PLATFORM_LOG=/var/log/platform.log

    #
    # If we are installing, append onto the host install logs as platform.log 
    # is not saved by xrnginstall in save_install_log (yet)
    #
    grep -q "root=/dev/ram" /proc/cmdline
    if [ $? -eq 0 ]; then
        PLATFORM_LOG=/var/log/host-install.log
        #
        # A tad obscure, but this is the FD that pxe_install uses for logging.
        # Only if we log to this will our output get into host-install.log
        #
        PLATFORM_LOG=/dev/fd/107
    fi

    PLATFORM_LOG_FILE=$PLATFORM_LOG
    if [ ! -f $PLATFORM_LOG_FILE ]; then
        touch $PLATFORM_LOG_FILE &>/dev/null
    fi

    if [ ! -w $PLATFORM_LOG_FILE ]; then
        local PLATFORM_TMP_LOG=/tmp/platform.early.log

        PLATFORM_LOG_FILE=$PLATFORM_TMP_LOG
    fi

    #
    # Sanity check it doesn't get too large
    #
    if [ -f $PLATFORM_LOG_FILE ]; then
        local FILESIZE=`filesize $PLATFORM_LOG_FILE`
        local MAX=1048576

        if [ $FILESIZE -ge $MAX ]; then
            #
            # Chop off the start of the file
            #
            sed -i '1,100d' $PLATFORM_LOG_FILE
        fi
    fi
}

#
# Utility function to log to our platform log file to help with
# debugging shell script flow.
#
function platform_log
{
    platform_log_choose_log_file

    local DATE=`date`
    echo "$DATE ($0): $*" >> $PLATFORM_LOG_FILE
}

#
# Utility function to log to our platform log file to help with
# debugging shell script flow.
#
function platform_log_error
{
    platform_log_console $*

    backtrace
}

#
# Some calvados scripts use log message but it is not defined. Get the output
# into our platform log if log_message is not defined.
#
function log_message
{
    platform_log $*
}

#
# Log to file and console
#
function platform_log_console 
{
    platform_log_choose_log_file

    local DATE=`date`
    echo "$DATE ($0): $*" | tee -a $PLATFORM_LOG_FILE

    return ${PIPESTATUS[0]}
}

#
# Keep this function aliased as a variable, so that if PLATFORM_LOG_EXEC is 
# not defined due to an error in including this file, the callers command 
# still executes
#
PLATFORM_LOG_EXEC=platform_log_exec
PLATFORM_LOG_EXEC_CONSOLE=platform_log_exec_console

#
# Log results to the log file only
#
function platform_log_exec
{
    platform_log_choose_log_file
    platform_log "exec: $*"
    platform_log "    : in cwd" `pwd`

    local PREFIX="`date -u`: -- "
    $* 2>&1 | sed "s/^/${PREFIX}/g" >>$PLATFORM_LOG_FILE 2>&1

    return ${PIPESTATUS[0]}
}

#
# Log results to the log file and the console
#
function platform_log_exec_console
{
    platform_log_choose_log_file
    platform_log "exec: $*"
    platform_log "    : in cwd" `pwd`

    local PREFIX="`date -u`: -- "
    $* 2>&1 | sed "s/^/${PREFIX}/g" | tee -a $PLATFORM_LOG_FILE

    return ${PIPESTATUS[0]}
}

#
# Print a shell backtrace
#
function backtrace () {
    local deptn=${#FUNCNAME[@]}

    for ((i=1; i<$deptn; i++)); do
        local func="${FUNCNAME[$i]}"
        local line="${BASH_LINENO[$((i-1))]}"
        local src="${BASH_SOURCE[$((i-1))]}"
        printf '%*s at: %s(), %s, line %s\n' $i '' $func $src $line # indent
    done
}

function platform_log_backtrace_ () {
    local depth=${#FUNCNAME[@]}

    for ((i=1; i<$depth; i++)); do
        local func="${FUNCNAME[$i]}"
        local line="${BASH_LINENO[$((i-1))]}"
        local src="${BASH_SOURCE[$((i-1))]}"
        printf '%*s at: %s(), %s, line %s\n' $i '' $func $src $line >> $PLATFORM_LOG_FILE
    done
}

function platform_log_backtrace () {
    platform_log_choose_log_file

    platform_log_backtrace_
}

# This will help the CAPI and GSP packets to get proper priority
function set_vlan_priority_map() {
    local dev=$1
    for i in {0..7}
    do
       vconfig set_egress_map $dev $i $i  > /dev/null 2>&1
       vconfig set_ingress_map $dev $i $i  > /dev/null 2>&1
    done
}

# Console Mux details
#
function platform_get_mux_tty_settings
{
    local CONSOLE=`cat /proc/cmdline | sed 's/^.*console=//' | cut -d" " -f 1`
    local TTY=`echo $CONSOLE | cut -d"," -f 1`
    local TTY_SPEED=`echo $CONSOLE | cut -d"," -f 2`

    if [ -n "$TTY" -a -n "$TTY_SPEED" ]; then
        MUX_TTY=/dev/$TTY
        MUX_TTY_SPEED=$TTY_SPEED
        MUX_TTY_TYPE=3
        MUX_TTY_FLOWCTRL=""
        MUX_TTY_SOCAT_OPTION="raw,echo=0,opost=1"
    fi
}

function platform_post_xr_launch
{
    local spp_rp_mac="4e:41:50:00:10:01"
    local spp_lc_mac="4e:41:50:00:00:01"

    if [ "$VMTYPE" == "hostos" ]; then
        if [ -e /sys/class/net/xr-eth0 ]; then
            ifconfig xr-eth0 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth1 ]; then
            ifconfig xr-eth1 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth2 ]; then
            ifconfig xr-eth2 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth3 ]; then
            ifconfig xr-eth3 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth4 ]; then
            ifconfig xr-eth4 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth5 ]; then
            ifconfig xr-eth5 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth6 ]; then
            ifconfig xr-eth6 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth7 ]; then
            ifconfig xr-eth7 mtu 9702
        fi
        if [ -e /sys/class/net/xr-eth8 ]; then
            ifconfig xr-eth8 mtu 9702
        fi
        if [ -e /sys/class/net/sysadmin-eth0 ]; then
            ifconfig sysadmin-eth0 mtu 9702
        fi
        if [ -e /sys/class/net/sysadmin-eth1 ]; then
            ifconfig sysadmin-eth1 mtu 9702
        fi
        if [ -e /sys/class/net/xr_local_br-nic ]; then
            ifconfig xr_local_br-nic mtu 9702
        fi
    fi

    if [ -e /sys/class/net/xr-eth-rp-spp ]; then
        ifconfig xr-eth-rp-spp mtu 9698
        bridge fdb add $spp_rp_mac dev xr-eth-rp-spp master temp
    fi

    if [ -e /sys/class/net/xr-eth-rp-tp ]; then
        bridge fdb add $spp_rp_mac dev xr-eth-rp-tp master temp
    fi

    if [ -e /sys/class/net/xr-eth-rp-sr ]; then
        bridge fdb add $spp_rp_mac dev xr-eth-rp-sr master temp
    fi

    if [ -e /sys/class/net/xr-eth-lc-spp ]; then
        ifconfig xr-eth-lc-spp mtu 9698
        bridge fdb add $spp_lc_mac dev xr-eth-lc-spp master temp
    fi

    if [ -e /sys/class/net/xr-eth-lc-olp ]; then
        bridge fdb add $spp_lc_mac dev xr-eth-lc-olp master temp
    fi

    if [ -e /sys/class/net/xr-eth-lc-bfd ]; then
        bridge fdb add $spp_lc_mac dev xr-eth-lc-bfd master temp
    fi
}

# App hosting Cgroup settings
function pd_tpa_cgroup_settings
{
    local pd_card_inst
        
    pd_get_card_inst pd_card_inst

    if [[ "${pd_card_inst}" == "ZERMATT-RP" ]] ; then
        APP_CGROUP_MEM_NUMA_NODES=0
        APP_CGROUP_MAX_CPU_ID=23
        APP_CGROUP_CPU_SHARES=256
        APP_CGROUP_MEM_LIMIT_IN_BYTES=1G
    elif [ "${pd_card_inst}" == "TURIN-RP" ] || [ "${pd_card_inst}" == "WINTERFELL-RP" ] || [ "${pd_card_inst}" == "OLDCASTLE-RP" ] || [ "${pd_card_inst}" == "TORTIN-RP" ]  || [ "${pd_card_inst}" == "PYKE-RP" ] || [ "${pd_card_inst}" == "PEYTO-RP" ] || [ "${pd_card_inst}" == "BIFROSTT-RP" ] || [ "${pd_card_inst}" == "TURINCR-RP" ] ; then
        APP_CGROUP_MEM_NUMA_NODES=0
        APP_CGROUP_MAX_CPU_ID=7
        APP_CGROUP_CPU_SHARES=256
        APP_CGROUP_MEM_LIMIT_IN_BYTES=1G
    else
        APP_CGROUP_MEM_NUMA_NODES=0
        APP_CGROUP_MAX_CPU_ID=5
        APP_CGROUP_CPU_SHARES=512
        APP_CGROUP_MEM_LIMIT_IN_BYTES=1G
    fi
    #
    # Check how many CPUs the router has. If we are trying to assign a
    # non existent CPU ID to cgroups, adjust now to avoid an error later.
    #
    ROUTER_CPUS=`nproc --all`
    ROUTER_MAX_CPU_ID=$(($ROUTER_CPUS-1))
    if [[ "$ROUTER_MAX_CPU_ID" -lt "$APP_CGROUP_MAX_CPU_ID" ]]; then
        APP_CGROUP_MAX_CPU_ID="$ROUTER_MAX_CPU_ID"
    fi
    APP_CGROUP_CPUSET_CPUS="1-$APP_CGROUP_MAX_CPU_ID"
}

#
# For Tortin We have two variants 16G and 32G ,default sdr-xml is
# aligned to 32G so check and override the xml config if running
# on 16G board.
#
function platform_calvados_sdr_xml_check
{

    #
    # Find the calvados xml (from the host)
    #
    if [ -f $CALV_ACTIVE_PART_FILE ]; then
        #extract calvados active LV index
        calvados_lv="$(cat $CALV_ACTIVE_PART_FILE | awk -F "/" '{print $4}')"
        ROOTFS="/lxc_rootfs/panini_vol_grp-$calvados_lv"
    else
        ROOTFS="/lxc_rootfs/panini_vol_grp-calvados_lv0"
    fi
    platform_log "Calvados root-fs LV is $calvados_lv and mounted on $ROOTFS"

    DEFAULT_SDR_XML="default_sdr.xml"
    TORTIN_16G_SDR_XML="tortin_16g_default_sdr.xml"

    # Read the symlink
    OPT_DEFAULT_SDR_XML="/opt/cisco/calvados/confd/var/confd/cdb/$DEFAULT_SDR_XML"
    OPT_DEFAULT_SDR_XML="${ROOTFS}${OPT_DEFAULT_SDR_XML}"
    OPT_DEFAULT_SDR_XML="$(readlink $OPT_DEFAULT_SDR_XML)"
    OPT_DEFAULT_SDR_XML="${ROOTFS}${OPT_DEFAULT_SDR_XML}"

    
    OPT_TORTIN_16G_SDR_XML="/opt/cisco/calvados/etc/$TORTIN_16G_SDR_XML"
    OPT_TORTIN_16G_SDR_XML="${ROOTFS}${OPT_TORTIN_16G_SDR_XML}"
    OPT_TORTIN_16G_SDR_XML="$(readlink $OPT_TORTIN_16G_SDR_XML)"
    OPT_TORTIN_16G_SDR_XML="${ROOTFS}${OPT_TORTIN_16G_SDR_XML}"

    local plat_type=$(iofpga_reg_read 0 4)
    local num=$( printf "0x%x" $plat_type )
    local result=$(($(( num >> 23 & 0x1 )) << 4 | $(( num >> 28 & 0xF ))))
    if [ $result -eq 23 ]
    then
        echo "TORTIN 16G board"
        cp $OPT_TORTIN_16G_SDR_XML $OPT_DEFAULT_SDR_XML
        sed -i -e "s;VIRT_RP_MEM=4194304;VIRT_RP_MEM=1048576;" ${ROOTFS}/etc/init.d/calvados_bootstrap.cfg
        sync
    fi
}

