Sophie

Sophie

distrib > CentOS > 5 > x86_64 > by-pkgid > 473b7338dfa56c5dcc9280f991084d1f > files > 6

ctdb-1.0.112-2.el5.x86_64.rpm

#!/bin/sh

#################################
# interface event script for ctdb
# this adds/removes IPs from your 
# public interface

. $CTDB_BASE/functions
loadconfig

[ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
	CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
}

[ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
	echo "No public addresses file found. Nothing to do for 10.interfaces"
	exit 0
}

add_failover_block() {
	# Make sure our chain exists
	iptables -N ctdbfailover 2> /dev/null
	
	# make sure we link to it from INPUT
	iptables -L INPUT -n | grep ctdbfailover >/dev/null 2>/dev/null || {
		iptables -I INPUT -j ctdbfailover
	}
	# block this ip
	iptables -I ctdbfailover -i $1 -d $2 -j DROP
}

delete_failover_block() {
	iptables -D ctdbfailover -i $1 -d $2 -j DROP 2>/dev/null
}

delete_all_failover_blocks() {
	# make sure to remova all links to the ctdbfailover table
	while iptables -L INPUT -n | grep ctdbfailover >/dev/null 2>/dev/null ; do
		iptables -D INPUT -j ctdbfailover
	done
	iptables -F ctdbfailover 2>/dev/null
	iptables -X ctdbfailover 2>/dev/null
}

case "$1" in 
     #############################
     # called when ctdbd starts up
     startup)
	# make sure that we only respond to ARP messages from the NIC where
	# a particular ip address is associated.
	[ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
	    echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
	}
	cat "$CTDB_PUBLIC_ADDRESSES" | cut -d/ -f1 | while read _IP; do
		_IP_HELD=`/sbin/ip addr show | grep "inet $_IP/"`
		[ -z "$_IP_HELD" ] || {
			_IFACE=`echo $_IP_HELD | sed -e "s/.*\s//"`
			_NM=`echo $_IP_HELD | sed -e "s/.*$_IP\///" -e "s/\s.*//"`
			echo "Removing public address $_IP/$_NM from device $_IFACE"
			/sbin/ip addr del $_IP/$_NM dev $_IFACE
		}
	done
	;;


     ################################################
     # called when ctdbd wants to claim an IP address
     takeip)
	if [ $# != 4 ]; then
	   echo "must supply interface, IP and maskbits"
	   exit 1
	fi
	iface=$2
	ip=$3
	maskbits=$4

	# we make sure the interface is up first
	/sbin/ip link set $iface up || {
		 echo "Failed to bringup interface $iface"
		 exit 1
	}
	/sbin/ip addr add $ip/$maskbits brd + dev $iface || {
		 echo "Failed to add $ip/$maskbits on dev $iface"
	}
	# cope with the script being killed while we have the interface blocked
	delete_failover_block $iface $ip

	# flush our route cache
	echo 1 > /proc/sys/net/ipv4/route/flush
	;;


     ##################################################
     # called when ctdbd wants to release an IP address
     releaseip)
	if [ $# != 4 ]; then
	   echo "must supply interface, IP and maskbits"
	   exit 1
	fi

	# releasing an IP is a bit more complex than it seems. Once the IP
	# is released, any open tcp connections to that IP on this host will end
	# up being stuck. Some of them (such as NFS connections) will be unkillable
	# so we need to use the killtcp ctdb function to kill them off. We also
	# need to make sure that no new connections get established while we are 
	# doing this! So what we do is this:
	# 1) firewall this IP, so no new external packets arrive for it
	# 2) use netstat -tn to find existing connections, and kill them 
	# 3) remove the IP from the interface
	# 4) remove the firewall rule
	iface=$2
	ip=$3
	maskbits=$4

	failed=0
	# we do an extra delete to cope with the script being killed
	delete_failover_block $iface $ip
	add_failover_block $iface $ip
	kill_tcp_connections $ip

	# the ip tool will delete all secondary IPs if this is the primary. To work around
	# this _very_ annoying behaviour we have to keep a record of the secondaries and re-add
	# them afterwards. yuck
	secondaries=""
	if /sbin/ip addr list dev $iface primary | grep -q "inet $ip/$maskbits " ; then
	    secondaries=`/sbin/ip addr list dev $iface secondary | grep " inet " | awk '{print $2}'`
	fi
	/sbin/ip addr del $ip/$maskbits dev $iface || failed=1
	[ -z "$secondaries" ] || {
	    for i in $secondaries; do
		if /sbin/ip addr list dev $iface | grep -q "inet $i" ; then
		    echo "kept secondary $i on dev $iface"
		else 
		    echo "re-adding secondary address $i to dev $iface"
		    /sbin/ip addr add $i dev $iface || failed=1		
		fi
	    done
	}
	delete_failover_block $iface $ip
	[ $failed = 0 ] || {
		 echo "Failed to del $ip on dev $iface"
		 exit 1
	}

	# flush our route cache
	echo 1 > /proc/sys/net/ipv4/route/flush
	;;


     ###########################################
     # called when ctdbd has finished a recovery
     recovered)
	delete_all_failover_blocks
	;;

     ####################################
     # called when ctdbd is shutting down
     shutdown)
	delete_all_failover_blocks
	;;

     monitor)
	# make sure we dont block any ips when we are outside of recovery
	delete_all_failover_blocks

	INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES | 
		sed -e "s/^[^\t ]*[\t ]*//" -e "s/[\t ]*$//"`

	[ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES"
	[ "$CTDB_NATGW_PUBLIC_IFACE" ] && INTERFACES="$CTDB_NATGW_PUBLIC_IFACE $INTERFACES"

	INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`

	for IFACE in $INTERFACES ; do
	    # These interfaces are sometimes bond devices
	    # When we use VLANs for bond interfaces, there will only
	    # be an entry in /proc for the underlying real interface
	    REALIFACE=`echo $IFACE |sed -e 's/\..*$//'`
	    [ -f /proc/net/bonding/$REALIFACE ] && {
		grep -q 'Currently Active Slave: None' /proc/net/bonding/$REALIFACE && {
			echo "ERROR: No active slaves for bond device $REALIFACE"
			exit 1
		}
		grep -q '^MII Status: up' /proc/net/bonding/$REALIFACE || {
			echo "ERROR: public network interface $REALIFACE is down"
			exit 1
		}
		exit 0;
	    }

	    case $IFACE in 
	    ib*)
		# we dont know how to test ib links
		;;
	    *)
		[ -z "$IFACE" ] || {
		    [ "$(basename $(readlink /sys/class/net/$IFACE/device/driver))" = virtio_net ] ||
		    ethtool $IFACE | grep -q 'Link detected: yes' || {
			# On some systems, this is not successful when a
			# cable is plugged but the interface has not been
			# brought up previously. Bring the interface up and
			# try again...
			ip link set $IFACE up
			ethtool $IFACE | grep -q 'Link detected: yes' || {
			    echo "ERROR: No link on the public network interface $IFACE"
			    exit 1
			}
	    	    }
		}
		;;
	    esac
	done
	;;
    *)
	ctdb_standard_event_handler "$@"
	;;
esac

exit 0