3 #################################
4 # interface event script for ctdb
5 # this adds/removes IPs from your
8 [ -n "$CTDB_BASE" ] || \
9 export CTDB_BASE
=$
(cd -P $
(dirname "$0") ; dirname "$PWD")
11 .
$CTDB_BASE/functions
14 [ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
15 CTDB_PUBLIC_ADDRESSES
=$CTDB_BASE/public_addresses
18 [ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
19 if [ "$1" = "init" ]; then
20 echo "No public addresses file found. Nothing to do for 10.interfaces"
25 # This sets $all_interfaces as a side-effect.
28 # Get all the interfaces listed in the public_addresses file
29 all_interfaces
=$
(sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//" $CTDB_PUBLIC_ADDRESSES)
31 # Add some special interfaces if they're defined
32 [ "$CTDB_PUBLIC_INTERFACE" ] && all_interfaces
="$CTDB_PUBLIC_INTERFACE $all_interfaces"
34 # Get the interfaces for which CTDB has public IPs configured.
35 # That is, for all but the 1st line, get the 1st field.
36 ctdb_ifaces
=$
(ctdb
-X ifaces |
sed -e '1d' -e 's@^|@@' -e 's@|.*@@')
38 # Add $ctdb_interfaces and uniquify
39 all_interfaces
=$
(echo $all_interfaces $ctdb_ifaces |
tr ' ' '\n' |
sort -u)
46 down_interfaces_found
=false
47 up_interfaces_found
=false
49 # Note that this loop must not exit early. It must process
50 # all interfaces so that the correct state for each interface
51 # is set in CTDB using setifacelink.
52 for _iface
in $all_interfaces ; do
53 if interface_monitor
"$_iface" ; then
54 up_interfaces_found
=true
55 ctdb setifacelink
"$_iface" up
>/dev
/null
2>&1
57 down_interfaces_found
=true
58 ctdb setifacelink
"$_iface" down
>/dev
/null
2>&1
62 if ! $down_interfaces_found ; then
66 if ! $up_interfaces_found ; then
70 if [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" != "yes" ]; then
77 # Sets: iface, ip, maskbits, family
78 get_iface_ip_maskbits_family
()
84 set -- $
(ip_maskbits_iface
"$ip")
90 if [ "$iface" != "$_iface_in" ] ; then
92 'WARNING: Public IP %s hosted on interface %s but VNN says %s\n' \
93 "$ip" "$iface" "$_iface_in"
95 if [ "$maskbits" != "$_maskbits_in" ] ; then
97 'WARNING: Public IP %s has %s bit netmask but VNN says %s\n' \
98 "$ip" "$maskbits" "$_maskbits_in"
101 die
"ERROR: Unable to determine interface for IP ${ip}"
109 # make sure that we only respond to ARP messages from the NIC where
110 # a particular ip address is associated.
111 get_proc sys
/net
/ipv
4/conf
/all
/arp_filter
>/dev
/null
2>&1 && {
112 set_proc sys
/net
/ipv
4/conf
/all
/arp_filter
1
115 _promote
="sys/net/ipv4/conf/all/promote_secondaries"
116 get_proc
"$_promote" >/dev
/null
2>&1 || \
117 die
"Public IPs only supported if promote_secondaries is available"
119 # make sure we drop any ips that might still be held if
120 # previous instance of ctdb got killed with -9 or similar
133 add_ip_to_iface
$iface $ip $maskbits ||
{
137 # cope with the script being killed while we have the interface blocked
139 *:*) family
="inet6" ;;
142 iptables_wrapper
$family -D INPUT
-i $iface -d $ip -j DROP
2> /dev
/null
148 # releasing an IP is a bit more complex than it seems. Once the IP
149 # is released, any open tcp connections to that IP on this host will end
150 # up being stuck. Some of them (such as NFS connections) will be unkillable
151 # so we need to use the killtcp ctdb function to kill them off. We also
152 # need to make sure that no new connections get established while we are
153 # doing this! So what we do is this:
154 # 1) firewall this IP, so no new external packets arrive for it
155 # 2) use netstat -tn to find existing connections, and kill them
156 # 3) remove the IP from the interface
157 # 4) remove the firewall rule
159 get_iface_ip_maskbits_family
"$@"
161 # we do an extra delete to cope with the script being killed
162 iptables_wrapper
$family -D INPUT
-i $iface -d $ip -j DROP
2> /dev
/null
163 iptables_wrapper
$family -I INPUT
-i $iface -d $ip -j DROP
164 kill_tcp_connections
$ip
166 delete_ip_from_iface
$iface $ip $maskbits ||
{
167 iptables_wrapper
$family \
168 -D INPUT
-i $iface -d $ip -j DROP
2> /dev
/null
172 iptables_wrapper
$family -D INPUT
-i $iface -d $ip -j DROP
2> /dev
/null
178 # moving an IP is a bit more complex than it seems.
179 # First we drop all traffic on the old interface.
180 # Then we try to add the ip to the new interface and before
181 # we finally remove it from the old interface.
183 # 1) firewall this IP, so no new external packets arrive for it
184 # 2) remove the IP from the old interface (and new interface, to be sure)
185 # 3) add the IP to the new interface
186 # 4) remove the firewall rule
187 # 5) use ctdb gratiousarp to propagate the new mac address
188 # 6) use netstat -tn to find existing connections, and tickle them
194 get_iface_ip_maskbits_family
"$_oiface" "$_ip" "$_maskbits"
197 # we do an extra delete to cope with the script being killed
198 iptables_wrapper
$family -D INPUT
-i $oiface -d $ip -j DROP
2> /dev
/null
199 iptables_wrapper
$family -I INPUT
-i $oiface -d $ip -j DROP
201 delete_ip_from_iface
$oiface $ip $maskbits 2>/dev
/null
202 delete_ip_from_iface
$niface $ip $maskbits 2>/dev
/null
204 add_ip_to_iface
$niface $ip $maskbits ||
{
205 iptables_wrapper
$family \
206 -D INPUT
-i $oiface -d $ip -j DROP
2> /dev
/null
210 # cope with the script being killed while we have the interface blocked
211 iptables_wrapper
$family -D INPUT
-i $oiface -d $ip -j DROP
2> /dev
/null
215 # propagate the new mac address
216 ctdb gratiousarp
$ip $niface
218 # tickle all existing connections, so that dropped packets
219 # are retransmited and the tcp streams work
220 tickle_tcp_connections
$ip
224 monitor_interfaces ||
exit 1
227 ctdb_standard_event_handler
"$@"