Add a variable CTDB_CHECK_SWAP_IS_NOT_USED="yes"
[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 . $CTDB_BASE/functions
9 loadconfig
10
11 [ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
12         CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
13 }
14
15 [ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
16         echo "No public addresses file found. Nothing to do for 10.interfaces"
17         exit 0
18 }
19
20 monitor_interfaces()
21 {
22         local INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES |
23                 sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//"`
24
25         [ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES"
26         [ "$CTDB_NATGW_PUBLIC_IFACE" ] && INTERFACES="$CTDB_NATGW_PUBLIC_IFACE $INTERFACES"
27
28         local IFACES=`ctdb ifaces -Y | grep -v '^:Name:LinkStatus:References:'`
29
30         local I
31         local IFACE
32
33         for I in $IFACES; do
34                 IFACE=`echo -n "$I" | cut -d ':' -f2`
35                 INTERFACES="$IFACE $INTERFACES"
36         done
37
38         INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`
39
40         local fail=0
41         local force_fail=0
42         local ok=0
43         for IFACE in $INTERFACES ; do
44
45             local OLDLINK=`echo -n "$IFACES" | grep "^:$IFACE:" | cut -d ':' -f3 | xargs`
46             test -z "$OLDLINK" && {
47                 force_fail=1
48             }
49
50             # These interfaces are sometimes bond devices
51             # When we use VLANs for bond interfaces, there will only
52             # be an entry in /proc for the underlying real interface
53             local REALIFACE=`echo $IFACE |sed -e 's/\..*$//'`
54             [ -f /proc/net/bonding/$REALIFACE ] && {
55                 grep -q 'Currently Active Slave: None' /proc/net/bonding/$REALIFACE && {
56                         echo "ERROR: No active slaves for bond device $REALIFACE"
57                         fail=1
58                         test -n "$OLDLINK" && {
59                                 ctdb setifacelink $IFACE down
60                         }
61                         continue;
62                 }
63                 grep -q '^MII Status: up' /proc/net/bonding/$REALIFACE || {
64                         echo "ERROR: public network interface $REALIFACE is down"
65                         fail=1
66                         test -n "$OLDLINK" && {
67                                 ctdb setifacelink $IFACE down
68                         }
69                         continue;
70                 }
71                 test -n "$OLDLINK" && {
72                         ok=1 # we only set ok for interfaces known to ctdbd
73                         ctdb setifacelink $IFACE up
74                 }
75                 return 0;
76             }
77
78             case $IFACE in
79             ib*)
80                 # we dont know how to test ib links
81                 ;;
82             *)
83                 [ -z "$IFACE" ] || {
84                     ethtool $IFACE | grep -q 'Link detected: yes' || {
85                         # On some systems, this is not successful when a
86                         # cable is plugged but the interface has not been
87                         # brought up previously. Bring the interface up and
88                         # try again...
89                         /sbin/ip link set $IFACE up
90                         ethtool $IFACE | grep -q 'Link detected: yes' || {
91                             echo "ERROR: No link on the public network interface $IFACE"
92                             fail=1
93                             test -n "$OLDLINK" && {
94                                 ctdb setifacelink $IFACE down
95                             }
96                             continue
97                         }
98                     }
99                     test -n "$OLDLINK" && {
100                         ok=1 # we only set ok for interfaces known to ctdbd
101                         ctdb setifacelink $IFACE up
102                     }
103                 }
104                 ;;
105             esac
106
107         done
108
109         test x"$fail" = x"0" && {
110                 return 0;
111         }
112
113         test x"$force_fail" != x"0" && {
114                 return 1;
115         }
116
117         test x"$ok" = x"1" && {
118                 return 2;
119         }
120
121         return 1;
122 }
123
124 case "$1" in 
125      #############################
126      # called when ctdbd starts up
127      init)
128         # make sure that we only respond to ARP messages from the NIC where
129         # a particular ip address is associated.
130         [ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
131             echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
132         }
133         cat "$CTDB_PUBLIC_ADDRESSES" | cut -d/ -f1 | while read _IP; do
134                 _IP_HELD=`/sbin/ip addr show | grep "inet $_IP/"`
135                 [ -z "$_IP_HELD" ] || {
136                         _IFACE=`echo $_IP_HELD | sed -e "s/.*\s//"`
137                         _NM=`echo $_IP_HELD | sed -e "s/.*$_IP\///" -e "s/\s.*//"`
138                         echo "Removing public address $_IP/$_NM from device $_IFACE"
139                         /sbin/ip addr del $_IP/$_NM dev $_IFACE
140                 }
141         done
142         ;;
143
144      #############################
145      # called after ctdbd has done its initial recovery
146      # and we start the services to become healthy
147      startup)
148         monitor_interfaces
149
150         ;;
151
152
153      ################################################
154      # called when ctdbd wants to claim an IP address
155      takeip)
156         if [ $# != 4 ]; then
157            echo "must supply interface, IP and maskbits"
158            exit 1
159         fi
160         iface=$2
161         ip=$3
162         maskbits=$4
163
164         add_ip_to_iface $iface $ip $maskbits || {
165                 exit 1;
166         }
167
168         # cope with the script being killed while we have the interface blocked
169         iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
170
171         # flush our route cache
172         echo 1 > /proc/sys/net/ipv4/route/flush
173         ;;
174
175
176      ##################################################
177      # called when ctdbd wants to release an IP address
178      releaseip)
179         if [ $# != 4 ]; then
180            echo "must supply interface, IP and maskbits"
181            exit 1
182         fi
183
184         # releasing an IP is a bit more complex than it seems. Once the IP
185         # is released, any open tcp connections to that IP on this host will end
186         # up being stuck. Some of them (such as NFS connections) will be unkillable
187         # so we need to use the killtcp ctdb function to kill them off. We also
188         # need to make sure that no new connections get established while we are 
189         # doing this! So what we do is this:
190         # 1) firewall this IP, so no new external packets arrive for it
191         # 2) use netstat -tn to find existing connections, and kill them 
192         # 3) remove the IP from the interface
193         # 4) remove the firewall rule
194         iface=$2
195         ip=$3
196         maskbits=$4
197
198         failed=0
199         # we do an extra delete to cope with the script being killed
200         iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
201         iptables -I INPUT -i $iface -d $ip -j DROP
202         kill_tcp_connections $ip
203
204         delete_ip_from_iface $iface $ip $maskbits || {
205                 iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
206                 exit 1;
207         }
208
209         iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
210
211         # flush our route cache
212         echo 1 > /proc/sys/net/ipv4/route/flush
213         ;;
214
215      ##################################################
216      # called when ctdbd wants to update an IP address
217      updateip)
218         if [ $# != 5 ]; then
219            echo "must supply old interface, new interface, IP and maskbits"
220            exit 1
221         fi
222
223         # moving an IP is a bit more complex than it seems.
224         # First we drop all traffic on the old interface.
225         # Then we try to add the ip to the new interface and before
226         # we finally remove it from the old interface.
227         #
228         # 1) firewall this IP, so no new external packets arrive for it
229         # 2) add the IP to the new interface
230         # 3) remove the IP from the old interface
231         # 4) remove the firewall rule
232         # 5) use ctdb gratiousarp to propagate the new mac address
233         # 6) use netstat -tn to find existing connections, and tickle them
234         oiface=$2
235         niface=$3
236         ip=$4
237         maskbits=$5
238
239         failed=0
240         # we do an extra delete to cope with the script being killed
241         iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
242         iptables -I INPUT -i $oiface -d $ip -j DROP
243
244         # we make sure the interface is up first
245         add_ip_to_iface $niface $ip $maskbits || {
246                 iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
247                 exit 1;
248         }
249
250         delete_ip_from_iface $oiface $ip $maskbits || {
251                 delete_ip_from_iface $niface $ip $maskbits
252                 iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
253                 exit 1;
254         }
255
256         # cope with the script being killed while we have the interface blocked
257         iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
258
259         # flush our route cache
260         echo 1 > /proc/sys/net/ipv4/route/flush
261
262         # propagate the new mac address
263         ctdb gratiousarp $ip $niface
264
265         # tickle all existing connections, so that dropped packets
266         # are retransmited and the tcp streams work
267
268         tickle_tcp_connections $ip
269
270         ;;
271
272
273      ###########################################
274      # called when ctdbd has finished a recovery
275      recovered)
276         ;;
277
278      ####################################
279      # called when ctdbd is shutting down
280      shutdown)
281         ;;
282
283      monitor)
284         monitor_interfaces
285         ret=$?
286
287         test x"$ret" = x"2" && {
288                 test x"$CTDB_PARTIALLY_ONLINE_INTERFACES" != x"yes" && {
289                         exit 1;
290                 }
291                 # as long as we have one interface available don't become
292                 # unhealthy
293                 ret=0
294         }
295
296         test x"$ret" != x"0" && {
297                 exit 1;
298         }
299         ;;
300     *)
301         ctdb_standard_event_handler "$@"
302         ;;
303 esac
304
305 exit 0
306