#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG
#  This is an automatically generated prolog.
#
#  Copyright (C) Altran ACT S.A.S. 2017,2018,2019,2021.  All rights reserved.
#
#  ALTRAN_PROLOG_END_TAG
#
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r714 src/43haes/usr/sbin/cluster/events/utils/cl_swap_IPv6_address.sh 1.9.1.2 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2008,2013 
# 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 
# @(#)  20c8e9d 43haes/usr/sbin/cluster/events/utils/cl_swap_IPv6_address.sh, 726, 2147A_aha726, Oct 30 2021 04:20 PM

###############################################################################
#
#   COMPONENT_NAME: EVENTUTILS
#
#   FUNCTIONS: flush_ndp_cache
#              configure_linklocal_routes
#              get_standby_for_service
#              check_ifconfig_status
#	           check_alias_status
#              alias_replace_route
#
###############################################################################

###############################################################################
#
#  Name:  cl_swap_IPv6_address
#
#  This script is used to handle IPv6 service IP labels/addresses, adapter swap and IP address takeover.
#  The first form, the specified interface is set from the old address
#  to the new address
#       cl_swap_IPv6_address cascading/rotating acquire/release interface \
#                new_address old_address
#       i.e cl_swap_IPv6_address cascading acquire en0 2001::1 1.1.1.1
#
#  The second form sets two interfaces in a single call. This is sometimes
#  necessary due to AIX routing quirks where an existing route gets 
#  spuriously deleted. An example where this is required is the case of 
#  swapping two interfaces.
#       cl_swap_IP_address swap_adapter swap \
#                interface1 address1 interface2 address2 
#       i.e cl_swap_IPv6_address swap_adapter swap \
#                en0 2001::1 en1 2.2.2.2
#
# Returns:      0 - success
#               1 - ifconfig failure
#               2 - bad number of arguments
#               3 - Hardware swap failure
# Environment:  VERBOSE_LOGGING,PATH
###############################################################################
###############################################################################
# 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: 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: get_standby_for_service
#
# This routines returns a standby address to be placed on the adapter
# where a takeover service is being released. This is not a simple lookup:
# because of all the potential combinations of service and standby swaps,
# we rely on rsct to tell us which standby it thinks should be put back
# on the adapter.
# This logic used to be in release_takeover_addr but has been moved here to
# account for the new "monitoirng of takeover service labels" function.
#
# Arguments: 
#	Interface currently holding the takeover service
#	IP address of the takeover service
#
# Returns: 
#	IP address of the standby
#
###############################################################################
get_standby_for_service () {
    typeset PS4_FUNC="get_standby_for_service"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    CH_INTERFACE=$1
    CH_ADDRESS=$2
    STBY_IP_ADDR=""

    NETWORK=$(cllsif -J "$OP_SEP" -Sn $CH_ADDRESS | cut -d"$OP_SEP" -f3 | uniq)
    NET_TYPE=$(cllsif -J "$OP_SEP" -Sn $CH_ADDRESS | cut -d"$OP_SEP" -f4 | uniq)
    IF_ALIAS=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | grep "${OP_SEP}$NETWORK${OP_SEP}" | \
                grep "${OP_SEP}$CH_INTERFACE${OP_SEP}" | cut -d"$OP_SEP" -f12)

    # if this network is using hb via aliasing, simply lookup
    # the interface from odm
    if [[ -n "$IF_ALIAS" ]]; then
 	STBY_IP_ADDR=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | \
 	              grep "${OP_SEP}$NETWORK${OP_SEP}" | grep \
 	              "${OP_SEP}$CH_INTERFACE${OP_SEP}" | cut -d"$OP_SEP" -f7)
        echo "$STBY_IP_ADDR"
        return
    fi

    echo "$STBY_IP_ADDR"
    return
}



