I wanted to try Ucarp, the userland daemon to use the CARP protocol, to manage a virtual address for automatic failover between two MySQL hosts.

The only problem was, I wanted to do that with Solaris shared-IP zones. They don’t really have complete (promiscuous mode) access to their IP interfaces. The interfaces are rather virtual interfaces for the global zone which are forwarded to a particular zone. So that means, ucarp has to run on the global zone as well. But how would it know which zone/interface to manage?

So I modified the ucarp sources a bit to run a little /usr/sbin/zoneadm -z <zonename> list -p before sending the `I’m alive package’. Afterwards I was thinking about making this a bit more generic to simply allow the user to provide a special check-script to ucarp, which would influence the alive state. But that’s not done yet.

So ucarp would only send it’s broadcasts when the physical interface is up AND the zone in question is alive. The configuration of the additional virtual interface for the zone is easily done with the default arguments. Just add the <zonename> as an extra parameter for the up-/down- scripts.

The if-up.sh script I use:

#!/bin/bash
# <interface name> <virtual address> <optional extra parameter>

if [ $# -gt 2 ]
then
  z_zone="zone"
fi

interface=$1
vaddr=$2
shift 2

/usr/sbin/ifconfig $interface addif $vaddr netmask + broadcast + up

if [ ! -z "$z_zone" ]
then
  # we need the virtual interface!!
  vinterface=`/usr/sbin/ifconfig -a | \
    awk '$1 !~ /^(ether|inet|lo|zone)/ { interface=$1; } $1 == "inet" && $2 == "'$vaddr'" { print substr(interface, 0, length(interface) - 1); exit; }'`

  if [ ! -z "$vinterface" ]
  then
    fgrep -s ':' <<<$vinterface

    if [ $? -eq 0 ]
    then
      /usr/sbin/ifconfig $vinterface $z_zone "$@"
    fi
  fi
fi

And the if-down.sh as well;-)

#!/bin/bash
# <interface name> <virtual address> <optional extra parameter>

interface=$1
vaddr=$2
shift 2

# we need the virtual interface!!
vinterface=`/usr/sbin/ifconfig -a | awk '$1 !~ /^(ether|inet|lo|zone)/ { interface=$1; } $1 == "inet" && $2 == "'$vaddr'" { print substr(interface, 0, length(interface) - 1); exit; }'`

if [ ! -z "$vinterface" ]
then
  fgrep -s ':' <<<$vinterface
  if [ $? -eq 0 ]
  then
    /usr/sbin/ifconfig $vinterface down unplumb
  fi
fi

I played with that and it seems to work as expected. My little patch for the curious ones is hier;-)

Have fun;-)

— Marco