# Get the interfaces for which CTDB has public IPs configured.
# That is, for all but the 1st line, get the 1st field.
- ctdb_ifaces=$(ctdb -Y ifaces | sed -e '1d' -e 's@^:@@' -e 's@:.*@@')
+ ctdb_ifaces=$(ctdb -X ifaces | sed -e '1d' -e 's@^|@@' -e 's@|.*@@')
# Add $ctdb_interfaces and uniquify
all_interfaces=$(echo $all_interfaces $ctdb_ifaces | tr ' ' '\n' | sort -u)
}
+get_real_iface ()
+{
+ # Output of "ip link show <iface>"
+ _iface_info="$1"
+
+ # Extract the full interface description to see if it is a VLAN
+ _t=$(echo "$_iface_info" |
+ awk 'NR == 1 { iface = $2; sub(":$", "", iface) ; \
+ print iface }')
+ case "$_t" in
+ *@*)
+ # VLAN: use the underlying interface, after the '@'
+ echo "${_t##*@}"
+ ;;
+ *)
+ # Not a regular VLAN. For backward compatibility, assume
+ # there is some other sort of VLAN that doesn't have the
+ # '@' in the output and only use what is before a '.'. If
+ # there is no '.' then this will be the whole interface
+ # name.
+ echo "${_t%%.*}"
+ esac
+}
+
monitor_interfaces()
{
get_all_interfaces
# problem with an interface then set fail=true and continue.
for iface in $all_interfaces ; do
- ip link show $iface 2>/dev/null >/dev/null || {
+ _iface_info=$(ip link show $iface 2>&1) || {
echo "ERROR: Interface $iface does not exist but it is used by public addresses."
mark_down $iface
continue
# 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
- realiface=`echo $iface |sed -e 's/\..*$//'`
+ realiface=$(get_real_iface "$_iface_info")
bi=$(get_proc "net/bonding/$realiface" 2>/dev/null) && {
echo "$bi" | grep -q 'Currently Active Slave: None' && {
echo "ERROR: No active slaves for bond device $realiface"
mark_up $iface
;;
ib*)
- # we dont know how to test ib links
+ # we don't know how to test ib links
mark_up $iface
;;
*)
return 1
}
+# Sets: iface, ip, maskbits, family
+get_iface_ip_maskbits_family ()
+{
+ _iface_in="$1"
+ ip="$2"
+ _maskbits_in="$3"
+
+ set -- $(ip_maskbits_iface "$ip")
+ if [ -n "$1" ] ; then
+ maskbits="$1"
+ iface="$2"
+ family="$3"
+
+ if [ "$iface" != "$_iface_in" ] ; then
+ printf \
+ 'WARNING: Public IP %s hosted on interface %s but VNN says %s\n' \
+ "$ip" "$iface" "$_iface_in"
+ fi
+ if [ "$maskbits" != "$_maskbits_in" ] ; then
+ printf \
+ 'WARNING: Public IP %s has %s bit netmask but VNN says %s\n' \
+ "$ip" "$maskbits" "$_maskbits_in"
+ fi
+ else
+ die "ERROR: Unable to determine interface for IP ${ip}"
+ fi
+}
+
ctdb_check_args "$@"
case "$1" in
_promote="sys/net/ipv4/conf/all/promote_secondaries"
get_proc "$_promote" >/dev/null 2>&1 || \
die "Public IPs only supported if promote_secondaries is available"
+
+ # make sure we drop any ips that might still be held if
+ # previous instance of ctdb got killed with -9 or similar
+ drop_all_public_ips
;;
#############################
}
# cope with the script being killed while we have the interface blocked
- iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
+ case "$ip" in
+ *:*) family="inet6" ;;
+ *) family="inet" ;;
+ esac
+ iptables_wrapper $family -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
- # flush our route cache
- set_proc sys/net/ipv4/route/flush 1
+ flush_route_cache
;;
# 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
+ shift
+ get_iface_ip_maskbits_family "$@"
- 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
+ iptables_wrapper $family -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
+ iptables_wrapper $family -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_wrapper $family \
+ -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
+ iptables_wrapper $family -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
- # flush our route cache
- set_proc sys/net/ipv4/route/flush 1
+ flush_route_cache
;;
##################################################
# 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
+ # 2) remove the IP from the old interface (and new interface, to be sure)
+ # 3) add the IP to the new 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
+ _oiface=$2
niface=$3
- ip=$4
- maskbits=$5
+ _ip=$4
+ _maskbits=$5
+
+ get_iface_ip_maskbits_family "$_oiface" "$_ip" "$_maskbits"
+ oiface="$iface"
- 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
+ iptables_wrapper $family -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
+ iptables_wrapper $family -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;
+ iptables_wrapper $family \
+ -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
+ iptables_wrapper $family -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
- # flush our route cache
- set_proc sys/net/ipv4/route/flush 1
+ flush_route_cache
# propagate the new mac address
ctdb gratiousarp $ip $niface