#!/bin/ksh93
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r721 src/43haes/usr/sbin/cluster/events/swap_adapter.sh 1.33.10.4 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1990,2016 
# 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 
# @(#)95  1.33.10.4  src/43haes/usr/sbin/cluster/events/swap_adapter.sh, hacmp.events, 61haes_r721, 1638A_hacmp721 9/14/16 09:47:30

#================================================
# The following, commented line enforces coding
# standards when this file is edited via vim.
#================================================
# vim:tabstop=4:shiftwidth=4:expandtab:smarttab
#================================================

#########################################################################
#
#   COMPONENT_NAME: EVENTS
#
#   FUNCTIONS: name_to_addr
#
#########################################################################

#########################################################################
#
# Name:        swap_adapter
#
# Description: This event script is called to recover a service address.
#
# Arguments:   nodename network ip_address1 ip_address2
#
#              ip_address1 - the new available address this script
#                            swaps the service adapter to.
#              ip_address2 - the failed address
#
# Returns:     0   success
#              1   failure
#              2   bad argument
#
#########################################################################

###############################################################################
#
# 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"
    [[ $VERBOSE_LOGGING == "high" ]] && set -x
    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
} # End of "get_inet_family()"


#########################################################################
#
# Name: best_boot_addr
#
# This routine finds the best boot interface for hosting an aliased service
# address. This routine exercises the resource distribution preference for
# service labels. The available options are:
#       anit-collocation - the default - all UP interfaces are sorted
#               according to the number of addresses currently on the interface.
#               The interface with the least number is selected.
#       collocation - put all service on the same interface
#       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
#
# Returns: network address of the selected boot interface
#
#########################################################################
best_boot_addr() {
    typeset PS4_FUNC="best_boot_addr"
    [[ $VERBOSE_LOGGING == "high" ]] && set -x
    SERV_ADDRESS=$1
    NETWORK=$2
    shift
    shift
    candidate_boots=$*
    ADDR_FAMILY=""

    # if there is only one boot then thats the candidate - regardless of
    # state or distribution preference
    integer 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=$(clodmget -q"identifier = $SERV_ADDRESS AND function = shared" -f max_aliases -n HACMPadapter | sort -nu | tail -1)
    # decode the setting
    case $MA in
        1|771 )
        # simple collocation
        # if there is already a service on any of the candidates, then that is
        # the candidate for this service 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=""
        for service in $services
        do
            # is it on this node ?
            service_if=$(LC_ALL=C clgetif -a $service)
            [[ -n "$service_if" ]] && break        #found it
        done
        # if there is a service, scan list of candidates
        if [[ -n "$service_if" ]]
        then
            for candidate in $candidate_boots
            do
                LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | read \
                candidate_dot_addr junk
                #
                : Finding family of address
                #
                ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)
                # find the state of this candidate
                if [[ "$ADDR_FAMILY" == "inet" ]]; then
                    addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                    addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                fi
                candidate_state=$(eval print $addr)
                boot_if=$(LC_ALL=C clgetif -a $candidate)
                if [[ $candidate_state == "UP" && -n $boot_if && \
                      $boot_if == $service_if ]]
                then
                    best_candidate=$candidate
                    break
                fi
            done
        fi

        # if the loop above did not identify a candidate, then the
        # candidate is the first UP boot
        if [[ $best_candidate == "NONE" ]]; then
            for candidate in $candidate_boots
            do
                LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | \
                read candidate_dot_addr junk

                #
                : Finding family of address
                #
                ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)
                # find the state of this candidate
                if [[ "$ADDR_FAMILY" == "inet" ]]; then
                    addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                    addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                fi
                candidate_state=$(eval print $addr)

                if [[ $candidate_state == "UP" ]]; then
                    best_candidate=$candidate
                    break  # all done
                fi
            done
        fi
        ;;
        259|1283 )
        # collocation with persistent
        # if there is a persistent label on any of the candidates, then
        # that is the candidate for this service
        # despite being passed the local node name, cllsif returns all
        # persistent
        # labels !
        # dont know where you grabbed this code from, but its worth
        # fixing the
        # test...
        persistent=$(cllsif -J "$OP_SEP" -Sp $LOCALNODENAME | \
        awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "persistent" \
        && $3 == NET) print $1}' | sort)
        persistent_if=""
        if [[ -n "$persistent" ]]
        then
            # is it on this node ?
            persistent_if=$(LC_ALL=C clgetif -a $persistent)
        fi
        # if there is a persistent, scan list of candidates
        if [[ -n "$persistent_if" ]]
        then
            for candidate in $candidate_boots
            do
                LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | \
                read candidate_dot_addr junk

                #
                : Finding family of address
                #
                ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)
                # find the state of this candidate
                if [[ "$ADDR_FAMILY" == "inet" ]]; then
                    addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                    addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                fi
                candidate_state=$(eval print $addr)
                boot_if=$(LC_ALL=C clgetif -a $candidate)
                if [[ $candidate_state == "UP" && -n $boot_if && \
                      $boot_if == $persistent_if ]]
                then
                    best_candidate=$candidate
                    break
                fi
            done
        fi

        # if the loop above did not identify a candidate, then go through
        # the same calculation as we use for simple anti-collocation
        if [[ $best_candidate == "NONE" ]]; then
            for candidate in $candidate_boots
            do
                LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                    cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | \
                    read candidate_dot_addr junk

                #
                : Finding family of address
                #
                ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)

                # find the state of this candidate
                if [[ "$ADDR_FAMILY" == "inet" ]]; then
                    addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                    addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                fi
                candidate_state=$(eval print $addr)

                if [[ $candidate_state == "UP" ]]; then
                    # this interface is UP - now lets check how many
                    # addresses it is already hosting
                    candidate_if=$(LC_ALL=C clgetif -a $candidate_dot_addr)
                    # Check if candidate_if is available. This check is for the case
                    # where during swap_adapter, interface goes away.
                    if [[ -n "$candidate_if" ]]
                    then
                        candidate_aliases=$(LC_ALL=C ifconfig $candidate_if |\
                                            grep -c -w "inet")
                        if [[ $best_candidate == "NONE" ]] || \
                           (( $candidate_aliases < $best_aliases ))
                        then
                            best_candidate=$candidate
                            best_aliases=$candidate_aliases
                        fi
                    fi
                fi
            done
        fi
        ;;
        515|1539 )
        # anti-collocation with persistent
        # if there is a persistent label on any of the candidates,
        # then
        # that candidate should be marked DOWN to avoid its
        # selection
        persistent=$(cllsif -J "$OP_SEP" -Sp $LOCALNODENAME | \
        awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "persistent" \
        && $3 == NET) print $1}' | sort)
        save_if="NONE"
        persistent_if=""
        if [[ -n "$persistent" ]]
        then
            # is it on this node ?
            persistent_if=$(LC_ALL=C clgetif -a $persistent 2>/dev/null)
        fi
        # if there is a persistent, scan list of candidates
        if [[ -n "$persistent_if" ]]
        then
            for candidate in $candidate_boots
            do
                LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                    cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | \
                    read candidate_dot_addr junk

                #
                : Finding family of address
                #
                ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)
                # find the state of this candidate
                if [[ "$ADDR_FAMILY" == "inet" ]]; then
                    addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                    addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                fi
                candidate_state=$(eval print $addr)
                boot_if=$(LC_ALL=C clgetif -a $candidate)
                if [[ $candidate_state == "UP" && -n $boot_if && \
                      $boot_if == $persistent_if ]]
                then
                    LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                        cut -f7,11 -d"$OP_SEP" | \
                        tr "$OP_SEP" " " | read candidate_dot_addr junk

                    # if the interface is up, save it away just in case
                    # its our only up interface
                    #
                    : Finding family of address
                    #
                    ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)

                    if [[ "$ADDR_FAMILY" == "inet" ]]; then
                        addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                    elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                        addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                    fi
                    candidate_state=$(eval print $addr)
                    [[ $candidate_state == "UP" ]] && save_if=$candidate_dot_addr

                    # set state to down
                    if [[ "$ADDR_FAMILY" == "inet" ]]; then
                        addr=i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                    elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                        addr=i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
                    fi
                    export $addr="DOWN"
                    break
                fi
            done
        fi

        # now that any interface holding the persistent is marked as DOWN,
        # go through the same calculation as we use for simple
        # anti-collocation
        for candidate in $candidate_boots
        do
            LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | \
                read candidate_dot_addr junk

            #
            : Finding family of address
            #
            ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)

            # find the state of this candidate
            if [[ "$ADDR_FAMILY" == "inet" ]]; then
                addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
            elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
            fi
            candidate_state=$(eval print $addr)

            if [[ $candidate_state == "UP" ]]; then
                # this interface is UP - now lets check how many addresses
                # it is already hosting
                candidate_if=$(LC_ALL=C clgetif -a $candidate_dot_addr)

                # Check if candidate_if is available. This check is for the
                # case where during swap_adapter, interface goes away.
                if [[ -n "$candidate_if" ]]
                then
                    candidate_aliases=$(LC_ALL=C ifconfig $candidate_if |\
                                        grep -c -w "inet")
                    if [[ $best_candidate == "NONE" ]] || \
                       (( $candidate_aliases < $best_aliases ))
                    then
                        best_candidate=$candidate
                        best_aliases=$candidate_aliases
                    fi
                fi
            fi
        done

        # if the loop above did not find a candidate then we cannot
        # exercise the preference - try setting the candidate to the
        # same interface as has the persistent
        [[ $best_candidate == "NONE" ]] && best_candidate=$save_if

        ;;
        * )
        # default to rdp_anti_collocation
        # test all the candidates in the list
        for candidate in $candidate_boots
        do
            LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | \
                read candidate_dot_addr junk

            #
            : Finding family of address
            #
            ADDR_FAMILY=$(get_inet_family $candidate_dot_addr)

            # find the state of this candidate
            if [[ "$ADDR_FAMILY" == "inet" ]]; then
                addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR}
            elif [[ "$ADDR_FAMILY" == "inet6" ]]; then
                addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR}
            fi
            candidate_state=$(eval print $addr)

            if [[ $candidate_state == "UP" ]]; then
                # this interface is UP - now lets check how many addresses
                # it is already hosting
                candidate_if=$(LC_ALL=C clgetif -a $candidate_dot_addr)

                # Check if candidate_if is available. This check is for the
                # case where during swap_adapter, interface goes away.
                if [[ -n "$candidate_if" ]]
                then
                    candidate_aliases=$(LC_ALL=C ifconfig $candidate_if | grep -c -w "inet")
                    if [[ $best_candidate == "NONE" ]] || \
                       (( $candidate_aliases < $best_aliases ))
                    then
                        best_candidate=$candidate
                        best_aliases=$candidate_aliases
                    fi
                fi
            fi
        done
        ;;
    esac

    # once here, the best candidate should have been selected
    if [[ $best_candidate != "NONE" ]]; then
        echo $best_candidate
        return
    fi

    # Should never get here
    dspmsg scripts.cat 342 "Unable to determine local boot/service interface.\n"
    exit 1
} # End of "best_boot_addr()"


