#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG                                                    
#  This is an automatically generated prolog.                                  
#                                                                              
#  Copyright (C) Altran ACT S.A.S. 2017,2020,2021.  All rights reserved.  
#                                                                              
#  ALTRAN_PROLOG_END_TAG                                                      
#                                                                              
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r720 src/43haes/usr/sbin/cluster/events/utils/cl_configure_persistent_address.sh 1.56.1.4 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2001,2015 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)  7d4c34b 43haes/usr/sbin/cluster/events/utils/cl_configure_persistent_address.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM

###########################################################################
#
#  Name: cl_configure_persistent_address
#
#  This script is used to bring up (alias) persistent labels onto
#  interfaces during adapter events, HA start-up, AIX boot-up, and during
#  cluster synchronization.
#
#  Syntax:  cl_configure_persistent_address <action> [-n] [-a] [-f] [-i] [-d]
#  Arguments:
#              action     Required for all calls, tells this script
#                         what to do.
#
#              -n         What network to examine, not needed for the
#                         "config_all" action.
#
#              -a         For the "up" action, which svc interface
#                         is being acquired/released, e.g. en1.
#                         For the "swap" action, the interface to which the
#                         boot/svc address is moving.
#
#              -f         For the "swap" action, which boot/svc interface
#                         failed.
#
#              -i         For the "fail_boot" action, the address of the
#                         failed boot address.
#
#              -d         Do not check if the clstrmgr is running.
#
#              -B         The command is executed at boot time ie)from harc.net.
#                         delete_bad_default_routes is executed.
#
###########################################################################
###############################################################################
# Name: flush_ndp_cache
#
#   Flushes entire ndp cache
#
# Returns: None.
###############################################################################
flush_ndp_cache () {
    typeset PS4_FUNC="flush_ndp_cache"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    ndp -an | grep "\?" | tr -d '()' | (while read host addr other ; do
        ndp -d $addr
    done)
    return 0
}

###############################################################################
# Name: add_rc_check
#
#   Add an exit code check, message and error exit to a file.
#
# Arguments:
#       $1 - filename
#       $2 - function name (for message)
#
# Returns: N/A
###############################################################################
add_rc_check() {

    typeset PS4_FUNC="add_rc_check"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    RR=$1
    FUNC=$2

    cat >>$RR<<-EOF
    rc=\$?
    if [[ \$rc != 0 ]]
    then
        echo "ERROR: $FUNC failed with code \$rc"
        exit \$rc
    fi

EOF

}

###############################################################################
# Name: get_inet_family
#
# The routines returns the internet family of the given IP label.
#
# Arguments: IP address
#
# Returns: unspec: unknown family
#          inet:   AF_INET family (IPv4 IP address)
#          inet6:  AF_INET6 family (IPv6 IP address)
#
###############################################################################
get_inet_family() {
    typeset PS4_FUNC="get_inet_family"

    ip_label=$1
    inet_family=$(cllsif -J "$OP_SEP" -Sn $ip_label | awk -F"$OP_SEP" '{print $15}')
    case "$inet_family" in
    	AF_INET)
        	echo "inet"
        	return
        	;;
	AF_INET6)
		echo "inet6"
        	return
        	;;
        *)
		dspmsg scripts.cat 9503 "\n$PROGNAME: ERROR: Invalid address \
family for IP address \"$ip_label\".\n" $PROGNAME $ip_label
		exit 1
		;;
	esac
}
###############################################################################
# Name: configure_linklocal_routes
#
# On configuration of IPv6 address on a link, it creates static routes for
# routing nw traffic to destination ffx2::/16, be routed via gateway 
# (=link local address of that link). 
#
# Arguments: old interface name (example: en0, en1 etc.)
#            new interface
#
# Returns: nothing
#
###############################################################################
configure_linklocal_routes() {
    typeset PS4_FUNC="configure_linklocal_routes"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    old_intf=$1
    new_intf=$2

    new_gateway=$(netstat -in | awk -v intf=$new_intf '(($1==intf) && \
                  ($3 ~ /^fe80::*/)) {print $3}' | head -1)
                 
    route delete -inet6 -net ff02::/16 -if $old_intf
    route delete -inet6 -net ff12::/16 -if $old_intf
    
    route add -inet6 -net ff02::/16 $new_gateway -if $new_intf -static
    route add -inet6 -net ff12::/16 $new_gateway -if $new_intf -static
}

#########################################################################
#
# Name: best_boot_addr
#
# This routine finds the best interface for hosting a persistent label.
# This routine exercises the resource distribution preference for service labels
# which may affect the placement of the persistent label. 
# The options of interest here are:
#       collocation with persistent - put all service on the same interface
#               as the one holding the persistent
#       anti-collocation with persistent - avoid putting service on the
#               same interface as the persistent
#
# Arguments: network name
#            List of candidate boot addresses on that network
#
# Globals used: ALIVE_IF
#
# Returns: network address of the selected boot interface
#
#########################################################################
best_boot_addr () {

    typeset PS4_FUNC="best_boot_addr"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    NETWORK=$1
    shift
    candidate_boots=$*

    # if there is only one boot then thats the candidate - regardless of
    # state or distribution preference
    let num_candidates="$(echo $candidate_boots | tr " " "\n" | wc -l)";
    if (( $num_candidates == 1 )); then
        echo $candidate_boots
        return;
    fi

    best_candidate=NONE
    best_aliases=0

    # find the (optional) service label distribution preference for this network
    MA=$(odmget -q"network = $NETWORK AND function = shared" HACMPadapter |
                        grep "max_aliases" | awk '{print $3}' |  sort -nu | tail -1)

    # decode the setting
    case $MA in
        259|1283 )   # collocation with persistent
            # configure_persistent has been called with a
	    # target interface which is where the service label will be 
            # mapped - that interface is where the persistent must also go
	    # scan list of candidates
	    for candidate in $candidate_boots
	    do
		boot_if=$(LC_ALL=C clgetif -a $candidate 2>/dev/null | awk '{print $1}')
		if [[ "$boot_if" == "$ALIVE_IF" ]]
		then
			break
		fi
	    done
	    echo "$candidate"
	    return;
            ;;
        515|1539 )   # anti-collocation with persistent

            # configure_persistent has been called with a
	    # target interface which is where the service label will be 
            # mapped - that interface should be avoided if there is another
	    # interface available
	
	    # find all services on this network
            services=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | \
                        awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "service" && \
                        $3 == NET) print $1}' | sort)

	    # loop through the candidates to try and find one that is available
	    # and is _not_ holding any service(s)
            for candidate in $candidate_boots
            do
                boot_if=$(LC_ALL=C clgetif -a $candidate 2>/dev/null | awk '{print $1}')
                [[ -z "$boot_if" ]] && continue;

		if [[ "$boot_if" == "$ALIVE_IF" ]]
		then
			best_candidate=$candidate
		fi
		# boot is active on this node - see if its holding any 
		# services already
		service_if=""
		for service in $services
            	do
                    # is it on this node ?
                    service_if=$(LC_ALL=C clgetif -a $service 2>/dev/null | awk '{print $1}')
                    [[ -z "$service_if" ]] && continue;        # not on local

		    # is it on the same interface as the boot ?
                    [[  $service_if == $boot_if ]] && break; 

                done

		# if the block above found a service on this boot, its not
	  	# a good candidate
                [[ $service_if == $boot_if ]] && continue; 
		
		# no service on this interface, done.
		echo "$candidate"	
		return;
		
            done

	    # if here the tests above did not find a better interface - just
	    # return the address on the interface we were called with 
	    echo "$best_candidate" 
	    return;
            ;;
        * )     # not set or not one of the policies we care about - just return
		# the interface we were called with
	    for candidate in $candidate_boots
	    do
		boot_if=$(LC_ALL=C clgetif -a $candidate 2>/dev/null | awk '{print $1}')
		if [[ "$boot_if" == "$ALIVE_IF" ]]
		then
			break
		fi 
	    done
	    echo "$candidate"
	    return;
	    ;;
    esac

     # Should never get here
     dspmsg scripts.cat 342 "Unable to determine local boot/service interface.\n"
     exit 1;

}






############################################################################
#
#  Name: getNetmask
#
#  HAES: This function will return the netmask of the persistent label
#        from the HACMPnetwork ODM.
#
#  HAS:  This function will return the netmask of the first IP address
#        bound to the interface passed as an argument.  The netmask field
#        does not exist in the HACMPnetwork ODM in HAS.  The first IP
#        address printed by ifconfig will always be the IP address that
#        is bound to the interface not as an alias, and thus will be
#        either a boot or service address.
#
#  Arguments:  interface name, e.g. en0
#
#  Returns:  netmask string, e.g. 0xffffff00
#
############################################################################
getNetmask() {
    typeset PS4_FUNC="getNetmask"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    IF=$1
    NETMASK=""

	NETMASK=$(cllsif -J "$OP_SEP" -Spn $PERSISTENT | cut -d"$OP_SEP" -f11)
	if [[ -n $NETMASK ]]; then
	    print $NETMASK
	else
	    # If the HACMPadapter ODM didn't contain a filled in netmask
	    # field, then grab it from the interface.
	    print $(ifconfig $IF | grep -w netmask | awk '{print $4; exit}')
	fi	
}


