#!/sbin/sh
#
# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#ident	"@(#)nhcgtp	1.23	06/01/23 SMI"
#
# this script configure CGTP for cluster and non-cluster mode
# note: this script must not fail if configuration file are
#       not present in non-cluster mode

NH_INCLUDE=/etc/opt/SUNWcgha/init.d/nhinclude.sh
. $NH_INCLUDE

PROG=`basename $0`

NHCONFDIR=/etc/opt/SUNWcgha
USER_FILE=/etc/opt/SUNWcgha/nhfs.conf

AWK=/usr/bin/awk
IFCONFIG=/usr/sbin/ifconfig
ROUTE=/usr/sbin/route
GREP=/usr/bin/grep
PGREP=/usr/bin/pgrep
CAT=/usr/bin/cat
UNAME=/usr/bin/uname
NHGETCONF=/opt/SUNWcgha/sbin/nhgetconf
NHNETCFG=/opt/SUNWcgha/sbin/nhnetcfg

# the code of the function wait_for_dhcp is also present in nhcgtps
# (CGTP for diskless standalone). Do not forget to make change in both
# scripts

wait_for_dhcp () {

    # Get name of the network interfaces
    nic0=`$NHGETCONF -u file://$USER_FILE -s Node.Nic0`	\
    || error "Property \"Node.Nic0\" not found in $USER_FILE"

    nic1=`$NHGETCONF -u file://$USER_FILE -s Node.Nic1`	\
    || error "Property \"Node.Nic1\" not found in $USER_FILE"

    $NH_ECHO "Waiting for DHCP interfaces to be configured\c"

    # wait until both interfaces has been configured
    nic0_done=0
    nic1_done=0
    loop=20
    end=0
    while [ ${end} -eq 0 ]
    do
	$NH_ECHO ".\c"

	# check if the interfaces have been configured
	if [ ${nic0_done} -eq 0 ]
	then
	    result=`$IFCONFIG ${nic0} | $GREP -c 0.0.0.0`
	    if [ ${result} -eq 0 ]
	    then
		nic0_done=1
		$NH_ECHO "\n${nic0} configured."
	        if [ ${nic1_done} -eq 0 ]; then
		    $NH_ECHO "Waiting for ${nic1} to be configured.\c"
		fi
	    fi
	fi
	if [ ${nic1_done} -eq 0 ]
	then
	    result=`$IFCONFIG ${nic1} | $GREP -c 0.0.0.0`
	    if [ ${result} -eq 0 ]
	    then
		nic1_done=1
		$NH_ECHO "\n${nic1} configured."
	        if [ ${nic0_done} -eq 0 ]; then
		    $NH_ECHO "Waiting for ${nic0} to be configured.\c"
		fi
	    fi
	fi

	# if still not done, make some actions
	if [ ${nic0_done} -eq 0 ] || [ ${nic1_done} -eq 0 ]
	then
	    # check if dhcpagent is still there
	    result=`$PGREP -x dhcpagent`
	    if [ -z "${result}" ]
	    then
		    error "dhcpagent not present"
		    exit $NH_EXIT_ERROR
	    fi

	    # do not loop forever
	    loop=`expr ${loop} - 1`
	    if [ ${loop} -le 0 ]
	    then
		$NH_ECHO "timeout: interface not initialized by DHCP"
		end=1
	    else
		# wait before looping
		sleep 1
            fi
	 else
	    end=1
	 fi
    done

    # by default, dhcpinfo will use nic0 as the primary interface
    # whatever the boot interface.
    # if nic0 is not configured by DHCP at startup, the DHCP info will not be
    # available on nic0 but on nic1
    # -> use nic1 for all dhcpinfo requests.

    dhcp_itf=${nic0}
    if [ ${nic0_done} -eq 0 ]; then
	# nic1 is the DHCP interface
	dhcp_itf=${nic1}
	local_nic0_addr=`/sbin/dhcpinfo -i ${dhcp_itf} NhNic0Addr 2> /dev/null`
        $NH_ECHO "Forcing ${nic0} configuration"
	$IFCONFIG ${nic0} ${local_nic0_addr} netmask + broadcast + up
    fi
    if [ ${nic1_done} -eq 0 ]; then
	local_nic1_addr=`/sbin/dhcpinfo -i ${dhcp_itf} NhNic1Addr 2> /dev/null`
        $NH_ECHO "Forcing ${nic1} configuration"
	$IFCONFIG ${nic1} ${local_nic1_addr} netmask + broadcast + up
    fi

    # if the boot interface is nic1, we have to set it as primary dhcp
    # interface, to let dhcpinfo (without -i option) work correctly
    if [ "$nic1" = "$dhcp_itf" ]; then
	$NH_ECHO "Setting $nic1 as dhcp primary interface .. \c"
	$IFCONFIG $nic1 dhcp primary ping
	case $? in
	   0) $NH_ECHO "ok" ;;
	   *) $NH_ECHO "failed" ;;
	esac
    fi
}

