#!/bin/bash
#
#      -*- OpenSAF  -*-
#
# (C) Copyright 2008 The OpenSAF Foundation
# Copyright Ericsson AB 2017 - All Rights Reserved.
#
# 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. This file and program are licensed
# under the GNU Lesser General Public License Version 2.1, February 1999.
# The complete license can be accessed from the following location:
# http://opensource.org/licenses/lgpl-license.php
# See the Copying file included with the OpenSAF distribution for full
# licensing terms.
#
# Author(s): Emerson Network Power
#

. /etc/opensaf/osafdir.conf
. $pkgsysconfdir/nid.conf

MANAGE_TIPC=${OPENSAF_MANAGE_TIPC:-"yes"}
TIPC_MODULE=$(modinfo -n tipc 2> /dev/null) || TIPC_MODULE="/lib/modules/$(uname -r)/kernel/net/tipc/tipc.ko"
CHASSIS_ID_FILE=$pkgsysconfdir/chassis_id
SLOT_ID_FILE=$pkgsysconfdir/slot_id
SUBSLOT_ID_FILE=$pkgsysconfdir/subslot_id

# Configure TIPC in network mode. If the variable TIPC_MODULE points to a file,
# 'insmod' is used else 'modprobe'. 'tipc-config' needs to be in the path.

# Support for using subslot ID as part the TIPC network address.
# When TIPC_USE_SUBSLOT_ID is set to "NO" (the default), the subslot ID is 
# not included in the address and slot ID is not shifted thus producing
# TIPC addresses like 1.1.1, 1.1.2, 1.1.3 etc.
# When TIPC_USE_SUBSLOT_ID is set to "YES", the subslot ID becomes the last 4 bits
# of the address and the slot ID is shifted up 4 bits. 
USE_SUBSLOT_ID=${TIPC_USE_SUBSLOT_ID:-"NO"}

# Currently supported max nodes for Opensaf
TIPC_MAX_NODES=4095

# Support for enable disable duplicate node verification.
# When TIPC_DUPLICATE_NODE_DETECT is set to "YES" (the default is "YES"),
# at Opensaf start-up , it is per-verified whether any duplicate node
# exist in the cluster, set TIPC_DUPLICATE_NODE_DETECT set to NO to disable
# per-verification of duplicate node.
#
# Note: In OS like Montavista where TIPC is built in kernel module,
#       once TIPC has joined a network with a network id & address
#       it cannot change node address once assigned, until node reboots,
#       so duplicate node verification is not possible and enable disable
#       duplicate node verification has NO effect.
DUPLICATE_NODE_DETECT=${TIPC_DUPLICATE_NODE_DETECT:-"NO"}

# constants
SHIFT4=4

if [ "$#" -lt "1" ] || [ "$#" -gt "4" ]
   then
     echo " If you want to use TIPC in Non Networking mode"
     echo " Usage: $0 start &"
     echo " If you want to use TIPC in Networking mode"
     echo " Usage: $0 start ifname[,ifname] <netid[1-9999]>"
     echo " Example: interface eth0 and netid 7777"
     echo " $0 start eth0 7777 &"
     echo " Example: interface eth0 and eth1 and netid 9999"
     echo " $0 start eth0,eth1 9999"
     exit 1
fi

tipc=$(which tipc 2> /dev/null)
tipc_config=$(which tipc-config 2> /dev/null)

if ! [ -x "${tipc}" ] && ! [ -x "${tipc_config}" ]; then
    echo "error: neither tipc nor tipc-config is available"
    exit 1
fi

# Prefer using `tipc` to the obsolete `tipc-config`
if [ -x "${tipc}" ]; then
    tipc_config="${pkglibdir}"/tipc-config
fi

if [ "$MANAGE_TIPC" != "yes" ] && ! [ -s "$pkglocalstatedir/node_id" ]; then
	addr=$(${tipc_config} -addr | cut -d'<' -f2 | cut -d'>' -f1)
    addr=$(echo "$addr" | cut -d. -f3)
    CHASSIS_ID=2
    SLOT_ID=$((addr & 255))
    SUBSLOT_ID=$(((addr >> 8) ^ 15))
    printf "00%02x%02x%02x\\n" $CHASSIS_ID $((SLOT_ID & 255)) $((SUBSLOT_ID ^ ((SLOT_ID >> 8) & 15) )) > "$pkglocalstatedir/node_id"
fi

if [ "$MANAGE_TIPC" != "yes" ]; then
    exit 0
fi

ETH_NAME=$2
TIPC_NETID=$3

# Get the Chassis Id and Slot Id from /etc/opensaf/chassis_id and /etc/opensaf/slot_id
if ! test -f "$CHASSIS_ID_FILE"; then
   echo "$CHASSIS_ID_FILE doesnt exists, exiting ...." 
   exit 1