###############################################################################
#
# This routine maps a label_address to an internet_dot_address.
# Thus, given a label_address, we do not require the name server
# to get its corresponding dot address.
#
###############################################################################
name_to_addr() {
    typeset PS4_FUNC="name_to_addr"
    [[ $VERBOSE_LOGGING == "high" ]] && set -x
    echo $(cllsif -J "$OP_SEP" -Sn $1 | cut -d"$OP_SEP" -f7 | uniq)
    exit $?
} # End of "name_to_addr()"


###############################################################################
# This routine sets the status of resource in resource location DB.
###############################################################################
set_resource_status() {
    typeset PS4_FUNC="set_resource_status"
    [[ $VERBOSE_LOGGING == "high" ]] && set -x
    if [ -n "$GROUPNAME" ]
    then
        clchdaemons -d clstrmgr_scripts -t resource_locator \
                    -n "$LOCALNODENAME" -o "$GROUPNAME" -v "$1"
        if (( $? != 0 ))
        then
            cl_log 655 "$PROGNAME: Problem with resource location database in HACMPdaemons ODM." $PROGNAME
            STATUS=1
        fi
    fi

    #
    # Resource Manager Updates
    #
    if [[ $1 == "ERROR" && -n $GROUPNAME ]]
    then
        cl_RMupdate rg_error "$GROUPNAME" "$PROGNAME"
    fi
} # End of "set_resource_status()"