###############################################################################
# Name: check_ifconfig_status
#
# This modification has been made because of change of behavior
# of 'ifconfig' on AIX 4.1. If we want to add a route which is
# already in the routing table, 'ifconfig' DOES change the
# address on the adapter BUT the return code IS 1 (error). The
# error is accompanied with a message :
#
# "ifconfig: ioctl (SIOCAIFADDR): Do not specify an existing file."
#
# Since the adapter does get the new address, we do a 'netstat' on
# that adapter and get the current address. If the current address
# is the same as the address that we want to put on the adapter,
# then everything is fine. Otherwise, we give an error.
#
# Arguments: 
#	Interface to check
#	IP address in dotted-decimal format
#	Netmask in dotted-decimal format
#
# Returns: 
#	0 Interface has a proper entry
#	1 Interface does not have a proper entry
#
###############################################################################
check_ifconfig_status () {

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

    CH_INTERFACE=$1
    CH_ADDRESS=$2
    CH_NETMASK=$3

    CUR_ADDR=$(clifconfig $CH_INTERFACE | (read ; read a b c ; print $b))
    [[ "$CUR_ADDR" != "$CH_ADDRESS" ]] && {
        cl_log 59 "$PROGNAME: Failed ifconfig $CH_INTERFACE inet $CH_ADDRESS netmask $CH_NETMASK up." $PROGNAME $CH_INTERFACE $CH_ADDRESS $CH_NETMASK
        return 1
    }
    return 0	
}

