#!/bin/sh

# Test ethernet operation.
#
# This is a basic test, it will excersize the links
# but provide little or no fault isolation.  The test
# will abort on the first error detected.
#
# syntax: enettest [ nloops ]
#
# Test method
#   The test consists of two subtests, a ping subtest
#   and an rcp subtest.
#
#   The ping portion consists of several Ping commands to
#   the other CP through both the internal and external
#   ethernet connections.  The ping commands are run in
#   both normal (slow) and flood (fast) mode.  Any errors
#   detected in the form of lost or corrupted packets
#   will cause the test to fail and abort.
#
#   The rcp portion copies aproximatly 7 MB of data
#   back and forth across each ethernet link using the
#   rcp/rsh protocol.  The data is then compared with
#   the original data using diff.  Again any error causes
#   the test to abort.
#
# Setup
#   - The switch must be properly configured with 3 IP addresses
#     one for each switch and one for the chassis.  If all 3 addresses
#     are not valid the test will fail.
#
#   - 2 CP05's are required.  The test will not pass on a single CP
#     nor on CP04's.
#
#   - Each external ethernet connection must be attached to either a
#     hub or a switch.  In other words both CP's must be on the
#     network.  Alternativly a crossover ethernet cable could be
#     used to connect the CP's, but in this case it will be required
#     to run the test from the serial console.
#
#   - The test MUST be run on the master CP.  Currently no check is
#     made to verify this but if it is not the case the test will fail.
#
# WARNING:
#   The rcp and flood mode ping portions of this test can
#   cause very heavy network traffic.  Particularly if anything
#   goes wrong this could disrupt the entire sub-net or possibly
#   even the entire network.  (ever here of tribal-flood ?)
#
#   It is suggested that upstream link on the hub be dis-connected
#   during this test to avoid problems.
#

#
# Configuration stuff
#
rcpuser="root"	# user able to run rcp

#
# rcp test configuration
#
testdir="etest_data"	# source data directory for rcp tests
rcvdir="etest_rcv"	# result data directory for rcp tests
max_loops=40		# number of test loops

if [ "$1" != "" ] ; then
  max_loops=$1
fi

#
# Ping test configuration
#
slow_ping_count=1	# Number of ping frames at 1 frame/sec
flood_ping_count=400	# Number of ping frames at 100 frames/sec
# Ping data frame sizes
frame_sizes="14 28 56 128 256 520 1024 1510"

#
# Subroutines
#

# Fetch active slot number
get_active_slot ()
{
_tmp=`getcpslot | /usr/bin/cut -d" " -f 3`
expr $_tmp + 0
}


# Get int IP address of current CP (must be active)
get_my_int_ip ()
{
# look in current ifconfig
_tmp=`/sbin/ifconfig eth1 | /bin/grep "inet addr"`
if [ "0" != "$?" ] ; then
   /bin/echo "Error reading interface configuration for internal ethernet" >&2
   return 1
fi
_addr=`/bin/echo $_tmp | /usr/bin/cut -d":" -f2 | /usr/bin/cut -d" " -f1`
if [ "0" != "$?" ] ; then
   /bin/echo "Ethernet address $_tmp does not appear to be valid" >&2
   return 1
fi
/bin/echo $_addr
return 0
}

# Get int IP address of other CP
get_other_int_ip()
{
# First check for valid hosts file
_lines=`/bin/grep internaleth /etc/hosts | /usr/bin/wc -l`
if [ "2" -ne "$_lines" ] ; then
   /bin/echo "Invalid /etc/hosts file, can not find internal ethernet entries"
   return 1
fi
# Looks good so far, now make sure we are one of them.
_myip=`get_my_int_ip`
/bin/grep internaleth /etc/hosts | /bin/grep -q $_myip
if [ "0" != "$?" ] ; then
   /bin/echo "Invalid /etc/hosts -- missing my int ip"
   return 1
fi
# Great !! now find the other one
_addr=`/bin/grep internaleth /etc/hosts | /bin/grep -v $_myip`
if [ "0" != "$?" ] ; then
   /bin/echo "Invalid /etc/hosts -- missing other int ip"
   return 1
fi
echo $_addr | cut -d" " -f1
return 0
}

# Get ext IP address of current CP (must be active)
get_my_ext_ip ()
{
# look in current ifconfig
_tmp=`/sbin/ifconfig eth0 | grep "inet addr"`
if [ "0" != "$?" ] ; then
   /bin/echo "Error reading interface configuration for external ethernet" >&2
   return 1
fi
_addr=`/bin/echo $_tmp | /usr/bin/cut -d":" -f2 | /usr/bin/cut -d" " -f1`
if [ "0" != "$?" ] ; then
   /bin/echo "Ethernet address $_tmp does not appear to be valid" >&2
   return 1
fi
/bin/echo $_addr
return 0
}