###############################################################################
#
# Name: check_for_WPAR_failure
#
###############################################################################
check_for_WPAR_failure() {
    typeset PS4_FUNC="check_for_WPAR_failure"
    [[ $VERBOSE_LOGGING == "high" ]] && set -x

    if [[ -z $GROUPNAME ]]
    then
        # return 0 if no GROUPNAME is specified
        return 0
    fi

    set -a
        eval $(cllsres -g ${GROUPNAME} | grep WPAR_NAME)
    set +a
    if [[ -z $WPAR_NAME ]]
    then
        # return 0 if RG is not WPAR enabled
        return 0
    fi

    WPAR_STATE=$(lswpar ${WPAR_NAME} |\
                 awk '{ if ( $1 == "'${WPAR_NAME}'" ) print $2 }')
    if [[ $WPAR_STATE == "A" ]]
    then
        # return 0 if WPAR is active
        return 0
    fi

    #
    # Come here because of odd case: RG is WPAR enabled, but WPAR is not active
    # Set RG to ERROR state and print an ERROR, exit with RC=1 to generate a
    # EVENT ERROR
    #
    cl_RMupdate rg_error "$GROUPNAME" "$PROGNAME"
    cl_log 10600 "'%1\$s': ERROR: WPAR '%2\$s' is not active."  $PROGNAME $WPAR_NAME
    exit 1
} # End of "check_for_WPAR_failure()"