############################################################################
#
#  Name: getAliveBootsServices
#
#  For non-IP aliasing networks, this function will call cllssvcs to return
#  the alive boot/service label on the local network.
#  For IP aliasing networks, cllsstbys will be called to return the alive
#  boot labels on the local network.
#
#  Arguments:  network name
#
#  Returns:  list of service/boot labels to stdout
#
############################################################################
getAliveBootsServices() {
    typeset PS4_FUNC="getAliveBootsServices"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    NETWORK=$1

    if [[ $(isAliasingNetwork $NETWORK) == "1" ]]; then
	cllsstbys $NETWORK | awk '{print $1}'
    else
	cllssvcs | awk '$2 == "'$NETWORK'" {print $1}'
    fi
}

############################################################################
#
#  Name: isAliasingNetwork
#
#  Determines if $NETWORK is an aliasing network by querying the
#  HACMPNetwork ODM.
#
#  Arguments:  network name
#
#  Returns:  printed to stdout:
#               1 - aliasing network
#               0 - non-aliasing network
#
############################################################################
isAliasingNetwork() {
    typeset PS4_FUNC="isAliasingNetwork"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    NETWORK=$1

    print $(odmget -q"name=$NETWORK" HACMPnetwork \
	    | awk '$1 == "alias" {print $3}' \
	    | sed 's/"//g')
}


############################################################################
#
#  Name: configAll
#
#  This function will alias each persistent label defined on a network
#  on the local node onto an appropriate interface.
#
#  Arguments:  none
#
#  Returns:  nothing
#
############################################################################
configAll() {
    typeset PS4_FUNC="configAll"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    typeset HA_RUNNING;
    HA_RUNNING=0

    # If we explicitly get the "-d" argument passed to us, then
    # don't try to determine if HA is running.  If we didn't do this,
    # and tried to determine if HA was running in every case, then
    # we could end up getting called from rc.cluster after the cluster
    # manager has started, but before it can accept RPC requests,
    # which would cause the call to cllssvcs/cllsstbys to wait and timeout.
    # The -d argument is used from harc.net and rc.cluster.
    if [[ $CHECK_HA_ALIVE == 0 ]]; then
	HA_RUNNING=0
	[[ $B_FLAG == 1 ]] &&
        delete_bad_default_routes
    else
	# If cluster services are running on the local node, then
	# we want to try looking for alive service/boot labels on the
	# local node.
	CURRENT_STATE=$(lssrc -ls clstrmgrES \
            | awk -F: '($1 == "Current state") { print $2 }' | sed 's/ //g')

	if [[ -n "$CURRENT_STATE" && $CURRENT_STATE != "ST_INIT" && 
				     $CURRENT_STATE != "NOT_CONFIGURED" ]]; then
	    HA_RUNNING=1
	fi
    fi

    # 
    # Outer loop is through all persistent labels for this node
    #
    for ADDR_INFO in $(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME |\
                         awk -F"$OP_SEP" '$2 == "persistent" {print}')
    do
        #
        : ADDR_INFO=$ADDR_INFO
        #
	print $ADDR_INFO | awk -F"$OP_SEP" '{print $7 " " $3}' \
	    | read PERSISTENT NETWORK

        #
        : PERSISTENT=$PERSISTENT NETWORK=$NETWORK
        #
	IF1=$(clgetif -a $PERSISTENT 2>/dev/null | awk '{print $1}')

	if [[ -z $IF1 ]]; then
	    PERSISTENT_CONFIGURED=0
	else
	    DOWN=$(netstat -in | grep -w ^$IF1 \
		| awk '{getline; getline; if ($1 != "'$IF1'") {print $1}}')
	    if [[ -n $DOWN ]]; then
		# The interface wasn't found in netstat, e.g. en1,
		# which means it is probably down and would show up in
		# netstat as en1*.  We continue on and hope to find another
		# interface that is up for this persistent label to alias
		# onto.  We'll ifconfig delete the persistent label from this
		# interface later in the code.
		PERSISTENT_CONFIGURED=1

	    else
                # The interface that the persistent label is on is up and
                # available, we don't call a ifconfig on this interface
                # because if we realias then the default routes of persistent IP
                # will be overwritten by that of service IP if both of them have the
                # same subnet. This happens because ifconfig deletes the persistent IP
                # entry before adding it now when this persistent IP entry is removed
                # service IP takes it position as it is in the same subnet this results in
                # change of routes.
		check_alias_status $IF1 $PERSISTENT "acquire"
		continue;
	    fi
	fi

	IF2=""
	LABEL=""
	DOWN_IF=""
	DOWN_LABEL=""

	# A note on the code paths into this section: 
 	# harc.net and rc.cluster - where HA_RUNNING=0
	# from dare - where HA_RUNNING could be 0 or 1 
	# clchpcihpif - where HA_RUNNING also could be 0 or 1, but 
	# USER_REQUESTED will be set. 
	# For all cases where running = 0 or USER_REQUESTED is set
	# there is no need to exercise the distribution preference: simply add
	# the persistent on the first available interface. 
	# If ha is running then we have been called in a dynamic dare, but 
	# we can only get this far if dare'ing in a new persistent (an 
	# existing persistent would have been handled above). 
	# Any subsequent acquires or releases due to other changes made by 
	# dare will exercise the preference.

	# Look at all the candidates to find the best one

	if [[ $HA_RUNNING == 1 ]]; then
	    # If HA is running on the local node then we try to find
	    # an alive boot or service interface onto which we can
	    # alias the persistent label.
    
	    # find the (optional) service label distribution preference for 
	    # this network
    	    MA=$(odmget -q"network = $NETWORK AND function = shared" HACMPadapter |
                        grep "max_aliases" | awk '{print $3}' | sort -nu | tail -1)

    	    # decode the setting
    	    case $MA in
        	259 )   # collocation with persistent
            	    # find the first interface on this network that also
		    # has a service, or the first one up
		    # find all services on this network
            	    services=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | \
            	    awk -F"$OP_SEP" -v NET="$NETWORK" \
                    '{if ($2 == "service" && $3 == NET) print $1}' | sort)
            	    service_if=""
            	    save_if=""
		    candidate_found=0	# used to break out of loop
	    	    for LABEL in $(getAliveBootsServices $NETWORK); do
			(( $candidate_found == 1 )) && break;
		        IF2=$(LC_ALL=C clgetif -a $LABEL 2>/dev/null | awk '{print $1}')
		        if [[ -z $IF2 ]]; then
		            IF2=""
		            LABEL=""
		            continue
		        fi
			# save this just in case we dont find a better one
			save_if=$IF2
			# see if this interface also has a service
            		for service in $services
            		do
			    service_if=$(LC_ALL=C clgetif -a $service 2>/dev/null | awk '{print $1}')
			    if [[ $service_if == $IF2 ]]
			    then
				candidate_found=1
				break;	# out of both loops !
			    fi
			done
		    done
		    # if the loop above did not find a perfect candidate but
		    # did find one that was close, use that one
		    [[ -z "$IF2" && -n "$save_if" ]] && IF2=$save_if
            	    ;;
        	515 )   # anti-collocation with persistent
            	    # find the first interface on this network that has
		    # no service on it, and if none found just return the
		    # last one up
                    services=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | \
                                awk -F"$OP_SEP" -v \
                                NET="$NETWORK" '{if ($2 == "service" && \
                                $3 == NET) print $1}' | sort)
                    service_if=""
                    save_if=""
                    candidate_found=0
                    for LABEL in $(getAliveBootsServices $NETWORK); do
                        (( $candidate_found == 1 )) && break;
                        IF2=$(LC_ALL=C clgetif -a $LABEL 2>/dev/null | awk '{print $1}')
                        if [[ -z $IF2 ]]; then
                            IF2=""
                            LABEL=""
                            continue
                        fi
                        # save this just in case we dont find a better one
                        save_if=$IF2
                        # see if this interface also has a service
                        for service in $services
                        do
                            service_if=$(LC_ALL=C clgetif -a $service 2>/dev/null | awk '{print $1}')
                            if [[ $service_if != $IF2 ]]
                            then
                                candidate_found=1
			    else
                                candidate_found=0
				break;	# go on to next interface
                            fi
                        done
                    done
		    # if the loop above did not find a perfect candidate but
		    # did find one that was close, use that one
		    [[ -z "$IF2" && -n "$save_if" ]] && IF2=$save_if
            	    ;;
        	1539 )   # anti-collocation with persistent
            	    # find the first interface on this network that has
		    # no service on it, and if none found just return the
		    # last one up
                    services=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | \
                                awk -F"$OP_SEP" -v \
                                NET="$NETWORK" '{if ($2 == "service" && \
                                $3 == NET) print $1}' | sort)
                    service_if=""
                    save_if=""
                    candidate_found=0
                    for LABEL in $(getAliveBootsServices $NETWORK); do
                        [[ $candidate_found == 1 ]] && break;
                        IF2=$(LC_ALL=C clgetif -a $LABEL 2>/dev/null | awk '{print $1}')
                        if [[ -z $IF2 ]]; then
                            IF2=""
                            LABEL=""
                            continue
                        fi
                        # save this just in case we dont find a better one
                        save_if=$IF2
                        # see if this interface also has a service
                        for service in $services
                        do
                            service_if=$(LC_ALL=C clgetif -a $service 2>/dev/null | awk '{print $1}')
                            if [[ $service_if != $IF2 ]]
                            then
                                candidate_found=1
			    else
                                candidate_found=0
				break;	# go on to next interface
                            fi
                        done
                    done
		    # if the loop above did not find a perfect candidate but
		    # did find one that was close, use that one
		    [[ -z "$IF2" && -n "$save_if" ]] && IF2=$save_if
            	    ;;
            	* )	# none - simply find the first available interface
	    	    for LABEL in $(getAliveBootsServices $NETWORK); do
		        IF2=$(LC_ALL=C clgetif -a $LABEL 2>/dev/null | awk '{print $1}')
		        if [[ -z $IF2 ]]; then
		            # Couldn't find interface for $LABEL. It seems a bit
		            # odd that the label should be marked active by 
		            # clstrmgr but not actually found by clgetif.
		            IF2=""
		            LABEL=""
		            continue
		        fi

		        # We found the interface to alias the persistent label
		        # onto, so break out of the searching loop.
		        break
	            done
            	    ;;
	    esac
	fi

	# If $IF2 is empty, then either HA is not running, or HA is running
	# but no alive boot or service interfaces could be found in the above
	# loop, so we search for a boot or service interface that is
	# ifconfig-ed up.  If none are up, then we will alias the persistent
	# label onto the last found interface that is available but
	# ifconfig-ed down.
	if [[ -z $IF2 ]]; then
	    for LABEL in $(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | \
		  awk -F"$OP_SEP" '($3 == "'$NETWORK'" && ($2 == "boot" || $2 == "service")) \
		  {print $1}')
	    do
		if [[ -z $LABEL ]]; then
		    continue
		fi
		IF2=$(LC_ALL=C clgetif -a $LABEL 2>/dev/null | awk '{print $1}')
		if [[ -z $IF2 ]]; then
		    # Couldn't find interface for $LABEL.
		    IF2=""
		    LABEL=""
		    continue
		fi

		DOWN=$(netstat -in | grep -w ^$IF2 \
		    | awk '{getline; getline; if ($1 != "'$IF2'") {print $1}}')
		if [[ -n $DOWN ]]; then
		    # The interface wasn't found in netstat, e.g. en1,
		    # which means it is probably down and would show up in
		    # netstat as en1*.  We store the interface anyways
		    # since we might not find another interface that is alive.
		    DOWN_IF=$IF2
		    DOWN_LABEL=$LABEL
		    IF2=""
		    LABEL=""
		    continue
		fi

		# We found the interface to alias the persistent label
		# onto, so break out of the searching loop.
		break
	    done
	fi

	if [[ -z $IF2 ]]; then
	    if [[ -n $DOWN_IF ]]; then
		# We didn't find an up interface, but we found one that was
		# down, so use that one.
		IF2=$DOWN_IF
		LABEL=$DOWN_LABEL
	    else
		cl_log 7600 \
