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