# Get ext IP address of other CP (must be standby)
get_other_ext_ip ()
{
_otherint=`get_other_int_ip`
_tmp=`su $rcpuser -c "/usr/bin/rsh $_otherint /sbin/ifconfig eth0 | grep inet"`
/bin/echo $_tmp | /bin/grep -q "inet addr"
if [ "0" != "$?" ] ; then
   /bin/echo "Error reading other CP external ethernet IP addr" >&2
   return 1
fi
_addr=`/bin/echo $_tmp | /usr/bin/cut -d":" -f2 | /usr/bin/cut -d" " -f1`
if [ "0" != "$?" ] ; then
   /bin/echo "Other CP Ethernet address $_tmp does not appear to be valid" >&2
   return 1
fi
/bin/echo $_addr
return 0
}

#
# Standard installation does not include proper /etc/protocols
# settings so fix them.
#
fix_protocols () {
 /bin/echo "Fixing up /etc/protocols" >&2
 /bin/grep --quiet icmp /etc/protocols > /dev/null 2>&1
 if [ "0" != "$?" ] ; then
   cat >> /etc/protocols <<EOF
icmp    1       ICMP            # internet control message protocol
EOF
   /bin/echo "done" >&2
 else
   /bin/echo "/etc/protocols already ok" >&2
 fi
}

#
# Add extrnal IP address to .rhosts file so
# we can use rcp to test external link.
#
# $1 local ext ip address
# $2 other ext ip address
# $3 other int ip address
#
fix_rhosts () {
 cd /$rcpuser
 _dir=`/bin/pwd`
 /bin/echo "Fixing up $_dir/.rhosts $1 $2 $3" >&2
 /bin/grep --quiet $1 .rhosts > /dev/null 2>&1
 if [ "0" != "$?" ] ; then
     su $rcpuser -c "/bin/echo $1 >> .rhosts"
     if [ "0" != "$?" ] ; then
	 /bin/echo "Error updating .rhosts" >&2
	 exit -2
     fi
 fi
 /bin/grep --quiet $2 .rhosts > /dev/null 2>&1
 if [ "0" != "$?" ] ; then
     su $rcpuser -c "/bin/echo $2 >> .rhosts"
     if [ "0" != "$?" ] ; then
	 /bin/echo "Error updating .rhosts" >&2
	 exit -2
     fi
 fi
 su $rcpuser -c "rcp .rhosts $3:$_dir/.rhosts"
 if [ "0" != "$?" ] ; then
    /bin/echo "Error copying .rhosts to remote system" >&2
    exit -2
 fi

}

#
# Create test data directory in /tmp.  We need to copy
# data instead of directly useing /fabos to avoid
# permissions problems.
#
# $1 test data directory
setup_test_data () {
 /bin/echo "Setting up test data in /tmp/$1" >&2
 rm -rf /tmp/$1 > /dev/null 2>&1
 _rval=`su $rcpuser -c "cp -r /fabos/bin /tmp/$1; /bin/echo \\$?"`
 if [ "0" != "$_rval" ] ; then
    /bin/echo "Setup test data failed to copy /fabos/bin, status: $_rval" >&2
    /bin/echo "-1"
    return 1
 fi
 _rval=`su $rcpuser -c "cp -r /fabos/modules /tmp/$1; /bin/echo \\$?"`
 if [ "0" != "$_rval" ] ; then
    /bin/echo "Setup test data failed to copy /fabos/modules, status: $_rval" >&2
    /bin/echo "-1"
    return 1
 fi

 /bin/echo "0"
 return 0
}

#
# Do rcp test and diff
#
# $1 test data directory
# $2 rcv data directory
# $3 IP address to send/rcv from
#
rcp_test () {
 /bin/echo "Testing rcp /tmp/$1 to $3:/tmp/$1 to /tmp/$2" >&2

 #remove dest directory on the other side
 _cmd=`/bin/echo "/usr/bin/rsh $3 /bin/rm -rf /tmp/$1"`
 su $rcpuser -c "$_cmd" > /dev/null 2>&1

 #remove rcv directory on this side
 /bin/rm -rf /tmp/$2 > /dev/null 2>&1
 
 #copy source from here to there
 /bin/echo "Copy source to dest" >&2
 _cmd=`/bin/echo "/bin/rcp -r /tmp/$1 $3:/tmp/$1"`
 _rval=`su $rcpuser -c "$_cmd ; /bin/echo \\$?"`
 if [ "0" != "$_rval" ] ; then
    /bin/echo "Failed to copy data to $3:/tmp/$1" >&2
    /bin/echo "-4"
    return -4
 fi

 #copy from there to here
 _cmd=`/bin/echo "/bin/rcp -r $3:/tmp/$1 /tmp/$2"`
 /bin/echo "Copy dest to source" >&2
 _rval=`su $rcpuser -c "$_cmd ; /bin/echo \\$?"`
 if [ "0" != "$_rval" ] ; then
    /bin/echo "Failed to copy data from $3:/tmp/$1" >&2
    /bin/echo "-5"
    return -5
 fi

 #compare data
 /bin/echo "Compare data" >&2
 /usr/bin/diff -r /tmp/$1 /tmp/$2 >&2
 if [ "0" != "$?" ] ; then
    /bin/echo "Data was corrupted during copy" >&2
    /bin/echo "-6"
    return -6
 fi
 /bin/echo "Passed" >&2
 /bin/echo "0"
 return 0
}

