#!/bin/sh # # $Id: IPaddr2.in,v 1.8.2.5 2004/08/30 09:08:24 horms Exp $ # # Copyright (C) 2003 Tuomo Soini <tis@foobar.fi> # # This script manages IP alias IP addresses # # It can add an IP alias, or remove one. # # usage: $0 ip-address[/netmaskbits[/interface[:label][/broadcast]]] \ # {start|stop|status|monitor} # # The "start" arg adds an IP alias. # # Surprisingly, the "stop" arg removes one. :-) # # unset LANG LC_ALL=C export LC_ALL prefix=/usr exec_prefix=/usr . /etc/ha.d/shellfuncs IP2UTIL=/sbin/ip SENDARP=$HA_BIN/send_arp FINDIF=$HA_BIN/findif VARLIB=/var/lib/heartbeat VLDIR=$VARLIB/rsctmp/IPaddr SENDARPPIDDIR=$VARLIB/rsctmp/send_arp USAGE="usage: $0 ip-address[/netmaskbits[/interface[:label][/broadcast]]] {start|stop|status|monitor}\n\nNote: $0 only works on Linux"; # # Set BASEIP for use in other parts of script. # Find out which interface to use with findif utility and # parse findif output. # BASEIP=`echo $1 | sed 's%/.*%%'` NICINFO=`$FINDIF -C $1 2>/dev/null | sed -e 's/netmask\ //;s/broadcast\ //'` IFACE=`echo "$NICINFO" | cut -f1` NETMASK=`echo "$NICINFO" | cut -f2` BROADCAST=`echo "$NICINFO" | cut -f3` case $IFACE in *:*) INTERFACE=`echo $IFACE | sed 's/:.*//'` IFLABEL=$IFACE ;; *) INTERFACE=$IFACE ;; esac # # Find out which interface serves the given IP address # The argument is an IP address, and its output # is an interface name (e.g., "eth0"). # find_interface() { # # List interfaces but exclude FreeS/WAN ipsecN virtual interfaces # iface=`$IP2UTIL -o -f inet addr show | grep "\ $1/" \ | cut -d ' ' -f2 | grep -v '^ipsec[0-9][0-9]*$'` echo $iface return 0 } # # Check if ip-address is running. # We return stopped or running. # status() { IFSTATUS=`find_interface $BASEIP` if [ -z "$IFSTATUS" ] then echo "stopped" RC=3 else case $IFSTATUS in lo*) # # Do we really control loopback interface? # if [ "$INTERFACE" = "lo" ] # Yes, we do. then echo "running" RC=0 # No, this is "Conflicting loopback" else echo "loopback" RC=3 fi ;; *) echo "running" RC=0 ;; esac fi return $RC } # # Delete an interface # delete_interface () { ipaddr="$1" iface="$2" CMD="$IP2UTIL -f inet addr delete $ipaddr dev $iface" ha_log "info: $CMD" $CMD if [ $? -ne 0 ] then return $? fi CMD="$IP2UTIL -o -f inet addr show $iface" ha_log "info: $CMD" ADDR=`$CMD` if [ $? -ne 0 -o ! -z "$ADDR" ] then return $? fi CMD="$IP2UTIL link set $iface down" ha_log "info: $CMD" $CMD return $? } # # Add an interface # add_interface () { ipaddr="$1" netmask="$2" broadcast="$3" iface="$4" label="$5" CMD="$IP2UTIL -f inet addr add $ipaddr/$netmask brd $broadcast dev $iface" if [ ! -z "$label" ] then CMD="$CMD label $label" fi ha_log "info: $CMD" $CMD if [ $? -ne 0 ] then return $? fi CMD="$IP2UTIL link set $iface up" ha_log "info: $CMD" $CMD return $? } # # Delete a route # delete_route () { prefix="$1" iface="$2" CMD="$IP2UTIL route delete $prefix dev $iface" ha_log "info: $CMD" $CMD return $? } # On Linux systems the (hidden) loopback interface may # conflict with the requested IP address. If so, this # unoriginal code will remove the offending loopback address # and save it in VLDIR so it can be added back in later # when the IPaddr is released. # remove_conflicting_loopback() { ipaddr="$1" netmask="$2" broadcast="$3" ifname="$4" ha_log "info: Removing conflicting loopback $ifname." if [ -d "$VLDIR/" ] || mkdir -p "$VLDIR/" then : Directory $VLDIR now exists else ha_log "ERROR: Could not create \"$VLDIR/\" conflicting" \ " loopback $ifname cannot be restored." fi if echo "$ipaddr $netmask $broadcast $ifname" > "$VLDIR/$ipaddr" then : Saved loopback information in $VLDIR/$ipaddr else ha_log "ERROR: Could not save conflicting loopback $ifname." \ "it will not be restored." fi delete_interface "$ipaddr" "$ifname" # Forcibly remove the route (if it exists) to the loopback. delete_route "$ipaddr" "$ifname" } # # On Linux systems the (hidden) loopback interface may # need to be restored if it has been taken down previously # by remove_conflicting_loopback() # restore_loopback() { ipaddr="$1" if [ -s "$VLDIR/$ipaddr" ] then ifinfo=`cat "$VLDIR/$ipaddr"` ha_log "info: Restoring loopback IP Address " \ "$ifinfo." add_interface $ifinfo rm -f "$VLDIR/$ipaddr" fi } run_send_arp() { # # Run send_arp to note peers about new mac address # [ -r ${CONF_D}/arp_config ] && . ${CONF_D}/arp_config if [ -r "${CONF_D}/arp_config:${TARGET_INTERFACE}" ] then . "${CONF_D}/arp_config:${TARGET_INTERFACE}" fi # Set default values (can be overridden as described above) : ${ARP_INTERVAL_MS=200} # milliseconds between ARPs : ${ARP_REPEAT=5} # repeat count : ${ARP_BACKGROUND=yes} # no to run in foreground : ${ARP_NETMASK=ffffffffffff} # netmask for ARP ARGS="-i $ARP_INTERVAL_MS -r $ARP_REPEAT -p $SENDARPPIDFILE $INTERFACE $BASEIP auto $BASEIP $ARP_NETMASK" ha_log "$SENDARP $ARGS" case $ARP_BACKGROUND in yes) ($SENDARP $ARGS || ha_log "ERROR: Could not send gratuitous arps") & ;; *) $SENDARP $ARGS || ha_log "ERROR: Could not send gratuitous arps" ;; esac } # # Add an IP alias for the requested IP address... # # It could be that we already have taken it, in which case it should # do nothing. # start() { SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$BASEIP" # # Do we already service this IP address? # case `status $1` in running) exit 0 ;; loopback) remove_conflicting_loopback $BASEIP 32 255.255.255.255 lo ;; esac # # If there is local_takeip script, run it. # if [ -x $HA_RCDIR/local_takeip ] then $HA_RCDIR/local_takeip $* fi add_interface $BASEIP $NETMASK $BROADCAST $INTERFACE $IFLABEL rc=$? case $rc in 0) ;; *) echo "ERROR: $CMD failed." return $rc ;; esac case $INTERFACE in lo*) : no need to run send_arp on loopback ;; *) run_send_arp ;; esac } # # Remove the IP alias for the requested IP address... # stop() { IF=`find_interface $BASEIP` SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$BASEIP" if [ -f "$SENDARPPIDFILE" ] then kill `cat "$SENDARPPIDFILE"` rc=$? case $rc in 0) ha_log "info: killed previously running send_arp for $BASEIP" rm -f "$SENDARPPIDFILE" ;; *) ha_log "WARN: Could not kill previously running send_arp for $BASEIP" ;; esac fi if [ -z "$IF" ] then : Requested interface not in use exit 0 fi # # If there is local_giveip script, run it. # if [ -x $HA_RCDIR/local_giveip ] then $HA_RCDIR/local_giveip $* fi delete_interface $BASEIP $IF rc=$? restore_loopback "$BASEIP" case $rc in 0) ha_log "info: IP Address $BASEIP released" ;; *) ha_log "WARN: IP Address $BASEIP NOT released" ;; esac return $rc } # # Determine if this IP address is really being served, or not. # Note that we don't distinguish if *we're* serving it locally... # monitor() { OPTS=" -c 1 -w1 -q" for j in 1 2 3 do if /bin/ping $OPTS $BASEIP >/dev/null 2>&1 then echo "OK" return 0 fi done echo "down" return 1 } usage() { echo -e $USAGE >&2 } # # Add or remove IP alias for the given IP address... # if [ $# -ne 2 ] then usage exit 1 fi case $2 in start) start $1 ;; stop) stop $1 ;; status) status $1 ;; monitor) monitor $1 ;; *) usage exit 1 ;; esac # EOF - end of file