# IP_ALIASING_SUPPORT
###############################################################################
# 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
#   Netmask in dotted-decimal format
#
# 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_ADDRESS=$2
    CH_ACQ_OR_RLSE=$3

    
    CUR_ADDR=$(clifconfig $CH_INTERFACE inet6 | fgrep -w $CH_ADDRESS | awk -F"/| " '{print $2}')
    
    if [[ "$CH_ACQ_OR_RLSE" == "acquire" ]]
    then

        # if acquiring, make sure the alias IS on the interface
        [[ "$CUR_ADDR" != "$CH_ADDRESS" ]] && {
            cl_log 7324 "$PROGNAME: Failed to ifconfig alias $CH_ADDRESS on interface $CH_INTERFACE" $PROGNAME $CH_ADDRESS $CH_INTERFACE
            return 1
        }
    else
        # if releasing, make sure the alias IS NOT on the interface
        [[ "$CUR_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: 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 makes use of following variables, global or set in main routine
#       LOCALNODENAME, NET, NETMASK, ADDR1, INVOCATION_FLAG, PERSISTENT,
#	ACQ_OR_RLSE
#
# Returns: Any error from cl_route_change, otherwise 0
###############################################################################
alias_replace_routes() {

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

    RR=$1
    shift
    interfaces="$*"
    RC=0

    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 ~ ":" && $3 !~ "Network" {print $3}')

    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

    for ifce in $interfaces ; do
	integer I=1
	NXTSVC=""
    IFADDRS=$(ifconfig $ifce | grep "inet6" | awk  '{print $2}') 
    IFADDRS_CNT=$(netstat -rnf inet6 | awk '($6 == "$ifce") {print $1}' | wc -l)
	SVCADDRS=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
	           grep "$OP_SEP$NET$OP_SEP" | grep -E "${OP_SEP}service${OP_SEP}" |\
	           cut -d"$OP_SEP" -f7 |  sort -u)
    	PERSISTENT_IP=$(cllsif -J "$OP_SEP" -Spi $LOCALNODENAME | \
	              grep "$OP_SEP$NET$OP_SEP" | \
	              grep -E "${OP_SEP}persistent${OP_SEP}" | cut -d"$OP_SEP" -f7)

    ADDR1_PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $ADDR1 | awk -F"$OP_SEP" '{print $14}')
	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" == "$svcaddr/$svcaddr_prefixlen" ]]
		    then
		        if [[ -z "$routeaddr" ]]
		        then
			        routeaddr=$(echo $ifaddr | awk -F"/" '{print $1}')
		        fi
		        if [[ "$ifaddr" == "$svcaddr/$svcaddr_prefixlen" && 
                              "$ifaddr" != "$ADDR1/$ADDR1_PREFIXLEN" && 
                              ("$ADDR1" != "$PERSISTENT_IP" || 
                               ( ${INVOCATION_FLAG:-0} != 0 && 
                                 $INVOCATION_FLAG == "USER_REQUESTED" && 
                                 "$ADDR1" == "$PERSISTENT_IP")) ]]
		        then
			        NXTSVC=$(echo $svcaddr)
			        break
		        fi
		    fi
 	    done
	    if [[ -n $NXTSVC ]]
	    then
		    break
	    fi
	done

	swaproute=0
    NETSTAT_FLAGS="-nrf inet6"

	if [[ "$ADDR1" == "$routeaddr" ]]
	then
	    # swapping addr has net route
	    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.
		    
		    ADDR1_PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $ADDR1 | awk -F"$OP_SEP" '{print $14}')
	        ADDR1_NET=$(clgetnet $ADDR1 $ADDR1_PREFIXLEN)
		    if [[ "$ADDR1_NET/$ADDR1_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
		            if [[ ($PERSISTENT != "" || "$ifc_link" == "$GW") || 
                                  ( ${INVOCATION_FLAG:-0} == 0 || 
                                    $INVOCATION_FLAG != "USER_REQUESTED") ]]
		            then
			            # cloned net (network of failing service IP)routes
			            # whose GW is failing serviceIP are stale
			            route delete -inet6 -net $DEST -if $ifce
			        fi
			    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 $ifce
		    ;;
		U*H*)
		    # If $DEST is a locally configured address, do
		    # nothing with this route since it may interfere
		    # with netmon logic.
		    found=0
		    for addr in $LOCADDRS
		    do
		        if [[ "$addr" == "$DEST" ]]
		        then
		            found=1
		            break
		        fi
		    done
		    if [[ $found == 0 ]]
		    then
		        if [[ "$(clgetnet $ADDR1 $ADDR1_PREFIXLEN)" == \
                              "$(clgetnet $GW $ADDR1_PREFIXLEN)" ]]
		        then
		            if [[ (${INVOCATION_FLAG:-0} == 0 || 
                                   $INVOCATION_FLAG != "USER_REQUESTED") || 
                                  $swaproute == 1 ]]
		            then
		                # into RR we put the route command:
		                if [[ -z $ACQ_OR_RLSE || "$routeaddr" == "$PERSISTENT_IP" ]]
		                then
		                    print "cl_route_change -if$routeaddr $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
		                I=I+1
		            fi
		        fi
		    fi
		    ;;

		U*)
		    ADDR1_PREFIXLEN=$(cllsif -J "$OP_SEP" -Sn $ADDR1 | awk -F"$OP_SEP" '{print $14}')
		    if [[ "$(clgetnet $ADDR1 $ADDR1_PREFIXLEN)" == "$(clgetnet $GW $ADDR1_PREFIXLEN)" ]]
		    then
		        [[ (${INVOCATION_FLAG:-0} == 0) || ($INVOCATION_FLAG != "USER_REQUESTED") || $swaproute == 1 ]] && {

		            if [[ -z $ACQ_OR_RLSE || "$routeaddr" == "$PERSISTENT_IP" ]]
		            then
		               print "cl_route_change -if$routeaddr $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
		            I=I+1
		        }
		    fi
		    ;;
	    esac
	done
    done

    chmod +x $RR
    return $RC
}
###############################################################################
# Name: disable_pmtu_gated
#
#  Disable PMTU discovery and the gated daemon temporarily.
#  Global variables DISABLE_TCP_PMTU, DISABLE_UDP_PMTU and DISABLE_GATED
#  are set to retain current values.
#
# Arguments: 0
#
# Returns: N/A
###############################################################################
disable_pmtu_gated()
{
	typeset PS4_FUNC="disable_pmtu_gated"
	DISABLE_TCP_PMTU=0
	DISABLE_UDP_PMTU=0
	DISABLE_TCP_PMTU=$(no -o tcp_pmtu_discover | cut -f3,3 -d" ")
	DISABLE_UDP_PMTU=$(no -o udp_pmtu_discover | cut -f3,3 -d" ")
	no -o tcp_pmtu_discover=0
	no -o udp_pmtu_discover=0

	# Note that running gated is not presently supported by HACMP.
	# The user may experience side effects if gated is not implemented
	# properly.  HACMP does at least attempt to stop gated:

	ps -eo "pid,comm" | grep -w gated 2> /dev/null
	DISABLE_GATED=$?

	if [ $DISABLE_GATED == 0 ]
	then

    # This loop waits for gated to exit before continuing on.
    # The counter is set to 10 which means we will loop for
    # a maximum of 10 seconds before continuing on.  This
    # counter can be increased however if it is increased
    # it might be wise to also increase the nim grace period
    # to prevent false fail_adapter events from occuring.

	typeset -i GATED_COUNT=10;
	/usr/bin/stopsrc -s gated 2> /dev/null
	while (( GATED_COUNT > 0 ))
	do
		ps -eo "pid,comm" | grep -w gated 2> /dev/null
		if (( $? == 1 ))
		then
		break;
		fi
		(( GATED_COUNT-- ))
		sleep 1
	done
	fi

	return 0
}
###############################################################################
# Name: enable_pmtu_gated
#
#  Reenable PMTU discovery and restart gated daemon.
#  Global variables DISABLE_TCP_PMTU, DISABLE_UDP_PMTU and DISABLE_GATED
#  hold values previously set in the disable_pmtu_gated subroutine.
#
# Arguments: 0
#
# Returns: N/A
###############################################################################
enable_pmtu_gated()
{
	typeset PS4_FUNC="enable_pmtu_gated"
	# if PMTU discovery was disabled, then reenable it.

	no -o tcp_pmtu_discover=$DISABLE_TCP_PMTU
	no -o udp_pmtu_discover=$DISABLE_UDP_PMTU

	# if gated was on when we entered this script, start it back

        [[ $DISABLE_GATED == 0 ]] &&
        {
            startsrc -s gated;
            sleep 5;
	}

	return 0
}

