3 #################################
4 # interface event script for ctdb
5 # this adds/removes IPs from your
14 [ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
15 CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
18 [ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
19 echo "`date` No public addresses file found. Nothing to do for 10.interfaces"
23 ################################################
24 # kill off any TCP connections with the given IP
25 kill_tcp_connections() {
30 connfile="$CTDB_BASE/state/connections.$_IP"
31 netstat -tn |egrep "^tcp.*\s+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
32 while read dest src; do
33 srcip=`echo $src | cut -d: -f1`
34 srcport=`echo $src | cut -d: -f2`
35 destip=`echo $dest | cut -d: -f1`
36 destport=`echo $dest | cut -d: -f2`
37 ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
38 echo "`date` Killing TCP connection $srcip:$srcport $destip:$destport"
39 _killcount=`expr $_killcount + 1`
43 echo "`date` Failed to send killtcp control"
46 [ $_killcount -gt 0 ] || {
50 while netstat -tn |egrep "^tcp.*\s+$_IP:.*ESTABLISHED" > /dev/null; do
52 _count=`expr $_count + 1`
53 [ $_count -gt 3 ] && {
54 echo "`date` Timed out killing tcp connections for IP $_IP"
58 echo "`date` killed $_killcount TCP connections to released IP $_IP"
62 #############################
63 # called when ctdbd starts up
65 # make sure that we only respond to ARP messages from the NIC where
66 # a particular ip address is associated.
67 [ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
68 echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
70 cat "$CTDB_PUBLIC_ADDRESSES" | cut -d/ -f1 | while read _IP; do
71 _IP_HELD=`/sbin/ip addr show | grep "inet $_IP/"`
72 [ -z "$_IP_HELD" ] || {
73 _IFACE=`echo $_IP_HELD | sed -e "s/.*\s//"`
74 _NM=`echo $_IP_HELD | sed -e "s/.*$_IP\///" -e "s/\s.*//"`
75 echo "`date` Removing public address $_IP/$_NM from device $_IFACE"
76 /sbin/ip addr del $_IP/$_NM dev $_IFACE
82 ################################################
83 # called when ctdbd wants to claim an IP address
86 echo "`date` must supply interface, IP and maskbits"
93 # we make sure the interface is up first
94 /sbin/ip link set $iface up || {
95 echo "`/bin/date` Failed to bringup interface $iface"
98 /sbin/ip addr add $ip/$maskbits dev $iface || {
99 echo "`/bin/date` Failed to add $ip/$maskbits on dev $iface"
102 # cope with the script being killed while we have the interface blocked
103 /sbin/iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
105 # flush our route cache
106 echo 1 > /proc/sys/net/ipv4/route/flush
110 ##################################################
111 # called when ctdbd wants to release an IP address
114 echo "`/bin/date` must supply interface, IP and maskbits"
118 # releasing an IP is a bit more complex than it seems. Once the IP
119 # is released, any open tcp connections to that IP on this host will end
120 # up being stuck. Some of them (such as NFS connections) will be unkillable
121 # so we need to use the killtcp ctdb function to kill them off. We also
122 # need to make sure that no new connections get established while we are
123 # doing this! So what we do is this:
124 # 1) firewall this IP, so no new external packets arrive for it
125 # 2) use netstat -tn to find existing connections, and kill them
126 # 3) remove the IP from the interface
127 # 4) remove the firewall rule
133 # we do an extra delete to cope with the script being killed
134 /sbin/iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
135 /sbin/iptables -I INPUT -i $iface -d $ip -j DROP
136 kill_tcp_connections $ip
138 # the ip tool will delete all secondary IPs if this is the primary. To work around
139 # this _very_ annoying behaviour we have to keep a record of the secondaries and re-add
140 # them afterwards. yuck
142 if /sbin/ip addr list dev $iface primary | grep "inet $ip/$maskbits " > /dev/null; then
143 secondaries=`/sbin/ip addr list dev $iface secondary | grep " inet " | awk '{print $2}'`
145 /sbin/ip addr del $ip/$maskbits dev $iface || failed=1
146 [ -z "$secondaries" ] || {
147 for i in $secondaries; do
148 if /sbin/ip addr list dev $iface | grep "inet $i" > /dev/null; then
149 echo "`date` kept secondary $i on dev $iface"
151 echo "`date` re-adding secondary address $i to dev $iface"
152 /sbin/ip addr add $i dev $iface || failed=1
156 /sbin/iptables -D INPUT -i $iface -d $ip -j DROP
158 echo "`/bin/date` Failed to del $ip on dev $iface"
162 # flush our route cache
163 echo 1 > /proc/sys/net/ipv4/route/flush
167 ###########################################
168 # called when ctdbd has finished a recovery
172 ####################################
173 # called when ctdbd is shutting down
178 [ -x /usr/sbin/ethtool ] && {
179 [ -z "$CTDB_PUBLIC_INTERFACE" ] || {
180 /usr/sbin/ethtool $CTDB_PUBLIC_INTERFACE | grep 'Link detected: yes' > /dev/null || {
181 echo "`date` ERROR: No link on the public network interface $CTDB_PUBLIC_INTERFACE"
185 cat $CTDB_PUBLIC_ADDRESSES | sed -e "s/^[^\t ]*[\t ]*//" -e "s/[\t ]*$//" |
186 sort | uniq | while read IFACE; do
188 /usr/sbin/ethtool $IFACE | grep 'Link detected: yes' > /dev/null || {
189 echo "`date` ERROR: No link on the public network interface $IFACE"