diskless_conf () 
{ 

# For diskless nodes, get information from DHCP.
# BootSrvA symbol contains cgtp master dynamic address
# NhCgtpAddr symbol contains : local cgtp addr
# Subnet symbol contains cgtp netmask (assumption is made
# that cgtp netmask is identifical to primary nics one).

    # wait for the interface to be configured
    wait_for_dhcp

    # set the hostname from /etc/nodename
    HOSTNAME=`$CAT /etc/nodename`
    $UNAME -S $HOSTNAME

    #
    # retrieve additional infos
    #

    local_cgtp_addr=`/sbin/dhcpinfo -i ${dhcp_itf} NhCgtpAddr 2> /dev/null`
    cgtp_netmask=`/sbin/dhcpinfo -i ${dhcp_itf} Subnet 2> /dev/null`
    master_cgtp=`/sbin/dhcpinfo -i ${dhcp_itf} BootSrvA 2> /dev/null`
    router=`/sbin/dhcpinfo -i ${dhcp_itf} Router 2> /dev/null`

    master_nic0=`$NHNETCFG nic0 masterdyn`				\
	|| error "Cannot retrieve master's dynamic NIC0 address"
    master_nic0=`echo ${master_nic0} | $AWK '{print$2}'`

    master_nic1=`$NHNETCFG nic1 masterdyn`				\
	|| error "Can't retrieve master's dynamic NIC1 address"
    master_nic1=`echo ${master_nic1} | $AWK '{print$2}'`

    # add a host route to the IP master address, cannot use setsrc
    # as soon as cgtp0 will be plumbed, we need a proper route (not
    # the default one)

    if [ "${router}" = "${master_nic0}" ]
    then
	#we used nic0 to boot
	$ROUTE add ${master_cgtp} ${master_nic0} -multirt
	cgtpintf_plumb ${local_cgtp_addr} 
	# now the CGTP address is configured, use setsrc
	cgtp_route_add ${master_nic1} 
	#this route is already partialy configured
	cgtp_route_update ${master_nic0}
    else
        #we used nic1 to boot
        $ROUTE add ${master_cgtp} ${master_nic1} -multirt
        cgtpintf_plumb ${local_cgtp_addr} 
        # now the CGTP address is configured, use setsrc
        cgtp_route_add ${master_nic0} 
        #this route is already partialy configured
        cgtp_route_update ${master_nic1}
    
    fi

    # disconnect TCP connections to the master
    # so that NFS re-opens it using new CGTP routing
    /opt/SUNWcgha/sbin/nhtcpdisc ${master_cgtp}

}

cgtp_route_update () 
{ 
    $ROUTE change ${master_cgtp} $1 -multirt -setsrc ${local_cgtp_addr}
}

cgtp_route_add ()
{
    $ROUTE add ${master_cgtp} $1 -multirt -setsrc ${local_cgtp_addr}
}

cgtpintf_plumb () 
{ 
    $IFCONFIG ${cgtp_ifname} plumb $1 netmask ${cgtp_netmask} broadcast + up
}

error ()
{
	$NH_ECHO "$PROG: ERROR: $1"
	$NH_ECHO "$PROG: Aborting. Cannot configure CGTP routes"
	exit $NH_EXIT_ERROR
}

#------------------------------------------------------------------------------
#
# configure CGTP route to master
#
#------------------------------------------------------------------------------

configure_master_route() {

    # Check that CGTP interface exists
    $IFCONFIG ${cgtp_ifname} > /dev/null 2>&1 \
	|| error "Interface ${cgtp_ifname} not plumbed"

    # Get local cgtp address
    local_cgtp_addr=`$NHNETCFG cgtp local`				\
	|| error "Cannot retrieve local CGTP address"
    local_cgtp_addr=`echo ${local_cgtp_addr} | $AWK '{print$2}'`

    # Get CGTP network mask
    cgtp_netmask=`$NHNETCFG cgtp netmask`				\
	|| error "Cannot retrieve local CGTP address's netmask"
    cgtp_netmask=`echo ${cgtp_netmask} | $AWK '{print$2}'`

    # Get master dynamic cgtp address
    master_cgtp=`$NHNETCFG cgtp masterdyn`				\
	|| error "Cannot retrieve master's dynamic CGTP address"
    master_cgtp=`echo ${master_cgtp} | $AWK '{print$2}'`
	
    master_nic0=`$NHNETCFG nic0 masterdyn`				\
	|| error "Cannot retrieve master's dynamic NIC0 address"
    master_nic0=`echo ${master_nic0} | $AWK '{print$2}'`
	
    master_nic1=`$NHNETCFG nic1 masterdyn`				\
	|| error "Can't retrieve master's dynamic NIC1 address"
    master_nic1=`echo ${master_nic1} | $AWK '{print$2}'`
	
    cgtp_route_add ${master_nic0}
    cgtp_route_add ${master_nic1}
}

#------------------------------------------------------------------------------
#
# configure CGTP depending on the node type
#
#------------------------------------------------------------------------------

