#!/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 [-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