fi
CHASSIS_ID=`cat "$CHASSIS_ID_FILE"`
if [ "$CHASSIS_ID" -gt "16" ] || [ "$CHASSIS_ID" -lt "1" ]  
    then 
      echo "CHASSIS ID Should be in the range of 1 to 16"
      echo "Quitting......"
      exit 1
fi
if ! test -f "$SLOT_ID_FILE"; then
   echo "$SLOT_ID_FILE doesnt exists, exiting ...." 
   exit 1
fi
SLOT_ID=`cat "$SLOT_ID_FILE"`
if [ "$SLOT_ID" -gt "4095" ] || [ "$SLOT_ID" -lt "1" ]
    then 
      echo "SLOT ID Should be in the range of 1 to 4095"
      echo "Quitting......"
      exit 1
fi
if ! test -f $SUBSLOT_ID_FILE; then
    echo "$SLOT_ID_FILE doesnt exist, exiting ...." 
    exit 1
fi
SUBSLOT_ID=`cat $SUBSLOT_ID_FILE`
if [ "$SUBSLOT_ID" -gt "15" ] || [ "$SUBSLOT_ID" -lt "0" ]; then
    echo "SUBSLOT ID Should be in the range of 0 to 15"
    echo "Quitting......"
    exit 1
fi

if [ $# -gt 1 ] ; then 
    if [ "$TIPC_NETID" -gt "9999" ] || [ "$TIPC_NETID" -lt "1" ]  
      then 
        echo "CORE ID Should be in the range of 1 to 9999"
        echo "Quitting......"
        exit 1
    fi
fi    

printf "00%02x%02x%02x\\n" $CHASSIS_ID $((SLOT_ID & 255)) $((SUBSLOT_ID ^ ((SLOT_ID >> 8) & 15) )) > "$pkglocalstatedir/node_id"
chmod 744 $pkglocalstatedir/node_id
if [ "$USE_SUBSLOT_ID" = "YES" ]; then
    TIPC_NODEID=$(($SLOT_ID << $SHIFT4))
    TIPC_NODEID=$(($TIPC_NODEID + $SUBSLOT_ID))
else    
    TIPC_NODEID=$SLOT_ID    
fi

function tipc_duplicate_node_detect ()
{
    logger -t opensaf -s "Checking for duplicate Node: $TIPC_NODEID in Cluster..."
    if ! test -f "$TIPC_MODULE"  ; then
      modprobe tipc
      RM_TIPC_MODULE="modprobe -r tipc"
    else
      insmod "$TIPC_MODULE"
      RM_TIPC_MODULE="rmmod $TIPC_MODULE"
    fi

    ret_val=$?
    if [ $ret_val -ne 0 ] ; then
        logger -p user.err " TIPC Module could not be loaded "
        exit 1
    fi

    # max_nodes is not supported in TIPC 2.0
    if ${tipc_config} -max_nodes 2> /dev/null; then
        ${tipc_config} -max_nodes=$TIPC_MAX_NODES
        ret_val=$?
        if [ $ret_val -ne 0 ] ; then
            $RM_TIPC_MODULE
            exit 1
        fi
    fi
 
    if [ $# -eq 1 ] ; then
            ################ Address config and check #########
            ${tipc_config} -a=1.1.$(($TIPC_MAX_NODES - $TIPC_NODEID))
            ret_z1=$?
            if [ $ret_z1 -ne 0 ] ; then
                echo "Unable to Configure TIPC address, Please try again, exiting" 
                $RM_TIPC_MODULE
                exit 1
            fi
    else
        ${tipc_config} -netid=$TIPC_NETID -a=1.1.$(($TIPC_MAX_NODES - $TIPC_NODEID))
        ret_z2=$?
        if [ $ret_z2 -ne 0 ] ; then
            echo "Unable to Configure TIPC address, Please try again, exiting" 
            $RM_TIPC_MODULE
            exit 1
        fi
        ${tipc_config} -be=$(echo $ETH_NAME | sed 's/^/eth:/;s/,/,eth:/g')
        ret_z3=$?
        if [ $ret_z3 -ne 0 ] ; then
            echo "Unable to Configure TIPC bearer interface, Please try again, exiting" 
            $RM_TIPC_MODULE
            exit 1
        else
          ${tipc_config} -nt | grep cluster | grep "1.1.$TIPC_NODEID:" > /dev/null
          ret_z4=$?
          if [ $ret_z4 -eq 0 ] ; then
            logger -t opensaf -s "Unable to Configure TIPC Node, Duplicate Node $TIPC_NODEID exist in cluster, exiting..."
            $RM_TIPC_MODULE
            exit 1
          fi
        fi
 
        tipc_links=` ${tipc_config} -l | grep 1.1.$(($TIPC_MAX_NODES - $TIPC_NODEID)) | sed 's/: up/\/50 /g' `
        for link in $tipc_links; do `${tipc_config} -lt=$link ` ; done
        ${tipc_config} -bd=$(echo $ETH_NAME | sed 's/^/eth:/;s/,/,eth:/g')
    fi

    $RM_TIPC_MODULE
}

function tipc_configure ()
{
    echo "Inserting TIPC mdoule..."

    # Prefer using modprobe to insmod as modprobe takes care of
    # loading all dependencies if any. If any dependent module
    # has not yet loaded, insmod will get failed.
    RM_TIPC_MODULE=""
    if modprobe tipc ; then
      RM_TIPC_MODULE="modprobe -r tipc"
    elif insmod "$TIPC_MODULE" ; then
      RM_TIPC_MODULE="rmmod $TIPC_MODULE"
    elif lsmod | grep -q tipc ; then
      # tipc kernel has been loaded. This may happen when we run opensaf on
      # container which does not have the right to load/unload tipc module
      echo "TIPC module is already loaded"
    else
      logger -p user.err " TIPC Module could not be loaded "
      exit 1
    fi

    # max_nodes is not supported in TIPC 2.0
    if ${tipc_config} -max_nodes 2> /dev/null; then
        ${tipc_config} -max_nodes=$TIPC_MAX_NODES 
        ret_val=$?
        if [ $ret_val -ne 0 ] ; then 
            echo "Unable to set the Max_nodes to $TIPC_MAX_NODES, exiting ....."
            $RM_TIPC_MODULE
            exit 1
        fi
    fi

    if [ $# -eq 1 ] ; then
            echo "Configuring TIPC in Non-Networking Mode..."
            ################ Address config and check #########
            ${tipc_config} -a=1.1.$TIPC_NODEID 
            ret_z1=$?
            if [ $ret_z1 -ne 0 ] ; then 
                echo "Unable to Configure TIPC address, Please try again, exiting" 
                echo "Removing TIPC module ...."
                $RM_TIPC_MODULE
                exit 1
            fi
    else
        echo "Configuring TIPC in Networking Mode..."
        ################ Address config and check #########
        ${tipc_config} -netid=$TIPC_NETID -a=1.1.$TIPC_NODEID  
        ret_z2=$?
        if [ $ret_z2 -ne 0 ] ; then 
            echo "Unable to Configure TIPC address, Please try again, exiting" 
            echo "Removing TIPC module ...."
            $RM_TIPC_MODULE
            exit 1
        fi
        ################ Interface config and check #########
        ${tipc_config} -be=$(echo $ETH_NAME | sed 's/^/eth:/;s/,/,eth:/g')
        ret_z3=$?
        if [ $ret_z3 -ne 0 ] ; then 
            echo "Unable to Configure TIPC bearer interface, Please try again, exiting" 
            echo "Removing TIPC module ...."
            $RM_TIPC_MODULE
            exit 1
        fi
    fi   

    echo " TIPC Module is Present and Configured Success in network mode " 
}

# Consider that TIPC could be statically linked
if ! grep TIPC /proc/net/protocols >& /dev/null; then
    if [ "$DUPLICATE_NODE_DETECT" = "YES" ]; then
        tipc_duplicate_node_detect
    fi
    tipc_configure
else
    # TIPC is already present, is it configured properly?
    configured_tipc_addr=$(${tipc_config} -addr | tr -s '<>' % | cut -d% -f2)
    opensaf_tipc_addr=1.1."$TIPC_NODEID"
    if [ "$configured_tipc_addr" != "$opensaf_tipc_addr" ]; then
        if [ "$configured_tipc_addr" != "0.0.0" ]; then
            logger -t opensaf -s "TIPC node address not configured to OpenSAF requirements, Exiting..."
            exit 1
        else
            logger -t opensaf -s "TIPC node address not yet configured , Configuring..."
            tipc_configure
        fi
    else
        configured_net_id=$(${tipc_config} -netid | cut -d: -f2)
        opensaf_net_id="$TIPC_NETID"
        if [ "$configured_net_id" -ne "$opensaf_net_id" ]; then
            logger -t opensaf -s "TIPC network ID not configured to OpenSAF requirements, exiting..."
            exit 1
        fi
        configured_bearers=$(${tipc_config} -b | grep -v Bearer | cut -d: -f2 | sort)
        opensaf_bearers=$(echo "$ETH_NAME" | tr "," "\n" | sort)
        if [ "$configured_bearers" != "$opensaf_bearers" ]; then
            logger -t opensaf -s "TIPC bearer not configured to OpenSAF requirements, exiting..."
            exit 1
        fi
    fi
fi