"$PROGNAME: Failed to find a configured boot or service interface for \
persistent IP label $PERSISTENT.  The persistent IP label $PERSISTENT will not \
be available.\n" $PROGNAME $PERSISTENT $PERSISTENT
		continue
	    fi
	fi

	# Use the same netmask as the service/boot interface
	# onto which we are aliasing the persistent label.
	NETMASK=$(getNetmask $IF2)
    
    	#IPv6 persistent IP labels will have its own prefix length, 
    	#so, get the prefix length from HACMP configuration.  
    	PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT | \
                    awk -F"$OP_SEP" '{print $14}')
    	INET_FAMILY=$(get_inet_family $PERSISTENT)
	 ALIAS_PREF=$(odmget -q "function = shared AND identifier = $PERSISTENT" HACMPadapter | grep "max_aliases" | awk '{print$3}')
    
	if [[ "$ALIAS_PREF" == "259" ]]
	then
		 FIRST_ALIAS="firstalias"
	 else
		  FIRST_ALIAS=" "
	  fi
	  #Added this if condition to use the transfer and first alias option.
	if [[ "$INET_FAMILY" == "inet" ]]
	then
	  if [[ $PERSISTENT_CONFIGURED == 1 ]] && [[ $IF1 != $IF2 ]]; then
		ifconfig $IF1 $PERSISTENT transfer $IF2 $FIRST_ALIAS
	  else
		ifconfig $IF2 alias $PERSISTENT netmask $NETMASK up $FIRST_ALIAS
	  fi

	else
	  if [[ $PERSISTENT_CONFIGURED == 1 ]] && [[ $IF1 != $IF2 ]]; then
	    # If the interface we are going to alias the persistent
	    # label onto is different from the interface where it
	    # is currently configured, then delete the persistent
	    # alias from IF1.


	    if [[ "$INET_FAMILY" == "inet6" ]]
	    then
	        alias_replace_ipv6_routes $RESTORE_ROUTES $IF1
	    else
	        alias_replace_routes $RESTORE_ROUTES $IF1
	    fi

	    RC=$?
	    : alias_replace_routes completed with code $RC
	    [[ $RC != 0 ]] && exit 1
	    
	    if [[ "$INET_FAMILY" == "inet6" ]]
            then 
              	   ifconfig $IF1 inet6 delete $PERSISTENT
            else
                   ifconfig $IF1 delete $PERSISTENT
            fi
	    
	    check_alias_status $IF1 $PERSISTENT "release"
            if [[ "$INET_FAMILY" == "inet6" ]]
            then 
                # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
                # if the interface is not having any LL address then run autoconf6 on the same interface.
                # Note: All the link-local addresses starts with "fe80::"
                LL_ADDR=$(ifconfig $IF2 inet6 | awk '($2 ~ /^fe80::*/){print $2}')
                if [[ -z "$LL_ADDR" ]]
                then
                    autoconf6 -i $IF2
                fi
                ifconfig $IF2 inet6 alias $PERSISTENT/$PREFIXLEN up
            else
                ifconfig $IF2 alias $PERSISTENT netmask $NETMASK up
            fi

	    $RESTORE_ROUTES
	    RC=$?
	    : Completed $RESTORE_ROUTES with return code $RC
	    [[ $RC != 0 ]] && exit 1
	  else
	        if [[ "$INET_FAMILY" == "inet6" ]]
                then 
                    # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
                    # if the interface is not having any LL address then run autoconf6 on the same interface.
                    # Note: All the link-local addresses starts with "fe80::"
                    LL_ADDR=$(ifconfig $IF2 inet6 | awk '($2 ~ /^fe80::*/){print $2}')
                    if [[ -z "$LL_ADDR" ]]
                    then
                        autoconf6 -i $IF2
                    fi
     	            ifconfig $IF2 inet6 alias $PERSISTENT/$PREFIXLEN up
     	        else
     	            ifconfig $IF2 alias $PERSISTENT netmask $NETMASK up
     	        fi
	  fi
	fi

	check_alias_status $IF2 $PERSISTENT "acquire"
    done
}


