1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-26 10:04:02 +03:00
Ronnie Sahlberg d97e42183e bonding mode 4 monitoring:
we can not just check if MII Status is up for bonding mode 4, since the kernel will always report the bond device as UP
even if all cables are disconneccted.

For mode 4, ignore the status of the bond device and instead chek if at least one slave interface is up
when determining if the device is good or bad

(This used to be ctdb commit a6930cec6d9503dba18b9d4839d87a1c1a8ddba2)
2011-04-13 09:05:58 +10:00

302 lines
7.8 KiB
Bash
Executable File

#!/bin/sh
#################################
# interface event script for ctdb
# this adds/removes IPs from your
# public interface
. $CTDB_BASE/functions
loadconfig
[ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
}
[ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
echo "No public addresses file found. Nothing to do for 10.interfaces"
exit 0
}
monitor_interfaces()
{
local INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES |
sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//"`
[ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES"
[ "$CTDB_NATGW_PUBLIC_IFACE" ] && INTERFACES="$CTDB_NATGW_PUBLIC_IFACE $INTERFACES"
local IFACES=`ctdb ifaces -Y | grep -v '^:Name:LinkStatus:References:'`
local I
local IFACE
for I in $IFACES; do
IFACE=`echo -n "$I" | cut -d ':' -f2`
INTERFACES="$IFACE $INTERFACES"
done
INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`
local fail=0
local ok=0
for IFACE in $INTERFACES ; do
ip addr show $IFACE 2>/dev/null >/dev/null || {
echo Interface $IFACE does not exist but it is used by public addresses.
exit 1
}
# These interfaces are sometimes bond devices
# When we use VLANs for bond interfaces, there will only
# be an entry in /proc for the underlying real interface
local REALIFACE=`echo $IFACE |sed -e 's/\..*$//'`
[ -f /proc/net/bonding/$REALIFACE ] && {
grep -q 'Currently Active Slave: None' /proc/net/bonding/$REALIFACE && {
echo "ERROR: No active slaves for bond device $REALIFACE"
fail=1
ctdb setifacelink $IFACE down
continue;
}
grep -q '^MII Status: up' /proc/net/bonding/$REALIFACE || {
echo "ERROR: public network interface $REALIFACE is down"
fail=1
ctdb setifacelink $IFACE down
continue;
}
grep -q '^Bonding Mode: IEEE 802.3ad Dynamic link aggregation' /proc/net/bonding/$REALIFACE && {
grep 'MII Status:' /proc/net/bonding/$REALIFACE | tail -n +2 | grep -q '^MII Status: up' || {
echo No active slaves for 802.ad bond device $REALIFACE
ctdb setifacelink $IFACE down
fail=1
continue
}
}
ok=1 # we only set ok for interfaces known to ctdbd
ctdb setifacelink $IFACE up
continue;
}
case $IFACE in
lo*)
# loopback is always working
ok=1 # we only set ok for interfaces known to ctdbd
ctdb setifacelink $IFACE up
;;
ib*)
# we dont know how to test ib links
ok=1 # we only set ok for interfaces known to ctdbd
ctdb setifacelink $IFACE up
;;
*)
[ -z "$IFACE" ] || {
[ "$(basename $(readlink /sys/class/net/$IFACE/device/driver) 2>/dev/null)" = virtio_net ] ||
ethtool $IFACE | grep -q 'Link detected: yes' || {
# On some systems, this is not successful when a
# cable is plugged but the interface has not been
# brought up previously. Bring the interface up and
# try again...
/sbin/ip link set $IFACE up
ethtool $IFACE | grep -q 'Link detected: yes' || {
echo "ERROR: No link on the public network interface $IFACE"
fail=1
ctdb setifacelink $IFACE down
continue
}
}
ok=1 # we only set ok for interfaces known to ctdbd
ctdb setifacelink $IFACE up
}
;;
esac
done
test x"$fail" = x"0" && {
return 0;
}
test x"$ok" = x"1" && {
return 2;
}
return 1;
}
case "$1" in
#############################
# called when ctdbd starts up
init)
# make sure that we only respond to ARP messages from the NIC where
# a particular ip address is associated.
[ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
}
;;
#############################
# called after ctdbd has done its initial recovery
# and we start the services to become healthy
startup)
# Assume all links are good initially
INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`
for IFACE in $INTERFACES ; do
ctdb setifacelink $IFACE down
done
monitor_interfaces
;;
################################################
# called when ctdbd wants to claim an IP address
takeip)
if [ $# != 4 ]; then
echo "must supply interface, IP and maskbits"
exit 1
fi
iface=$2
ip=$3
maskbits=$4
add_ip_to_iface $iface $ip $maskbits || {
exit 1;
}
# cope with the script being killed while we have the interface blocked
iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
# flush our route cache
echo 1 > /proc/sys/net/ipv4/route/flush
;;
##################################################
# called when ctdbd wants to release an IP address
releaseip)
if [ $# != 4 ]; then
echo "must supply interface, IP and maskbits"
exit 1
fi
# releasing an IP is a bit more complex than it seems. Once the IP
# is released, any open tcp connections to that IP on this host will end
# up being stuck. Some of them (such as NFS connections) will be unkillable
# so we need to use the killtcp ctdb function to kill them off. We also
# need to make sure that no new connections get established while we are
# doing this! So what we do is this:
# 1) firewall this IP, so no new external packets arrive for it
# 2) use netstat -tn to find existing connections, and kill them
# 3) remove the IP from the interface
# 4) remove the firewall rule
iface=$2
ip=$3
maskbits=$4
failed=0
# we do an extra delete to cope with the script being killed
iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
iptables -I INPUT -i $iface -d $ip -j DROP
kill_tcp_connections $ip
delete_ip_from_iface $iface $ip $maskbits || {
iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
exit 1;
}
iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
# flush our route cache
echo 1 > /proc/sys/net/ipv4/route/flush
;;
##################################################
# called when ctdbd wants to update an IP address
updateip)
if [ $# != 5 ]; then
echo "must supply old interface, new interface, IP and maskbits"
exit 1
fi
# moving an IP is a bit more complex than it seems.
# First we drop all traffic on the old interface.
# Then we try to add the ip to the new interface and before
# we finally remove it from the old interface.
#
# 1) firewall this IP, so no new external packets arrive for it
# 2) add the IP to the new interface
# 3) remove the IP from the old interface
# 4) remove the firewall rule
# 5) use ctdb gratiousarp to propagate the new mac address
# 6) use netstat -tn to find existing connections, and tickle them
oiface=$2
niface=$3
ip=$4
maskbits=$5
failed=0
# we do an extra delete to cope with the script being killed
iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
iptables -I INPUT -i $oiface -d $ip -j DROP
delete_ip_from_iface $oiface $ip $maskbits 2>/dev/null
delete_ip_from_iface $niface $ip $maskbits 2>/dev/null
add_ip_to_iface $niface $ip $maskbits || {
iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
exit 1;
}
# cope with the script being killed while we have the interface blocked
iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
# flush our route cache
echo 1 > /proc/sys/net/ipv4/route/flush
# propagate the new mac address
ctdb gratiousarp $ip $niface
# tickle all existing connections, so that dropped packets
# are retransmited and the tcp streams work
tickle_tcp_connections $ip
;;
###########################################
# called when ctdbd has finished a recovery
recovered)
;;
####################################
# called when ctdbd is shutting down
shutdown)
;;
monitor)
monitor_interfaces
ret=$?
test x"$ret" = x"2" && {
test x"$CTDB_PARTIALLY_ONLINE_INTERFACES" != x"yes" && {
exit 1;
}
# as long as we have one interface available don't become
# unhealthy
ret=0
}
test x"$ret" != x"0" && {
exit 1;
}
;;
*)
ctdb_standard_event_handler "$@"
;;
esac
exit 0