#
# ping_test
#
# Do test of enet link with ping.
#
# $1 = IP address to test.
#
ping_test () {
for size in $frame_sizes ; do

    _cmd="/bin/ping -q -c $slow_ping_count -s $size $1"
    /bin/echo >&2
    /bin/echo "Testing command: $_cmd" >&2
    $_cmd >&2
    if [ "0" != "$?" ] ; then
	/bin/echo "Test failed" >&2
	/bin/echo "-3"
    fi

    if [ "0" != "$abort" ] ; then
	/bin/echo "Aborting" >&2
	/bin/echo "-3"
    fi

    _cmd="/bin/ping -q -f -c $flood_ping_count -s $size $1"
    /bin/echo >&2
    /bin/echo "Testing command: $_cmd" >&2
    $_cmd >&2
    if [ "0" != "$?" ] ; then
	/bin/echo "Test failed" >&2
	/bin/echo "-3"
    fi

    if [ "0" != "$abort" ] ; then
	/bin/echo "Aborting" >&2
	/bin/echo "-3"
    fi

    _cmd="/bin/ping -q -f -p"00ff00ff00ff00ff00ff00ff00ff00ff" -c $flood_ping_count -s $size $1"
    /bin/echo >&2
    /bin/echo "Testing command: $_cmd" >&2
    $_cmd >&2
    if [ "0" != "$?" ] ; then
	/bin/echo "Test failed" >&2
	/bin/echo "-3"
    fi

    if [ "0" != "$abort" ] ; then
	/bin/echo "Aborting" >&2
	/bin/echo "-3"
    fi

   _cmd="/bin/ping -q -f -p"000102030405060708090a0b0c0d0e0f" -c $flood_ping_count -s $size $1"
    /bin/echo >&2
    /bin/echo "Testing command: $_cmd" >&2
    $_cmd >&2
    if [ "0" != "$?" ] ; then
	/bin/echo "Test failed" >&2
	/bin/echo "-3"
    fi

    if [ "0" != "$abort" ] ; then
	/bin/echo "Aborting" >&2
	/bin/echo "-3"
    fi

done;
/bin/echo "0"
}


abort=0;
cleanup()
{
    /bin/echo "Terminated"
    abort=1
    exit -1
}


#  setup signal trap to call cleanup() if the followings:
#	control/d entered at the same window
#	kill <pid> is entered
#
trap cleanup INT TERM KILL

my_ip=`get_my_int_ip`
status=$?
if [ $status -ne 0 ]
then
     exit $status
fi
/bin/echo "My int ip is $my_ip"

my_ip=`get_my_ext_ip`
status=$?
if [ $status -ne 0 ]
then
     exit $status
fi
/bin/echo "My ext ip is $my_ip"

other_int=`get_other_int_ip`
status=$?
if [ $status -ne 0 ]
then
     exit $status
fi
/bin/echo "Other int ip is $other_int"

other_ext=`get_other_ext_ip`
status=$?
if [ $status -ne 0 ]
then
     exit $status
fi
/bin/echo "Other ext ip is $other_ext"

fix_protocols
fix_rhosts $my_ip $other_ext $other_int

rval=`setup_test_data $testdir`
if [ "0" != "$rval" ] ; then
  /bin/echo "Failed to setup test data for rcp test, status: $rval"
  exit $rval
fi



test=0

while [ $test -lt $max_loops ] ; do

    /bin/echo ""
    /bin/echo "Test loop $test"

    /bin/echo ""
    /bin/echo "Testing Internal link with Ping"
    rval=`ping_test $other_int`

    /bin/echo ""
    /bin/echo "Testing External link with Ping"
    rval=`ping_test $other_ext`

    rval=`rcp_test $testdir $rcvdir $other_int`
    if [ "0" != "$rval" ] ; then
      /bin/echo "Rcp test to IP $other_int failed, status: $rval"
      exit $rval
    fi

    rval=`rcp_test $testdir $rcvdir $other_ext`
    if [ "0" != "$rval" ] ; then
      /bin/echo "Rcp test to IP $other_ext failed, status: $rval"
      exit $rval
    fi

    test=`expr $test + 1`

done;