###############################################################################
# From cl_swap_IP_address, modified to take an IP label as an argument
# instead of an IP address.
#
# Name: check_alias_status
#
# This modification to check_ifconfig_status, added for IP aliasing support 
# because ifconfig displays aliased addresses on additional lines.
#
# Arguments:
#   Interface to check
#   IP address in dotted-decimal format
#   Acquiring or Releasing address
#
# Returns:
#   0 Interface has a proper entry
#   1 Interface does not have a proper entry
#
###############################################################################
check_alias_status () {
    typeset PS4_FUNC="check_alias_status"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    CH_INTERFACE=$1
    CH_LABEL=$2
    CH_ACQ_OR_RLSE=$3

    CH_ADDRESS=$(cllsif -J "$OP_SEP" -Spn $CH_LABEL | \
                cut -d"$OP_SEP" -f 7)
    ADDR=$(ifconfig $CH_INTERFACE | awk '{print $2}' | awk -F/ '($1 == "'$CH_ADDRESS'") {print $1}')

    if [[ "$CH_ACQ_OR_RLSE" == "acquire" ]]
    then

        # if acquiring, make sure the alias IS on the interface
        [[ "$ADDR" != "$CH_ADDRESS" ]] && {
            cl_log 7324 "$PROGNAME: Failed to ifconfig alias $CH_ADDRESS on interface $CH_INTERFACE" $PROGNAME $CH_ADDRESS $CH_INTERFACE
            return 1
        }
        CLUSTER_STATE=$(lssrc -ls clstrmgrES \
                        | awk -F: '($1 == "Current state") { print $2 }' | sed 's/ //g')

        if [[ -n "$CLUSTER_STATE" && $CLUSTER_STATE != "ST_INIT" &&
                                     $CLUSTER_STATE != "NOT_CONFIGURED" && $UPDATE_CLSTRMGR != 0 ]]; then
           cl_hats_adapter $CH_INTERFACE -e $ADDR alias
        fi      
    else
        # if releasing, make sure the alias IS NOT on the interface
        [[ "$ADDR" == "$CH_ADDRESS" ]] && {
            cl_log 7325 "$PROGNAME: Failed ifconfig delete alias $CH_ADDRESS from interface $CH_INTERFACE." $PROGNAME $CH_ADDRESS $CH_INTERFACE
            return 1
        }
    fi
    return 0
}

###############################################################################
# Name: flush_arp
#
#       Flushes entire arp cache
#
# Returns: None.
###############################################################################
flush_arp () {
    typeset PS4_FUNC="flush_arp"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    arp -an | grep "\?" | tr -d '()' | (while read host addr other ; do
        arp -d $addr
    done)
    return 0
}

###############################################################################
# Name: alias_replace_routes
#
#   For the list of interfaces given on command line, moves each route
#   to 127.1 (lo0) and writes a file (name in $1) containing a shell
#   script that will restore the original routing table
#
# Arguments:
#       $1 - filename
#       $2 - failing interface name
#	Also uses the following variables, global or set in main routine:
#	LOCALNODENAME, NETWORK
#
# Returns: 1 on error, otherwise 0
###############################################################################
alias_replace_routes() {

    typeset PS4_FUNC="alias_replace_routes"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    RR=$1
    shift
    interfaces="$*"
    RC=0
    PERSISTENT_IP=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
                    grep "${OP_SEP}$NETWORK${OP_SEP}" | grep -E "${OP_SEP}persistent${OP_SEP}" | cut -d"$OP_SEP" -f7)

    cp /dev/null $RR

    cat >$RR<<-EOF
	#!/bin/ksh
	#
	# Script created by $PROGNAME on $(date)
	#
	PATH=$PATH
	PS4='$PS4'
	export VERBOSE_LOGGING=\${VERBOSE_LOGGING:-"high"}
	[[ "\$VERBOSE_LOGGING" == "high" ]] && set -x
	: Starting \$0 at \$(date)
	#
	EOF

    LOCADDRS=$(netstat -in | awk '$3 !~ "[Ll]ink" && $3 !~ "Network" {print $4}')
    netstat -rnC
    # according to the netstat command man page:
    # U = Up
    # c = Access to this route creates a cloned route
    # H = route to a host (use -host instead of -net)
    # W = the route is a cloned route
    # b = the route broadcast route

    netstat_flags="-nrf inet"
    for ifce in $interfaces ; do
	integer I=1
	NXTSVC=""
	IFADDRS=$(netstat -in | awk '$3 !~ "[Ll]ink" && ($1 == "'$ifce'" || $1 == "'$ifce\*'") {print $4}')
	SVCADDRS=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
	           grep "${OP_SEP}$NETWORK${OP_SEP}"| grep -E "${OP_SEP}service${OP_SEP}|${OP_SEP}persistent${OP_SEP}" | \
	           cut -d"$OP_SEP" -f7 |sort -u)
	routeaddr=""
	for ifaddr in $IFADDRS
	do
		for svcaddr in $SVCADDRS
		do
		if [[ $(clgetnet $ifaddr $NETMASK) == $(clgetnet $svcaddr $NETMASK) ]]
		then
			if [[ -z "$routeaddr" ]]
			then
				routeaddr=$ifaddr
			fi
			if [[ "$ifaddr" == "$svcaddr" && "$ifaddr" != "$routeaddr" ]]
			then
				NXTSVC=$svcaddr
				break
			fi
			fi
		done
		if [[ -n $NXTSVC ]]
		then
			break
		fi
	done
	swaproute=0
	if [[ "$PERSISTENT_IP" == "$routeaddr" ]]
	then
		swaproute=1
	fi

	netstat $netstat_flags | fgrep -w $ifce | while read DEST GW FLAGS OTHER ; do
	    LOOPBACK="127.0.0.$I"
	
	    case $FLAGS in
		U|Uc)
		    if [[ $(clgetnet $PERSISTENT_IP $NETMASK) == $(clgetnet $GW $NETMASK) ]]
		    then
		    if [[ "$PERSISTENT_IP" == "$GW" ]]
		    then
			route delete -net $DEST $GW
		    fi
		    fi
		    ;;
		U*W*)
		    # all routes created by cloning are evil
		    route delete -host $DEST $GW
		    ;;
		U*H*b*)
		    #Delete broadcast routes if persistent IP is gateway
		    if [[ "$PERSISTENT_IP" == "$GW" ]]
		    then
			route delete -host $DEST $GW
		    fi 
		    ;;
		U*H*)
		    # If $DEST is a locally configured address, do
		    # nothing with this route since it may interfere
		    # with netmon logic.
		    typeset -i found=0
		    for addr in $LOCADDRS
		    do
			if [[ "$addr" == "$DEST" ]]
			then
			    found=1
			    break
			fi
		    done
		    if (( $found == 0 ))
		    then
			if [[ $(clgetnet $PERSISTENT_IP $NETMASK) == $(clgetnet $GW $NETMASK) ]]
			then
			    # into RR we put the route command:
			    if [[ $swaproute == 1 ]]
			    then
				print "cl_route_change -if$PERSISTENT_IP $DEST $LOOPBACK $GW inet" >>$RR
				add_rc_check $RR "cl_route_change"
			    else
				print "cl_route_change $DEST $LOOPBACK $GW inet" >>$RR
				add_rc_check $RR "cl_route_change"
			    fi
		            # which will undo:
			    cl_route_change $DEST $GW $LOOPBACK inet
			    RC=$?
			    : cl_route_change completed with rc $RC
			    [[ $RC != 0 ]] && RC=1
			    I=I+1
			fi
		    fi
		    ;;
		U*)
		    if [[ $(clgetnet $PERSISTENT_IP $NETMASK) == $(clgetnet $GW $NETMASK) ]]
		    then
			# into RR we put the route command:
			if [[ $swaproute == 1 ]]
			then
				print "cl_route_change -if$PERSISTENT_IP $DEST $LOOPBACK $GW inet" >>$RR
				add_rc_check $RR "cl_route_change"
			else
				print "cl_route_change $DEST $LOOPBACK $GW inet" >>$RR
				add_rc_check $RR "cl_route_change"
			fi	
			# which will undo:
			cl_route_change $DEST $GW $LOOPBACK inet
			RC=$?
			: cl_route_change completed with rc $RC
			[[ $RC != 0 ]] && RC=1
			I=I+1
		    fi
		    ;;
	    esac
	done
    done

    chmod +x $RR
    return $RC
}
###############################################################################
# Name: alias_replace_ipv6_routes
#
#   For the list of interfaces given on command line, moves each route
#   to ::1 (lo0) and writes a file (name in $1) containing a shell
#   script that will restore the original routing table
#
# Arguments:
#       $1 - filename
#       $2 - failing interface name
#   Also uses the following variables, global or set in main routine:
#   LOCALNODENAME, NETWORK
#
# Returns: N/A
###############################################################################
alias_replace_ipv6_routes() {
    typeset PS4_FUNC="alias_replace_ipv6_routes"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    RR=$1
    shift
    interfaces="$*"
    RC=0
    PERSISTENT_IP=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
                    grep "${OP_SEP}$NETWORK${OP_SEP}" | grep -E "${OP_SEP}persistent${OP_SEP}" | cut -d"$OP_SEP" -f7)
    PERSISTENT_PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT_IP | awk -F"$OP_SEP" '{print $14}')
                        

    cp /dev/null $RR