restore_ipignoreredirects()
{
	typeset PS4_FUNC="restore_ipignoreredirects"
	/usr/sbin/no -o ipignoreredirects=$PRIOR_IPIGNORE_REDIRECTS_VALUE
}

set_ipignoreredirects()
{
	typeset PS4_FUNC="set_ipignoreredirects"
	PRIOR_IPIGNORE_REDIRECTS_VALUE=$(no -a | grep ipignoreredirects | awk '{ print $3 }')
	/usr/sbin/no -o ipignoreredirects=1
}

###############################################################################
#
# Name: non_alias
#
# Arguments: ip address
#
# Returns: 1 if non-alias address, 0 if alias address
#
###############################################################################
non_alias() {
   typeset PS4_FUNC="non_alias"

   typeset addr="$1"

   typeset net=$(cllsif -J "$OP_SEP" -Sw -n $addr | cut -f3 -d"$OP_SEP")
   typeset alias=$(cllsnw -J "$OP_SEP" -Sw -n $net | cut -f3 -d"$OP_SEP")

   if [[ "$alias" == "true" ]] ; then
      return 0
   else
      return 1
   fi

}


###############################################################################
# Name: get_MTU
#
#       Gets the MTU size from netstat for the specified interface.
#
# Arguments:
#       $1          Interface name, e.g. en0
#
# Returns: prints MTU size in standard output
###############################################################################
get_MTU ()
{
    typeset PS4_FUNC="get_MTU"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    IF=$1

    MTUSIZE=""
    MTUSIZE=$(netstat -nI $IF | awk 'NR == 2 {print $2}')

    print $MTUSIZE
}


###############################################################################
#
# Main entry point
#
###############################################################################

PROGNAME=$(basename ${0})
export PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)"
[[ "$VERBOSE_LOGGING" == "high" ]] && set -x
[[ "$VERBOSE_LOGGING" == "high" ]] && version='1.9.1.2'
OP_SEP="$(cl_get_path -S)"
export LC_ALL=C
RESTORE_ROUTES=/usr/es/sbin/cluster/.restore_routes
#
# setup for rsct hats adapter call
#
export HA_DOMAIN_NAME=$(cldomain)
export HB_SERVER_SOCKET=/var/ha/soc/topsvcs/server_socket
BINDIR=/usr/sbin/rsct/bin
RC=0