configure_cgtp() {

    case "${Node_type}" in

    'DISKLESS')
	diskless_conf
	;;

    'DATALESS' | 'DISKFULL')
	configure_master_route
	;;

    *)
	$NH_ECHO "Wrong value for property \"Node.type\", should be \"Dataless\", \"Diskless\" or \"Diskfull\""
	exit $NH_EXIT_ERROR
	;;
    esac


}

#------------------------------------------------------------------------------
#
# configure CGTP route to other nodes
#
#------------------------------------------------------------------------------

configure_node_route() {

    nodelist=`$AWK '$1 !~ /^(#)/ && $1 != "VERSION" { print $1; }' /etc/opt/SUNWcgha/cluster_nodes_table`

    # Get local cgtp address
    local_cgtp_addr=`$NHNETCFG cgtp local`				\
	|| error "Cannot retrieve local CGTP address"
    local_cgtp_addr=`echo ${local_cgtp_addr} | $AWK '{print$2}'`

    localid=`$NHGETCONF -u file://$USER_FILE -s Node.NodeId`	\
	|| error "Property \"Node.NodeId\" not found in $USER_FILE"

    # for each node, create the route
    for nodeid in $nodelist; do

	if [ $nodeid != $localid ]; then

	    remote_nic0_addr=`$NHNETCFG nic0 $nodeid` \
		    || error "Can't retrieve NIC0 address for node $nodeid"
	    remote_nic0_addr=`echo ${remote_nic0_addr} | $AWK '{print $2 }'`
		
	    remote_nic1_addr=`$NHNETCFG nic1 $nodeid` \
		    || error "Can't retrieve NIC1 address for node $nodeid"
	    remote_nic1_addr=`echo ${remote_nic1_addr} | $AWK '{print $2 }'`
		
	    remote_cgtp_addr=`$NHNETCFG cgtp $nodeid` \
		    || error "Can't retrieve CGTP address for node $nodeid"
	    remote_cgtp_addr=`echo ${remote_cgtp_addr} | $AWK '{print $2 }'`
		
	    $ROUTE add ${remote_cgtp_addr} ${remote_nic0_addr} \
		-multirt -setsrc ${local_cgtp_addr}
	    $ROUTE add ${remote_cgtp_addr} ${remote_nic1_addr} \
		-multirt -setsrc ${local_cgtp_addr}

	fi
    done
}

#------------------------------------------------------------------------------
#
# configure CGTP route when starting in non-cluster mode
#
#------------------------------------------------------------------------------

configure_cgtp_route () {

    case "${Node_type}" in

    'DISKLESS')
	# nothing to do
	break
	;;

    'DATALESS')
	configure_master_route
	;;

    'DISKFULL')

	# configure route to master node and other nodes of the cluster

	configure_master_route

	# retrieve the node list from cluster_nodes_table
	# if it already exists
	if [ -r /etc/opt/SUNWcgha/cluster_nodes_table ]; then
	    configure_node_route
	fi
	;;

    *)
	$NH_ECHO "Wrong value for property \"Node.type\", should be \"Dataless\", \"Diskless\" or \"Diskfull\""
	exit $NH_EXIT_ERROR
	;;

    esac
}

#------------------------------------------------------------------------------
#
# MAIN
#
#------------------------------------------------------------------------------


# Tune TCP parameters to decrease NFS client downtime.
/usr/sbin/ndd -set /dev/tcp tcp_rexmit_interval_initial 100
/usr/sbin/ndd -set /dev/tcp tcp_rexmit_interval_min 400
/usr/sbin/ndd -set /dev/tcp tcp_rexmit_interval_max 400

if [ -r $USER_FILE ]; then

    # no need to configure CGTP interfaces or create a CGTP IP address
    # if CGTP is not used
    if [ "`$NHGETCONF -u file://$USER_FILE -s Node.UseCGTP | tr '[:lower:]' '[:upper:]'`" != "TRUE" ]
    then
	exit $NH_EXIT_OK
    fi

    # Get information about type of node
    Node_type=`$NHGETCONF -u file://$USER_FILE -s Node.Type`	\
	|| error "Property \"Node.type\" not found in $USER_FILE"
	
    Node_type=`$NHGETCONF -u file://$USER_FILE -s Node.Type | tr '[:lower:]' '[:upper:]'`

    # Get CGTP interface name
    cgtp_ifname=`$NHGETCONF -u file://$USER_FILE -s Node.NICCGTP` \
	|| error "Property \"Node.NICCGTP\" not found in $USER_FILE"

fi

#
# if NHAS is started, configure the CGTP interface
# otherwise add the CGTP IP address on NIC0 to allow:
# - SVM to get access to the metadevice on the master-eligible nodes
# - mount of remote file system to be correctly done on dataless
#   (to not prevent the boot to go till its end)
#

if nh_non_cluster_mode; then

    if [ -r $USER_FILE ]; then
	$NH_ECHO "=> Configuring CGTP for non-cluster mode"
	configure_cgtp_route
    else
	$NH_ECHO "=> Cannot configure CGTP for non-cluster mode: $USER_FILE not yet created"
    fi

else

    configure_cgtp
    
fi

exit $NH_EXIT_OK