cat >$RR<<-EOF
#!/bin/ksh
#
# Script created by $PROGNAME on $(date)
#
PATH=$PATH
PS4='$PS4'
export VERBOSE_LOGGING=\${VERBOSE_LOGGING:-"high"}
[[ "\$VERBOSE_LOGGING" == "high" ]] && set -x
: Starting \$0 at \$(date)
EOF

    LOCADDRS=$(netstat -in | awk '$3 !~ "[Ll]ink" && $3 !~ "Network" {print $4}')
    netstat -rnC
    # according to the netstat command man page:
    # U = Up
    # c = Access to this route creates a cloned route
    # H = route to a host (use -host instead of -net)
    # W = the route is a cloned route
    # b = the route broadcast route

    netstat_flags="-nrf inet6"
    for ifce in $interfaces ; do
    integer I=1
    NXTSVC=""
    IFADDRS=$(ifconfig $ifce | grep "inet6" | awk  '{print $2}')
    SVCADDRS=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
               grep "${OP_SEP}$NETWORK${OP_SEP}"| grep -E "${OP_SEP}service${OP_SEP}|${OP_SEP}persistent${OP_SEP}" | \
               cut -d"$OP_SEP" -f7 |sort -u)
    routeaddr=""
    for ifaddr in $IFADDRS
    do
        ifaddr_nw=$(clgetnet $(echo $ifaddr |  sed 's/\// /'))
        ifaddr_prefixlength=$(echo $ifaddr | awk -F"/" '{print $2}')
        for svcaddr in $SVCADDRS
        do
            svcaddr_prefixlen=$(cllsif -J "$OP_SEP" -Sn $svcaddr | \
                awk -F"$OP_SEP" '{print $14}')
            svcaddr_nw=$(clgetnet $svcaddr $svcaddr_prefixlen)
            # It is not sufficient to "only" compare the dest network.
            if [[ "$ifaddr_nw/$ifaddr_prefixlength" == "$svcaddr_nw/$svcaddr_prefixlen" ]]
            then
                if [[ -z "$routeaddr" ]]
                then
                    routeaddr=$ifaddr
                fi
                if [[ "$ifaddr" == "$svcaddr/$svcaddr_prefixlen" && "$ifaddr" != "$routeaddr" ]]
                then
                    NXTSVC=$(echo $svcaddr | awk -F"/" '{print$1}')
                    break
                fi
            fi
        done
        if [[ -n $NXTSVC ]]
        then
            break
        fi
    done
    swaproute=0
    routeaddr=$(echo $routeaddr | awk -F"/" '{print $1}')
    if [[ "$PERSISTENT_IP" == "$routeaddr" ]]
    then
        swaproute=1
    fi
    netstat $netstat_flags | fgrep -w $ifce | while read DEST GW FLAGS REFS USE INTF OTHER; do
        LOOPBACK="::$I"

        case $FLAGS in
        U|UC*)
            # Unless the route is specified as route to a host (H), its a
            # network route in which case DEST is in addr/prefixlen format.
            PERSISTENT_PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT_IP | awk -F"$OP_SEP" '{print $14}')
            PERSISTNET_NET=$(clgetnet $PERSISTENT_IP $PERSISTENT_PREFIXLEN)
            if [[ "$PERSISTNET_NET/$PERSISTENT_PREFIXLEN" == "$DEST" ]]
            then
                # For v6 routes (with flag U|UC*), GW is "link#N". Hence
                # compare the correct link with the gateway.
                ifc_link=$(netstat -in | fgrep -w $ifce | awk '($3 ~ "[Ll]ink") {print $3}')
                if [[ "$ifc_link" == "$GW" ]]
                then
                    # cloned net (network of failing persistentIP)routes
                    # whose GW is failing persistnetIP are stale
                    route delete -inet6 -net $DEST -if $ifce
                fi
            fi
            ;;
        U*S)
            # On auto-configuration of link local address on an interface,
            # routes to "ff02::/16" and "ff12::/16" are automatically configured
            # enabling the link to join respective multicast groups.
            # When an interface, through which the nw traffic for this multicast
            # groups is routed, goes down, the gateway for these routes is
            # updated with link local address of another interface belonging to
            # same HACMP network. In case, there is no alternate link local address
            # available, leave the routing table as is. Failure to comply this
            # behavior causes unreachability to respective networks.

            [[ ($DEST == "ff02::/16" || $DEST == "ff12::/16") && ("$INTF" == "$ifce") ]] && {
                INTF_ON_NET=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
                              grep "$OP_SEP$NET$OP_SEP" | cut -d"$OP_SEP" -f9)
                for intf in $INTF_ON_NET
                do
                    [[ "$intf" != "$ifce" ]] && {
                        stdby_intf=$intf
                    }
                done
                [[ -n $stdby_intf ]] && {
                    configure_linklocal_routes $ifce $stdby_intf
                }
            }
            ;;
        U*W*)
            # all routes created by cloning are evil
            # Do NOT specify gw here. $DEST is the necessary and sufficient arg.
            # as gw could be mac address aswell.
            route delete -inet6 -host $DEST -if $INTERFACE
            ;;
        U*H*)
            # If $DEST is a locally configured address, do
            # nothing with this route since it may interfere
            # with netmon logic.
            typeset -i found=0
            for addr in $LOCADDRS
            do
            if [[ "$addr" == "$DEST" ]]
            then
                found=1
                break
            fi
            done
            if (( $found == 0 ))
            then
            if [[ $(clgetnet $PERSISTENT_IP $PERSISTENT_PREFIXLEN) == $(clgetnet $GW $PERSISTENT_PREFIXLEN) ]]
            then
                # into RR we put the route command:
                if [[ $swaproute == 1 ]]
                then
                    print "cl_route_change -if$PERSISTENT_IP $DEST $LOOPBACK $GW inet6" >>$RR
		    add_rc_check $RR "cl_route_change"
                else
                    print "cl_route_change $DEST $LOOPBACK $GW inet6" >>$RR
		    add_rc_check $RR "cl_route_change"
                fi
                    # which will undo:
                cl_route_change $DEST $GW $LOOPBACK inet6
		RC=$?
		: cl_route_change completed with rc $RC
		[[ $RC != 0 ]] && RC=1
                I=I+1
            fi
            fi
            ;;
        U*)
            PERSISTENT_PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT_IP | awk -F"$OP_SEP" '{print $14}')
            if [[ $(clgetnet $PERSISTENT_IP $PERSISTENT_PREFIXLEN) == $(clgetnet $GW $PERSISTENT_PREFIXLEN) ]]
            then
                # into RR we put the route command:
                if [[ $swaproute == 1 ]]
                then
                    print "cl_route_change -if$PERSISTENT_IP $DEST $LOOPBACK $GW inet6" >>$RR
		    add_rc_check $RR "cl_route_change"
                else
                    print "cl_route_change $DEST $LOOPBACK $GW inet6" >>$RR
		    add_rc_check $RR "cl_route_change"
                fi
                # which will undo:
                cl_route_change $DEST $GW $LOOPBACK inet6
		RC=$?
		: cl_route_change completed with rc $RC
		[[ $? != 0 ]] && RC=1
                I=I+1
            fi
            ;;

        esac

    done

    done
    chmod +x $RR
    return $RC

}

###############################################################################
# Name: delete_bad_default_routes
#
#   Due to an ideocyncracy of AIX's mkdev -l inet0, bogus default routes that
#   are meant to be associated with a persistent address may be installed on
#   an invalid adpater at boot time.  This routine deletes those bogus routes
#   so that once we ifconfig the persistent addresses, and later run mkdev -l inet0
#   we will not have duplicate default routes.
#
# Returns: N/A
###############################################################################
delete_bad_default_routes()
{
    typeset PS4_FUNC="delete_bad_default_routes"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset -i found=0

    # Go through list of all peristent addresses
    for ADDR_INFO in $(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME |\
                         awk -F"$OP_SEP" '$2 == "persistent" {print}')
    do
        # Read the persistent address and its netmask
        print $ADDR_INFO | awk -F"$OP_SEP" '{print $7 " " $14}' \
            | read PERSISTENT NETMASK

        # Get the network portion of the persistent address
        PERSIST_NET=$(clgetnet $PERSISTENT $NETMASK)

	# Get the IP address family of the persistent address
        INET_FAMILY=$(get_inet_family $PERSISTENT)

        # Look for adapters that have a default route, whose gateway address
        # is on the same subnet as the persistent address
        netstat -nrf $INET_FAMILY | grep default | awk '{print $2 " " $6}' |
        while read GATEWAY ADAPTER
        do
            GATE_NET=$(clgetnet $GATEWAY $NETMASK)

            if [[ $PERSIST_NET == $GATE_NET ]]
            then
                # We found an adapter that has a default route whose gateway is on the persistent subnet
                # Now look to see if that adapter has an interface address on the persistent subnet

                # check all addresses on that adapter to see if it has an interface
                # route to the persistent subnet 
                found=0
                for addr in $(netstat -ni | grep $ADAPTER | grep -v "link\#" | awk '{print $4}')
                do
                    ADDR_NET=$(clgetnet $addr $NETMASK)
                    if [[ $ADDR_NET == $PERSIST_NET ]]
                    then
                        found=1
                        break
                    fi
                done

                # if the adpater has a default route through a gateway that is on the
                # persistent subnet, but no interface route to the persistent subnet
                # was found, then the default route is bogus and should be deleted
                if (( $found == 0 ))
                then
                    #
                    : Deleting default route through $GATEWAY from adapter $ADAPTER
                    #
                    route delete 0 $GATEWAY
                fi
            fi
        done
    done
    return 0
}