# Check the runtime level
MIXVER=$(clmixver)
MIXVERRC=$?

cl_echo 33 "Starting execution of $0 with parameters $*" $0 "$*"
date

#  If PMTU discovery is enabled, we need to disable it temporarily.
#  If gated is running , disable it temporarily

# Will routes be changing?
if (( $# == 5 )) ; then
   non_alias $4
   if (( $? == 1 )) ; then
      	disable_pmtu_gated
   fi
else 
   disable_pmtu_gated
fi

set_ipignoreredirects

PROC_RES=false

# if JOB_TYPE is set, and it doesn't equal to "GROUP", then 
# we are processing for process_resources
if [[ ${JOB_TYPE:-0} != 0 && $JOB_TYPE != "GROUP" ]]; then
   PROC_RES=true
fi

set -u


case $# in
    #
    # This form changes a single interface, e.g. acquiring or releasing 
    #
    5)
	netstat -in
	netstat -rnC
        CASC_OR_ROT=$1		# rg relationship which owns the label
        ACQ_OR_RLSE=$2		# action
	IF=$3 			    # this is the interface (adapter)
	ADDR=$4			    # address to be acquired or released
	OLD_ADDR=$5		    # current address on the interface

    MTUSIZE=$(get_MTU $IF)
    PREFIX_LEN=$(cllsif -J "$OP_SEP" -Sn $ADDR | awk -F"$OP_SEP" '{print $14}') 
    
    # For cascading release, need to get the standby to put back
    if [[ "$CASC_OR_ROT" == "cascading" && "$ACQ_OR_RLSE" == "release" ]]
    then
        STBY_IP_ADDR=$(get_standby_for_service $IF $OLD_ADDR)
        [[ -n $STBY_IP_ADDR ]] && ADDR="$STBY_IP_ADDR"
    fi
	
    NET=$(cllsif -J "$OP_SEP" -Sw -n $ADDR | cut -f3 -d"$OP_SEP")
    ALIAS=$(cllsnw -J "$OP_SEP" -Sw -n $NET | cut -f3 -d"$OP_SEP")
    NET_TYPE=$(cllsif -J "$OP_SEP" -Sw -n $ADDR | cut -f4 -d"$OP_SEP")

    # done with interface and network specific actions
    # once the service IP is an ipv6 address, possible way of doing things is 
    # ALIASED.
    ALIAS_FIRST=$(clodmget -n -q"function = shared AND identifier=$ADDR" -f max_aliases HACMPadapter )
    if [[ "$ACQ_OR_RLSE" == "acquire" ]]
    then
        # Format for consumption by cl_am utility
        amlog_trace $AM_SERVICEIP_ALIAS_BEGIN "Aliasing Service IP|$ADDR"
        cl_echo 7310 "$PROGNAME: Configuring network interface $IF with aliased IP address $ADDR" $PROGNAME $IF $ADDR

        # alias add the specified address to the specified interface
        # 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
	case $ALIAS_FIRST in
		1027|771|1539|1283)
			#The user has chosen this address to be the first Address.
			clifconfig $IF inet6 alias $ADDR/$PREFIX_LEN up firstalias
			;;
		0|1|2)
			#Find if other service addresses are present on this adapter.
			# if not then this will be the first address.
			clifconfig $IF inet6 alias $ADDR/$PREFIX_LEN up firstalias
			;;
		515)
			#If persistent is on this adapter it will stay as First
			#If not the service will be first.
			PERSIST_IF=""
			PERSISTON=$(cllsif -J "$OP_SEP" -Sp $LOCALNODENAME | \
				awk -F"$OP_SEP" -v NET="$NET" '{if ($2 == "persistent" \
				&& $3 == NET) print $1}' | sort)
			if [[ -n "$PERSISTON" ]]
			then
				PERSIST_IF=$(LC_ALL=C clgetif -a $PERSISTON 2>/dev/null)
			fi
			if [[ -n "$PERSIST_IF"  && $IF == $PERSIST_IF ]]
			then
				clifconfig $IF inet6 alias $ADDR/$PREFIX_LEN up
			else
				clifconfig $IF inet6 alias $ADDR/$PREFIX_LEN up firstalias
			fi
			;;
		*)
			clifconfig $IF inet6 alias $ADDR/$PREFIX_LEN up
			;;
	esac
    
        # tell the clstrmgr to start monitoring this alias
        cl_hats_adapter $IF -e $ADDR alias

        check_alias_status $IF $ADDR $ACQ_OR_RLSE
        RC=$?
        # Format for consumption by cl_am utility
        if [[ $RC != 0 ]]
        then
            amlog_err $AM_SERVICEIP_ALIAS_FAILURE "Aliasing Service IP|$ADDR"
        else
            amlog_trace $AM_SERVICEIP_ALIAS_END "Aliasing Service IP|$ADDR"
        fi
        
    else
        cl_echo 7320 "$PROGNAME: Removing aliased IP address $OLD_ADDR from adapter $IF" $PROGNAME $OLD_ADDR $IF
        # Format for consumption by cl_am utility
        amlog_trace $AM_SERVICEIP_DEALIAS_BEGIN "Deliasing Service IP|$OLD_ADDR"
        
        PERSISTENT=""
        ADDR1=$OLD_ADDR
        disable_pmtu_gated
	alias_replace_routes $RESTORE_ROUTES $IF
	RC=$?
	: completed alias_replace_routes with return code $RC

        # delete the alias for the specified address
        clifconfig $IF inet6 delete $OLD_ADDR
	
        if [[ -n $NXTSVC && $swaproute == 1 ]]
	    then
            PREFIX_LEN=$(cllsif -J "$OP_SEP" -Sn $NXTSVC | awk -F"$OP_SEP" '{print $14}')
	    # 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
			clifconfig $IF inet6 alias $NXTSVC/$PREFIX_LEN up
			fi
        
	    $RESTORE_ROUTES
	    RC=$?
            : Completed $RESTORE_ROUTES with return code $RC
	    enable_pmtu_gated       # Reset pmtu and restart gated

	    # tell the clstrmgr not to monitor this alias
	    cl_hats_adapter $IF -d $OLD_ADDR alias

	    check_alias_status $IF $OLD_ADDR $ACQ_OR_RLSE
        RC=$?
        # Format for consumption by cl_am utility
            if [[ $RC != 0 ]]
            then
                amlog_err $AM_SERVICEIP_DEALIAS_FAILURE "Dealiasing Service IP|$OLD_ADDR"
            else
                amlog_trace $AM_SERVICEIP_DEALIAS_END "Deliasing Service IP|$OLD_ADDR"
            fi

    fi
    (( $RC != 0 )) && {
        # tell the resource manager the results
        cl_RMupdate resource_error $ADDR $PROGNAME

        if [[ $PROC_RES == false ]]; then
	        exit 1
	    else
	        exit 11
        fi
	}
    flush_ndp_cache

	netstat -in
	netstat -rnC
	;;

    #
    # this form for changing two address e.g. swap_adapter
    #
    6)
    UNUSED_1=$1
    UNUSED_2=$2
	IF1=$3		# interface currently holding the standby address
	ADDR1=$4	# the address to be recovered (service)
	IF2=$5		# interface currently holding the service
	ADDR2=$6	# the standby address 
	
	ACQ_OR_RLSE=""
    MTUSIZE=$(get_MTU $IF1)

	NET=$(cllsif -SwJ "$OP_SEP" -n $ADDR2 | cut -f3 -d"$OP_SEP")
	NET_TYPE=$(cllsif -SwJ "$OP_SEP" -n $ADDR2 | cut -f4 -d"$OP_SEP")

	PERSISTENT=$(odmget -q "function=persistent and nodename=$LOCALNODENAME and identifier=$ADDR1" HACMPadapter | grep ip_label)
        if [[ $PERSISTENT != "" ]]; then
                # The label passed in as the "service" label is actually
                # a persistent label, and it should be swapped to the
                # selected boot.  So just do that then exit.
                cl_configure_persistent_address swap -n $NET -a $IF1 -f $IF2
                RC=$?
                netstat -in
                netstat -rnC
                flush_ndp_cache
                enable_pmtu_gated   #Reset pmtu and restart gated
                restore_ipignoreredirects
                exit $RC
        fi

	alias_replace_routes $RESTORE_ROUTES $IF2
	RC=$?
	: Completed alias_replace_routes with return code $RC
    
	if [[ (${INVOCATION_FLAG:-0} == 0) || ($INVOCATION_FLAG != "USER_REQUESTED") ]]
	then
	    cl_configure_persistent_address swap -n $NET -a $IF1 -f $IF2
	    netstat -in
	    netstat -rnC
	fi
    
    # Delete the alias service from the current interface
    clifconfig $IF2 inet6 $ADDR1 delete
    	
    
	# add the alias service to the target interface
	PREFIX_LEN=$(cllsif -J "$OP_SEP" -Sn $ADDR1 | awk -F"$OP_SEP" '{print $14}')
	# 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 $IF1 inet6 | awk '($2 ~ /^fe80::*/){print $2}')
        if [[ -z "$LL_ADDR" ]]
        then
            autoconf6 -i $IF1
        fi

	NET=$(cllsif -SwJ "$OP_SEP" -n $ADDR1 | cut -f3 -d"$OP_SEP")
	ALIAS_FIRST=$(clodmget -n -q"function = shared AND identifier=$ADDR" -f max_aliases HACMPadapter )
	case $ALIAS_FIRST in
		1027|771|1539|1283)
			#The user has chosen this address to be the first Address.
			clifconfig $IF1 inet6 alias $ADDR1/$PREFIX_LEN up firstalias
			;;
		0|1|2)
			#Find if other service addresses are present on this adapter.
			# if not then this will be the first address.
			clifconfig $IF1 inet6 alias $ADDR1/$PREFIX_LEN up firstalias
			;;
		515)
			#If persistent is on this adapter it will stay as First
			#If not the service will be first.
			PERSIST_IF=""
			PERSISTON=$(cllsif -J "$OP_SEP" -Sp $LOCALNODENAME | \
				awk -F"$OP_SEP" -v NET="$NET" '{if ($2 == "persistent" \
				&& $3 == NET) print $1}' | sort)
			if [[ -n "$PERSISTON" ]]
			then
				PERSIST_IF=$(LC_ALL=C clgetif -a $PERSISTON 2>/dev/null)
			fi
			if [[ -n "$PERSIST_IF"  && $IF1 == $PERSIST_IF ]]
			then
				clifconfig $IF1 inet6 alias $ADDR1/$PREFIX_LEN up
			else
				clifconfig $IF1 inet6 alias $ADDR1/$PREFIX_LEN up firstalias
			fi
			;;
		*)
			clifconfig $IF1 inet6 alias $ADDR1/$PREFIX_LEN up
			;;
	esac
        $RESTORE_ROUTES
	RC=$?
        : Completed $RESTORE_ROUTES with return code $RC
	netstat -in
	netstat -rnC
	flush_ndp_cache
	enable_pmtu_gated
    # Tell the cluster manager to start monitoring this alias
    cl_hats_adapter $IF1 -e $ADDR1  alias
    
    check_alias_status $IF1 $ADDR1 "acquire"
    (( $? != 0 )) && {
        # tell clstrmgr to stop monitoring
    	# cl_hats_adapter $IF1 -d $ADDR1 alias ??
    
		# tell the resource manager the results
		cl_RMupdate resource_error $ADDR1 $PROGNAME
			
		if [[ $PROC_RES == false ]]; then
		    exit 1
		else
		    exit 11
		fi
    }

    enable_pmtu_gated
    		
    ;;

    *)
       # bad arg count
       cl_echo 62 "usage: $PROGNAME cascading/rotating acquire/release interface new_address old_address" $PROGNAME
       cl_echo 63 "    or $PROGNAME swap_adapter swap interface1 address1 interface2 address2" $PROGNAME
       exit 2
    esac

restore_ipignoreredirects

cl_echo 32 "Completed execution of $0 with parameters $*.  Exit status = $RC" $0 "$*" $RC

date

exit $RC