###############################################################################
#
# MAIN Main main
#
###############################################################################

PROGNAME=${0##*/}
export PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)"

set -a
    eval $(cllsparam -n $LOCALNODENAME)
set +a

[[ $VERBOSE_LOGGING == "high" ]] && set -x

OP_SEP="$(cl_get_path -S)"

STATUS=0

if (( $# != 4 ))
then
    cl_echo 1041 "Usage: $PROGNAME nodename network ip_address1 ip_address2\n" $PROGNAME
    exit 2
fi

# if this is a remote event, exit
if [[ $1 != $LOCALNODENAME ]]
then
    exit 0
fi

if [[ -n "$SIMULATENODE" ]]
then
    cl_echo 3020 "NOTICE >>>> Simulator Command <<<< \n"
    echo "No action in simulator mode for swap_adapter"
    exit 0
fi

# turn off DNS/NIS
export NSORDER=local

#
# If address is given in ip label format, convert to dot addr.,
# this is required by cl_swap_IP_addr.
# ADDR1 is the "target" address/interface which is currently holding
# a boot or standby label and upon exit will have the service.
#
ADDR1=$(name_to_addr $3)
#
# Do the same for ADDR2.
# ADDR2 is the service or highly available address which upon exit will
# be avaialble on the interface now in use by ADDR1.
#
ADDR2=$(name_to_addr $4)

#
# Get the resource group if there is one because it may be needed
# by set_resource_status
#
SERVICE_LABEL=$(cllsif -SJ "$OP_SEP" | awk -F"$OP_SEP" '$7 == "'$ADDR2'" {print $1;exit}')
GROUPNAME=""
if [[ $SERVICE_LABEL != "" ]]; then
    GROUPNAME=$(odmget -q "name=SERVICE_LABEL and value=$SERVICE_LABEL" HACMPresource \
    | grep -w group | awk '{print $3}'| sed 's/"//g')
fi
export GROUPNAME

#
# check if WPAR-enabled Resource Group exists and in active status
#
check_for_WPAR_failure

#
# Get the interface currently holding the recovery label - the one which will
# eventually get the service address.
#
SERVICE_INTERFACE=$(LC_ALL=C clgetif -a $ADDR1)

#
# If the label passed to us is not currently on an interface, try to find
# an alternate recovery address/interface
#
if [[ $SERVICE_INTERFACE == "" ]]
then
    if [[ ${INVOCATION_FLAG:-0} == 0 || \
          $INVOCATION_FLAG != "USER_REQUESTED" ]]
    then
        cl_echo 7624 "$PROGNAME: Interface for boot network interface $3 could not be found." $PROGNAME $3
        #
        # This can occur if the swap event gets pre-empted by a higher priority
        # event (e.g. node_down) which consumes the standby adapter that was to
        # have been used for this event. Look for a different standby on the
        # same network
        #
        ALT_STBYS=$(cllsif -SJ "$OP_SEP"             |\
                    grep "$OP_SEP$2$OP_SEP"          |\
                    grep "${OP_SEP}standby${OP_SEP}" |\
                    cut -f1 -d"$OP_SEP")
        for candidate in $ALT_STBYS
        do
            LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \
                cut -f7,11 -d"$OP_SEP" | tr "$OP_SEP" " " | \
                read candidate_dot_addr junk

            #
            : Finding family of address
            #
            INET_FAMILY=$(get_inet_family $candidate_dot_addr)
            # find the state of this candidate
            if [[ "$INET_FAMILY" == "inet" ]]; then
                addr=\$i${candidate_dot_addr//\./x}_$LOCALNODENAME
            elif [[ "$INET_FAMILY" == "inet6" ]]; then
                addr=\$i${candidate_dot_addr//:/y}_$LOCALNODENAME
            fi
            candidate_state=$(eval print $addr)

            if [[ $candidate_state == "UP" ]]; then
                SERVICE_INTERFACE=$(LC_ALL=C clgetif -a $candidate)
                break
            fi
        done

        if [[ $SERVICE_INTERFACE == "" ]]
        then
            cl_echo 7627 "$PROGNAME: Check hacmp.out for events prior to this one which may\nhave consumed the available boot network interfaces." $PROGNAME
            cl_log 7628 "$PROGNAME: Service adapter $4 will not be recovered by this event." $PROGNAME $4
            exit 0
        else
            cl_echo 7626 "$PROGNAME: Using boot network interface $candidate instead.\n" $PROGNAME $candidate
        fi
    else
        cl_log 7624 "$PROGNAME: Interface for boot network interface $3 could not be found." $PROGNAME $3
        exit 1
    fi
fi

NETMASK=$(LC_ALL=C clgetif -n $ADDR1)
NETWORK=$(cllsif -J "$OP_SEP" -Sn $ADDR2 | awk -F"$OP_SEP" '{print $3}')
ALIAS=$(cllsnw -J "$OP_SEP" -Sw -n $NETWORK | cut -f3 -d"$OP_SEP")
SERVICE_TYPE=$(cllsif -J "$OP_SEP" -Sn $ADDR2 | awk -F"$OP_SEP" '{print $2}')

#
# Get the interface currently holding the failed service - on exit this
# interface will get the recovery address (standby) if using ipat via
# replacement).
# If the interface is not configured, which is sometimes true
# at startup with the boot interface, just exit 0.
#
STANDBY_INTERFACE=$(LC_ALL=C clgetif -a $ADDR2)
if [[ $STANDBY_INTERFACE == "" ]]
then
    #
    # if an alias service address has been deleted, set both the failed
    # interface and recovery interface to the same value - this will cause
    # the service to be deleted leaving just the boot label on the interface.
    #
    if [[ $ALIAS == "true" ]]
    then
        STANDBY_INTERFACE=$SERVICE_INTERFACE
    else

        if [[ $SERVICE_TYPE == "boot" ]]
        then
            exit 0
        else
            cl_log 7625 "$PROGNAME: Interface for service adapter $4 could not be found." $PROGNAME $4
            cl_log 7628 "$PROGNAME: Service adapter $4 will not be recovered by this event." $PROGNAME $4
            set_resource_status "ERROR"
            exit 1
        fi
    fi
fi

# When this event is called by clstrmgr, the ADDR1 passed in is
# the address/interface the clstrmgr found as being up and capable of
# servicing the service label. This event can also be called from
# clswapaddress in response to a user initiated request to move a label.
# Clstrmgr does not yet exercise the resource distribution preference,
# so we may need to change the recovery label.
if [[ ${INVOCATION_FLAG:-0} == 0 || \
      $INVOCATION_FLAG != "USER_REQUESTED" ]]
then
    if [[ $ALIAS == "true" ]]
    then
        #
        # Call cl_configure_persistent_address in case the failed interface is
        # holding the persistent address - this will give it a chance to
        # recover the persistent label before we exercise the resource
        # distribution preference
        #
        cl_configure_persistent_address swap -n $NETWORK -a $SERVICE_INTERFACE -f $STANDBY_INTERFACE

        # find the full list of candidates for hosting this service
        boot=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | \
        awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "boot" && $3 == NET) \
        print $1}' | sort)
        ADDR1=$(best_boot_addr $ADDR2 $NETWORK $boot)
        # If best_boot_addr is not able to find
        # any candidate interface for holding
        # service lable, then exit.
        if (( $? != 0 ))
        then
            dspmsg -s 19 scripts.cat 10507 "$PROGNAME: An available adapter for service label $SERVICE_LABEL on network $NETWORK could not be found.\n" $PROGNAME $SERVICE_LABEL $NETWORK
            exit 0
        fi
        SERVICE_INTERFACE=$(LC_ALL=C clgetif -a $ADDR1)
    fi
fi

#
# Release SNA rsources
# If any SNA activity is running on the adapter to be released
# or acquired, swap_adapter will fail.
#
# Check to see if SNA is part of the resource group on the service
# adapter
SNA_LINKS=""
if [ -n "$GROUPNAME" ]
then
    set -a
    eval $(clsetenvres $GROUPNAME $PROGNAME)
    set +a

    if [[ -n "$COMMUNICATION_LINKS" ]]
    then

        #stop the link applications, if any are active
        for a_link in $COMMUNICATION_LINKS
        do
            APPL=""
            LINKTYPE=""
            #get link information
            eval $(cllscommlinks -C -t snalan | \
            awk "BEGIN { FS=\":\" } \$1 == \"${a_link}\" {\
    printf(\"LINKTYPE=%s APPL=%s\", \$2, \$6) }")
            if [[ "${LINKTYPE}" != "snalan" ]]
            then
                # not SNA-over-LAN, ignore it
                continue
            fi
            #remember that we found an SNA link
            SNA_LINKS="$SNA_LINKS$a_link "

            #stop the application service for this link
            if [ -n "$APPL" ]
            then
                cl_SNAapp -stop $APPL "SNA"
                if (( $? != 0 ))
                then
                    cl_log 4166 "Error processing script $APPL ." $APPL
                    STATUS=1
                fi
            fi
        done

        #now release the links
        if [ -n "$SNA_LINKS" ]
        then
            cl_release_sna_dlc $SERVICE_INTERFACE $STANDBY_INTERFACE

            if (( $? != 0 ))
            then
                cl_echo 4170 "$PROGNAME: Failure occurred while releasing SNA DLC profiles.\nManual intervention required.\n" $PROGNAME
                STATUS=1
            fi
        fi
    fi
fi

#
# Call cl_swap_IP_address to do the actual swap
#
INET_FAMILY=$(get_inet_family $ADDR2)

if [[ $INET_FAMILY == "inet6" ]]
then
    cl_swap_IPv6_address swap_adapter swap \
    $SERVICE_INTERFACE $ADDR2 $STANDBY_INTERFACE $ADDR1
else
    cl_swap_IP_address swap_adapter swap \
    $SERVICE_INTERFACE $ADDR2 $STANDBY_INTERFACE $ADDR1 $NETMASK
fi
if (( $? != 0 ))
then
    STATUS=1
    cl_log 316 "Can not perform adapter swap on $SERVICE_INTERFACE and $STANDBY_INTERFACE" $SERVICE_INTERFACE $STANDBY_INTERFACE
fi

#
# Acquire and start SNA rsources
#
if [[ -n "$SNA_LINKS" ]]
then
    cl_acquire_sna_dlc $SERVICE_INTERFACE $SNA_LINKS
    if (( $? == 0 ))
    then
        for snadlc in $SNA_LINKS
        do
            cl_start_snalink $snadlc
        done
    fi
fi
if (( $? != 0 ))
then
    cl_echo 4171 "$PROGNAME: Failure occurred while acquiring SNA DLC profiles.\nManual intervention required.\n" $PROGNAME
    STATUS=1
fi

if (( $STATUS != 0 ))
then
    set_resource_status "ERROR"
fi

exit $STATUS