#####################################################################
# Main starts here.
#####################################################################

PROGNAME=$(basename ${0})

export PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)"
eval export $(cllsparam -x)
[[ "$VERBOSE_LOGGING" == "high" ]] && {
    set -x
    version='1.56.1.4'
}
OP_SEP="$(cl_get_path -S)"


LOCALNODENAME=$(get_local_nodename)
#
# if the cluster is not configured or we cannot otherwise figure
# out what node we are on, exit
#
[[ -z "$LOCALNODENAME" ]] && exit 0

NETWORK=""
ALIVE_IF=""
FAILED_IF=""
FAILED_ADDRESS=""
UPDATE_CLSTRMGR=1
CHECK_HA_ALIVE=1
RESTORE_ROUTES=/usr/es/sbin/cluster/.pers_restore_routes
RC=0
B_FLAG=0

ACTION=$1
shift

set -- $(getopt n:a:f:i:dPB $*)

if (( $? != 0 )) || [[ -z $ACTION ]]; then
    # No arguments passed, just exit.
    exit 1
fi

while [[ $1 != -- ]]; do
    case $1 in
	-n) # Network name
	    NETWORK=$2
	    shift; shift
	;;
	-a) # Alive interface
	    ALIVE_IF=$2
	    shift; shift
	;;
	-f) # Failed interface
	    FAILED_IF=$2
	    shift; shift
	;;
	-i) # IP address of failed boot interface.
	    # For "fail_boot" action only.
	    FAILED_ADDRESS=$2
	    shift; shift
	;;
	-d) # do not check if the clstrmgr is running - this is used
	    # by rc.cluster, harc.net 
	    CHECK_HA_ALIVE=0

	    # the resource distribution preference will not be exercised 
	    # in this case either (ha is down so no service labels should
	    # be active) so we set the preference override here
	    export INVOCATION_FLAG=USER_REQUESTED
	    shift
	;;
        -P) # Do not update the cluster manager about the persistent movement
            # Used by cldare.
            UPDATE_CLSTRMGR=0
            shift
        ;;
        -B) # This command is exected at boot time by harc.net
            # delete_bad_default_routes will be executed.
            B_FLAG=1
            shift
        ;;
    esac
done

shift # Get rid of trailing --

# For acquiring or releasing a service address on a boot interface.
# Called from cl_swap_IP_address
if [[ $ACTION == "up" ]]; then
    if [[ -z $ALIVE_IF ]] || [[ -z $NETWORK ]]; then
	exit 1
    fi

    PERSISTENT=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
	           awk -F"$OP_SEP" '$2 == "persistent" && $3 == "'$NETWORK'" {print $1}')
    if [[ -z $PERSISTENT ]]; then
	# No persistent label defined for this network on this node.
	exit 0
    fi

    FOUND_IF=$(LC_ALL=C clgetif -a $PERSISTENT 2>/dev/null | awk '{print $1}')
    if [[ $FOUND_IF != "" ]]; then
	# For IP aliasing networks:
	# Since IP aliasing networks have mulitiple boot interfaces,
	# the persistent label might be up on another boot interface.
	#
	# For non-IP aliasing networks:
	# This call could be during the acquiring of a service
	# address from a cascading resource group onto a standby interface.
	# In that case the persistent label would already be configured
	# on the service/boot interface on the local network.
	#
	# In either case, re-alias the persistent label onto the interface
	# that is currently on to make sure the routes are correct and to
	# send out a gratuitous ARP response.
	#
	# Note that since this path simply ifconfigs the persistent on the
	# same interface we assume that the resource distribution preference has
	# already been exercised and skip any processing here.
	NETMASK=$(getNetmask $FOUND_IF)
	
	#IPv6 persistent IP labels will have its own prefix length, 
	#so, get the prefix length from HACMP configuration.  
	PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT | awk -F"$OP_SEP" '{print $14}')
	INET_FAMILY=$(get_inet_family $PERSISTENT)
                
	   if [[ "$INET_FAMILY" == "inet6" ]]
	   then 
               # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
               # if the interface is not having any LL address then run autoconf6 on the same interface.
               # Note: All the link-local addresses starts with "fe80::"
               LL_ADDR=$(ifconfig $FOUND_IF inet6 | awk '($2 ~ /^fe80::*/){print $2}')
               if [[ -z "$LL_ADDR" ]]
               then
                   autoconf6 -i $FOUND_IF
               fi
               ifconfig $FOUND_IF inet6 alias $PERSISTENT/$PREFIXLEN up
	   else
               ifconfig $FOUND_IF alias $PERSISTENT netmask $NETMASK up
           fi     
	
	check_alias_status $FOUND_IF $PERSISTENT "acquire"
	if (( $? != 0 )); then
	    # Failed to ifconfig up the alias.  A message will be printed
	    # from check_alias_status, so just exit here.
	    exit 1
	fi
	exit 0
    fi

    # This path is called from cl_swap_IP_address and simply ifconfigs up 
    # on the address passed in - we do not need to exercise the resource 
    # distribution preference here because the caller of swap should have done
    # so already

    NETMASK=$(getNetmask $ALIVE_IF)
    # IPv6 persistent IP labels will have its own prefix length,
    #so, get the prefix length from HACMP configuration.
    PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT | awk -F"$OP_SEP" '{print $14}')
    INET_FAMILY=$(get_inet_family $PERSISTENT)

       if [[ "$INET_FAMILY" == "inet6" ]] 
       then  
           # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
           # if the interface is not having any LL address then run autoconf6 on the same interface.
           # Note: All the link-local addresses starts with "fe80::"
           LL_ADDR=$(ifconfig $ALIVE_IF inet6 | awk '($2 ~ /^fe80::*/){print $2}')
           if [[ -z "$LL_ADDR" ]]
           then
               autoconf6 -i $ALIVE_IF
           fi
           ifconfig $ALIVE_IF inet6 alias $PERSISTENT/$PREFIXLEN up 2>/dev/null
       else
           ifconfig $ALIVE_IF alias $PERSISTENT netmask $NETMASK up 2>/dev/null
       fi    

    check_alias_status $ALIVE_IF $PERSISTENT "acquire"
    if (( $? != 0 )); then
	# Failed to ifconfig up the alias.  A message will be
	# printed from check_alias_status, so just exit here.
	exit 1
    fi
    exit 0

