fixed script errors in 10.interface
[metze/ctdb/wip.git] / config / events.d / 10.interface
1 #!/bin/sh
2
3 #################################
4 # interface event script for ctdb
5 # this adds/removes IPs from your 
6 # public interface
7
8 . /etc/ctdb/functions
9 loadconfig ctdb
10
11 cmd="$1"
12 shift
13
14 [ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
15         CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
16 }
17
18 [ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
19         echo "`date` No public addresses file found. Nothing to do for 10.interfaces"
20         exit 0
21 }
22
23 ################################################
24 # kill off any TCP connections with the given IP
25 kill_tcp_connections() {
26     _IP="$1"    
27     _failed=0
28     _killcount=0
29     netstat -tn |egrep "^tcp.*\s+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' | 
30     while read dest src; do
31         srcip=`echo $src | cut -d: -f1`
32         srcport=`echo $src | cut -d: -f2`
33         destip=`echo $dest | cut -d: -f1`
34         destport=`echo $dest | cut -d: -f2`
35         ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
36         _killcount=`expr $_killcount + 1`
37     done
38     [ $_failed = 0 ] || {
39         echo "`date` Failed to send killtcp control"
40         return;
41     }
42     _count=0
43     while netstat -tn |egrep "^tcp.*\s+$_IP:.*ESTABLISHED" > /dev/null; do
44         sleep 1
45         _count=`expr $_count + 1`
46         [ $_count -gt 3 ] && {
47             echo "`date` Timed out killing tcp connections for IP $_IP"
48             return;
49         }
50     done
51     echo "`date` killed $_killcount TCP connections to released IP $_IP"
52 }
53
54 case $cmd in 
55      #############################
56      # called when ctdbd starts up
57      startup)
58         # make sure that we only respond to ARP messages from the NIC where
59         # a particular ip address is associated.
60         [ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
61             echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
62         }
63         ;;
64
65
66      ################################################
67      # called when ctdbd wants to claim an IP address
68      takeip)
69         if [ $# != 3 ]; then
70            echo "`date` must supply interface, IP and maskbits"
71            exit 1
72         fi
73         iface=$1
74         ip=$2
75         maskbits=$3
76
77         # we make sure the interface is up first
78         /sbin/ip link set $iface up || {
79                  echo "`/bin/date` Failed to bringup interface $iface"
80                  exit 1
81         }
82         /sbin/ip addr add $ip/$maskbits dev $iface || {
83                  echo "`/bin/date` Failed to add $ip/$maskbits on dev $iface"
84                  exit 1
85         }
86         # cope with the script being killed while we have the interface blocked
87         /sbin/iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
88
89         # flush our route cache
90         echo 1 > /proc/sys/net/ipv4/route/flush
91         ;;
92
93
94      ##################################################
95      # called when ctdbd wants to release an IP address
96      releaseip)
97         if [ $# != 3 ]; then
98            echo "`/bin/date` must supply interface, IP and maskbits"
99            exit 1
100         fi
101
102         # releasing an IP is a bit more complex than it seems. Once the IP
103         # is released, any open tcp connections to that IP on this host will end
104         # up being stuck. Some of them (such as NFS connections) will be unkillable
105         # so we need to use the killtcp ctdb function to kill them off. We also
106         # need to make sure that no new connections get established while we are 
107         # doing this! So what we do is this:
108         # 1) firewall this IP, so no new external packets arrive for it
109         # 2) use netstat -tn to find existing connections, and kill them 
110         # 3) remove the IP from the interface
111         # 4) remove the firewall rule
112         iface=$1
113         ip=$2
114         maskbits=$3
115
116         failed=0
117         # we do an extra delete to cope with the script being killed
118         /sbin/iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
119         /sbin/iptables -I INPUT -i $iface -d $ip -j DROP
120         kill_tcp_connections $ip
121         /sbin/ip addr del $ip/$maskbits dev $iface || failed=1
122         /sbin/iptables -D INPUT -i $iface -d $ip -j DROP
123         [ $failed = 0 ] || {
124                  echo "`/bin/date` Failed to del $ip on dev $iface"
125                  exit 1
126         }
127
128         # flush our route cache
129         echo 1 > /proc/sys/net/ipv4/route/flush
130         ;;
131
132
133      ###########################################
134      # called when ctdbd has finished a recovery
135      recovered)
136         ;;
137
138      ####################################
139      # called when ctdbd is shutting down
140      shutdown)
141         ;;
142
143      monitor)
144         [ -x /usr/sbin/ethtool ] && {
145             [ -z "$CTDB_PUBLIC_INTERFACE" ] || {
146                 /usr/sbin/ethtool $CTDB_PUBLIC_INTERFACE | grep 'Link detected: yes' > /dev/null || {
147                     echo "`date` ERROR: No link on the public network interface $CTDB_PUBLIC_INTERFACE"
148                     exit 1
149                 }
150             }
151             cat $CTDB_PUBLIC_ADDRESSES | sed -e "s/^[^\t ]*[\t ]*//" -e "s/[\t ]*$//" | 
152             sort | uniq | while read IFACE; do
153                 [ -z "$IFACE" ] || {
154                     /usr/sbin/ethtool $IFACE | grep 'Link detected: yes' > /dev/null || {
155                         echo "`date` ERROR: No link on the public network interface $IFACE"
156                         exit 1
157                     }
158                 }
159             done
160         }
161         ;;
162
163 esac
164
165 exit 0
166
167
168