# For swapping a boot or service address to a standby interface.
# Called from cl_swap_IP_address/cl_swap_IPv6_address
elif [[ $ACTION == "swap" ]]; then
    if [[ -z $ALIVE_IF ]] || [[ -z $FAILED_IF ]] || [[ -z $NETWORK ]]
    then
	exit 1
    fi

    PERSISTENT=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
	           awk -F"$OP_SEP" '$2 == "persistent" && $3 == "'$NETWORK'" {print $1}')
    if [[ -z $PERSISTENT ]]; then
	# No persistent label defined for this network on this node.
	exit 0
    fi

    NETMASK=$(getNetmask $ALIVE_IF)
 
    #IPv6 persistent IP labels will have its own prefix length, 
    #so, get the prefix length from HACMP configuration.  
    PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT | awk -F"$OP_SEP" '{print $14}')
    INET_FAMILY=$(get_inet_family $PERSISTENT)
     ALIAS_PREF=$(odmget -q "function = shared AND identifier = $PERSISTENT" HACMPadapter | grep "max_aliases" | awk '{print$3}')
 
    # Note: aliasing networks are in HAES only, but this logic will
    # also work in HAS and fall-through correctly.
    if [[ $(isAliasingNetwork $NETWORK) == "1" ]]; then
	FOUND_IF=$(LC_ALL=C clgetif -a $PERSISTENT 2>/dev/null | awk '{print $1}')
	if [[ -n $FOUND_IF ]] && [[ $FOUND_IF != $FAILED_IF ]]; then
	    # Since IP aliasing networks have mulitiple boot interfaces,
	    # the persistent label might be up on another boot interface.
	    # If that's the case then exit now so we don't alias the same
	    # persistent label onto this interface, and thus have the
	    # persistent label aliased onto two different interfaces.
	    exit 0
	fi
    fi

    # If this is not a user requested operation, find the best interface to 
    # host the persistent based on the resource distribution preference
    if [[ (${INVOCATION_FLAG:-0} == 0) || ($INVOCATION_FLAG != "USER_REQUESTED") ]]
    then
	# make sure network is aliasing
        if [[ $(isAliasingNetwork $NETWORK) == "1" ]]
        then
    	    ALIVE_ADDR=$(best_boot_addr $NETWORK $(getAliveBootsServices $NETWORK))
    	    ALIVE_IF=$(clgetif -a $ALIVE_ADDR 2>/dev/null | awk '{print $1}') 	# convert addr to if
	fi
    fi

    typeset FIRST_ALIAS=""
    if [[ "$ALIAS_PREF" == "259" ]]
    then
	     FIRST_ALIAS="firstalias"
    fi

    if [[ "$INET_FAMILY" == "inet" ]]
    then
	    if [[ "$FAILED_IF" != "$ALIVE_IF" ]]
	    then
		    ifconfig $FAILED_IF $PERSISTENT transfer $ALIVE_IF $FIRST_ALIAS
	    else
		    ifconfig $ALIVE_IF alias $PERSISTENT netmask $NETMASK $FIRST_ALIAS
	    fi
    	    check_alias_status $FAILED_IF $PERSISTENT "release"
	    check_alias_status $ALIVE_IF $PERSISTENT "acquire"
    	    if (( $? != 0 )); then
		exit 1
    	    fi
	    exit 0
    else
	    alias_replace_ipv6_routes $RESTORE_ROUTES $FAILED_IF
    	    RC=$?
            : Completed alias_replace_routes with return code $RC
    fi

    
    if [[ "$FAILED_IF" != "$ALIVE_IF" ]]; then
    	   if [[ "$INET_FAMILY" == "inet6" ]] 
           then  
    		   ifconfig $FAILED_IF inet6 delete $PERSISTENT
    	   else
    	       ifconfig $FAILED_IF delete $PERSISTENT
    	   fi
    	
    	check_alias_status $FAILED_IF $PERSISTENT "release"
    	if [[ $? != 0 || $RC != 0 ]]; then
		# Failed to ifconfig delete the alias.  A message will be
		# printed from check_alias_status, so just exit here.
		$RESTORE_ROUTES
		: Completed $RESTORE_ROUTES with return code $?.
		exit 1
    	fi
    fi

        if [[ "$INET_FAMILY" == "inet6" ]] 
        then      
            # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
            # if the interface is not having any LL address then run autoconf6 on the same interface.
            # Note: All the link-local addresses starts with "fe80::"
            LL_ADDR=$(ifconfig $ALIVE_IF inet6 | awk '($2 ~ /^fe80::*/){print $2}')
            if [[ -z "$LL_ADDR" ]]
            then
                autoconf6 -i $ALIVE_IF
            fi
            ifconfig $ALIVE_IF inet6 alias $PERSISTENT/$PREFIXLEN up 
        else    
            ifconfig $ALIVE_IF alias $PERSISTENT netmask $NETMASK up 
        fi

    if [[ (${INVOCATION_FLAG:-0} != 0) && ($INVOCATION_FLAG == "USER_REQUESTED") ]]
    then
	if [[ -n $NXTSVC && $swaproute == 1 ]]
	then
	#IPv6 persistent IP labels will have its own prefix length, 
        #so, get the prefix length from HACMP configuration.  
        PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $NXTSVC | awk -F"$OP_SEP" '{print $14}')
        INET_FAMILY=$(get_inet_family $NXTSVC)
        if [[ "$INET_FAMILY" == "inet6" ]] 
        then  
            # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
            # if the interface is not having any LL address then run autoconf6 on the same interface.
            # Note: All the link-local addresses starts with "fe80::"
            LL_ADDR=$(ifconfig $FAILED_IF inet6 | awk '($2 ~ /^fe80::*/){print $2}')
            if [[ -z "$LL_ADDR" ]]
            then
                autoconf6 -i $FAILED_IF
            fi
	    ifconfig $FAILED_IF inet6 alias $NXTSVC/$PREFIXLEN 
        else
	    ifconfig $FAILED_IF alias $NXTSVC netmask $NETMASK
	fi
	fi
    fi
    $RESTORE_ROUTES
    RC=$?
    : $RESTORE_ROUTES completed with code $RC
    [[ $RC != 0 ]] && exit 1
    
    check_alias_status $ALIVE_IF $PERSISTENT "acquire"
    if (( $? != 0 )); then
	# Failed to ifconfig up the alias.  A message will be
	# printed from check_alias_status, so just exit here.
	exit 1
    fi
    exit 0

# For moving a persistent label to another alive boot interface when a boot
# interface without a service alias on an IP-aliasing network fails.
# This is for HAES only, as HAS doesn't have IP-aliasing networks.
elif [[ $ACTION == "fail_boot" ]]; then
    if [[ -z $FAILED_ADDRESS ]] || [[ -z $NETWORK ]]; then
	exit 1
    fi

    IF=$(LC_ALL=C clgetif -a $FAILED_ADDRESS 2>/dev/null | awk '{print $1}')
    NETWORK=$(cllsif -J "$OP_SEP" -Sn $FAILED_ADDRESS | cut -d"$OP_SEP" -f3)

    # Note: aliasing networks are in HAES only, but this logic will
    # also work in HAS and fall-through correctly.
    if [[ $(isAliasingNetwork $NETWORK) != "1" ]]; then
	# The "fail_boot" action is only for IP aliasing networks.
	exit 1
    fi

    PERSISTENT=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
	           awk -F"$OP_SEP" '$2 == "persistent" && $3 == "'$NETWORK'" {print $1}')
    if [[ -z $PERSISTENT ]]; then
	# No persistent label defined for this network on this node.
	exit 0
    fi

    ALIAS_PREF=$(odmget -q "function = shared AND identifier = $PERSISTENT" HACMPadapter | grep "max_aliases" | awk '{print$3}')
    PERSISTENT_IF=$(LC_ALL=C clgetif -a $PERSISTENT 2>/dev/null | awk '{print $1}')

    if [[ $PERSISTENT_IF != "" ]]; then
        if [[ $PERSISTENT_IF != $IF ]]
        then
            # This persistent label is already up on another boot interface
            # on the local network.
            exit 0
        fi
    fi

    IF2=""
    LABEL=""

    # find a candidate interface from amongst all up interfaces
    for LABEL in $(getAliveBootsServices $NETWORK); do
	IF2=$(LC_ALL=C clgetif -a $LABEL 2>/dev/null | awk '{print $1}')
	if [[ -z $IF2 ]] || [[ $IF2 == $PERSISTENT_IF ]]; then
	    # Couldn't find interface for $LABEL, or found same
	    # interface that just failed.
	    IF2=""
	    LABEL=""
	    continue
	fi
	# We found the interface to alias the persistent label
	# onto, so break out of the searching loop.
	break
    done

    if [[ -z $IF2 ]]; then
	: There is no other alive boot interface on this network on the
	: local node, so do not move the persistent label anywhere.
	exit 0
    fi

    # If this is a fail_interface event which has come after swap_adapter,
    # swap_adapter will have already exercised the resource distribution preference
    # and we would have taken one of the early returns above (already up or none
    # available). If here, the event is for an interface that did not have a 
    # service on it and we may want to exercise the distribution preference in 
    # selecting where the persistent should go
    if [[ (${INVOCATION_FLAG:-0} == 0) || ($INVOCATION_FLAG != "USER_REQUESTED") ]]
    then
	# network is aliasing (checked above) - set ALIVE_IF for use by best_boot_addr
	ALIVE_IF=$IF2
    	ALIVE_ADDR=$(best_boot_addr $NETWORK $(getAliveBootsServices $NETWORK))
    	IF2=$(clgetif -a $ALIVE_ADDR 2>/dev/null | awk '{print $1}') 	# convert addr to if
    fi

    NETMASK=$(getNetmask $IF2)
    #IPv6 persistent IP labels will have its own prefix length, 
    #so, get the prefix length from HACMP configuration.  
    PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT | awk -F"$OP_SEP" '{print $14}')
    INET_FAMILY=$(get_inet_family $PERSISTENT)
    if [[ "$INET_FAMILY" == "inet" ]]
    then
    	typeset FIRST_ALIAS=""
    	if [[ "$ALIAS_PREF" == "259" ]]
    	then
	     FIRST_ALIAS="firstalias"
    	fi

	if [[ -z $IF ]]; then
	    : The boot interface has failed and not available for ifconfig operations.

		ifconfig $IF2 alias $PERSISTENT netmask $NETMASK up $FIRST_ALIAS
	else
		ifconfig $IF $PERSISTENT transfer $IF2 $FIRST_ALIAS

    		check_alias_status $IF $PERSISTENT "release"
	fi

	check_alias_status $IF2 $PERSISTENT "acquire"
	if (( $? != 0 )); then
		exit 1
	fi
	exit 0
    fi
    if [[ "$INET_FAMILY" == "inet6" ]]
    then
        alias_replace_ipv6_routes $RESTORE_ROUTES $IF
    else
        alias_replace_routes $RESTORE_ROUTES $IF
    fi
    RC=$?
    : alias_replace_routes completed with code $RC
    (( $RC != 0 )) && exit 1

      if [[ $PERSISTENT_IF == $IF ]]; then
          if [[ "$INET_FAMILY" == "inet6" ]] 
          then  
              ifconfig $IF inet6 delete $PERSISTENT
          else
              ifconfig $IF delete $PERSISTENT
          fi
          check_alias_status $IF $PERSISTENT "release"
          if (( $? != 0 )); then
          	# Failed to ifconfig delete the alias.  A message will be
          	# printed from check_alias_status, so just exit here.
    		: alias_replace_routes completed with code $RC
            	$RESTORE_ROUTES
    		RC=$?
    		: $RESTORE_ROUTES completed with code $RC
            exit 1
          fi
      fi

        if [[ "$INET_FAMILY" == "inet6" ]] 
        then  
            # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
            # if the interface is not having any LL address then run autoconf6 on the same interface.
            # Note: All the link-local addresses starts with "fe80::"
            LL_ADDR=$(ifconfig $IF2 inet6 | awk '($2 ~ /^fe80::*/){print $2}')
            if [[ -z "$LL_ADDR" ]]
            then
                autoconf6 -i $IF2
            fi
            ifconfig $IF2 inet6 alias $PERSISTENT/$PREFIXLEN up 
        else
            ifconfig $IF2 alias $PERSISTENT netmask $NETMASK up 
        fi

    check_alias_status $IF2 $PERSISTENT "acquire"
    if (( $? != 0 )); then
	# Failed to ifconfig up the alias.  A message will be
	# printed from check_alias_status, so just exit here.
	$RESTORE_ROUTES
	: Completed $RESTORE_ROUTES with return code $?.
	exit 1
    fi
    $RESTORE_ROUTES
    RC=$?
    : Completed $RESTORE_ROUTES with return code $RC
    flush_arp
    : Completed flush_arp with return code $?.
    exit $RC

# For configuring a persistent label onto a boot interface that caused
# a network_up event.
# This is for HAES only, as HAS doesn't have IP-aliasing networks.
elif [[ $ACTION == "aliasing_network_up" ]]; then
    if [[ -z $NETWORK ]]; then
	exit 1
    fi

    # Note: aliasing networks are in HAES only, but this logic will
    # also work in HAS and fall-through correctly.
    if [[ $(isAliasingNetwork $NETWORK) != "1" ]]; then
	# The "aliasing_network_up" action is only for IP aliasing networks.
	exit 1
    fi

    PERSISTENT=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
	           awk -F"$OP_SEP" '$2 == "persistent" && $3 == "'$NETWORK'" {print $1}')
    if [[ -z $PERSISTENT ]]; then
	# No persistent label defined for this network on this node.
	exit 0
    fi

    PERSISTENT_IF=$(LC_ALL=C clgetif -a $PERSISTENT 2>/dev/null | awk '{print $1}')

    # If the persistent label is already configured on another boot
    # interface on the local network, then we need to determine if
    # that boot interface is alive.  If it is, then we exit and do
    # not move the persistent label anywhere.  If it is not alive,
    # then we delete the persistent label from that interface and
    # re-alias it onto an alive interface that we will find.
    IF=""
    LABEL=""
    IF_SAVE=""

    for LABEL in $(getAliveBootsServices $NETWORK); do
	IF=$(LC_ALL=C clgetif -a $LABEL 2>/dev/null | awk '{print $1}')
	if [[ -z $IF ]]; then
	    # Couldn't find interface for $LABEL.
	    IF=""
	    LABEL=""
	    continue
	fi

	if [[ $PERSISTENT_IF == $IF ]]; then
	    # The persistent label is already aliased onto the alive boot
	    # interface that we found, so don't re-alias it.
	    exit 0
	fi

	# We found the interface to alias the persistent label
	# onto, so save it.

	if [[ -z $IF_SAVE ]]; then
	    IF_SAVE=$IF
	fi

    done

    if [[ -z $IF_SAVE ]]; then
	# There is no other alive boot interface on this network on the
	# local node, so do not move the persistent label anywhere.
	exit 0
    fi
    IF=$IF_SAVE

    # If here we are ready to move the persistent but we dont need to check
    # the resource distribution preference: the network_down event which preceeded
    # this join will have caused all the services to be released. If the
    # user selected a fallover preference of "notify", then nothing should have
    # moved and all the labels should already be in the right place.
    # So there is nothing to do here: the preference will be exercised if and
    # when any services are subsequently acquired.

    NETMASK=$(getNetmask $IF)

    #IPv6 persistent IP labels will have its own prefix length, 
    #so, get the prefix length from HACMP configuration.  
    PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $PERSISTENT | awk -F"$OP_SEP" '{print $14}')
    INET_FAMILY=$(get_inet_family $PERSISTENT)
    ALIAS_PREF=$(odmget -q "function = shared AND identifier = $PERSISTENT" HACMPadapter | grep "max_aliases" | awk '{print$3}')

    if [[ $PERSISTENT_IF != "" ]]
    then
      if [[ "$INET_FAMILY" == "inet" ]]
      then
    	typeset FIRST_ALIAS=""
    	if [[ "$ALIAS_PREF" == "259" ]]
    	then
	     FIRST_ALIAS="firstalias"
    	fi

	ifconfig $PERSISTENT_IF $PERSISTENT transfer $IF $FIRST_ALIAS

    	check_alias_status $PERSISTENT_IF $PERSISTENT "release"
	check_alias_status $IF $PERSISTENT "acquire"
    	    if [[ $? != 0 ]]; then
		exit 1
    	    fi
	    exit 0
      fi
        if [[ "$INET_FAMILY" == "inet6" ]]
        then
            alias_replace_ipv6_routes $RESTORE_ROUTES $PERSISTENT_IF
        else
            alias_replace_routes $RESTORE_ROUTES $PERSISTENT_IF
        fi
	RC=$?
	: alias_replace_routes completed with code $RC
	    
            if [[ "$INET_FAMILY" == "inet6" ]]
            then 
                ifconfig $PERSISTENT_IF inet6 delete $PERSISTENT
            else
                ifconfig $PERSISTENT_IF delete $PERSISTENT
            fi
	check_alias_status $PERSISTENT_IF $PERSISTENT "release"
	if [[ $? != 0 || $RC != 0 ]]; then
	    # Failed to ifconfig delete the alias.  A message will be
	    # printed from check_alias_status, so just exit here.
	    $RESTORE_ROUTES
	    : Completed $RESTORE_ROUTES with return code $?.
	    exit 1
	fi
    fi

       if [[ "$INET_FAMILY" == "inet6" ]] 
       then	   
           # Before aliasing the address, Check the IPv6 Link-local address configuration on the interface
           # if the interface is not having any LL address then run autoconf6 on the same interface.
           # Note: All the link-local addresses starts with "fe80::"
           LL_ADDR=$(ifconfig $IF inet6 | awk '($2 ~ /^fe80::*/){print $2}')
           if [[ -z "$LL_ADDR" ]]
           then
               autoconf6 -i $IF
           fi
    	   ifconfig $IF inet6 alias $PERSISTENT/$PREFIXLEN up 
       else
           ifconfig $IF alias $PERSISTENT netmask $NETMASK up 
       fi

    RC=0
    [[ $PERSISTENT_IF != "" ]] && {
	$RESTORE_ROUTES
	RC=$?
        : Completed $RESTORE_ROUTES with return code $RC
    }

    check_alias_status $IF $PERSISTENT "acquire"
    if [[ $? != 0 || $RC != 0 ]]; then
	# Failed to ifconfig up the alias.  A message will be
	# printed from check_alias_status, so just exit here.
	exit 1
    fi
    exit 0

# For configuring all persistent labels onto appropriate interfaces.
elif [[ $ACTION == "config_all" ]]; then
    configAll
    exit 0
fi
