Note: originally I posted this over at freebsdforums.org, but moved here due to low attendance.

DISCLAIMER: I don't claim that this is a foolproof way to accomplish failover for your specific situation - but the state daemon can be used for this.

For years I used a FreeBSD router with static routes to manage a growing internal networkand, for the most part, it was very effective. However, adding routes and maintaining the changes quickly became a pain - a change to my FreeBSD router required routes to be added or removed from 2 Cisco devices I was using internally as well - a 2600 and a 7120.

So, mostly to reduce the amount of maintenance, I set up the openospfd daemon

So that allowed me to make changes to my FreeBSD router that would be propagated to my other network devices. I now use that FreeBSD router as the gateway for many internal subnets, so by adding an alias IP to the router the directly connected subnet is then advertised to it's neighbors and that greatly reduces the amount of running around a new subnet took to setup. However, I should also recommend that you blackhole the broadcast address of those subnets if you don't need them.

It is not terribly important, but I also configured my edge routers to distribute the gateway address to my FreeBSD routers at this point. This was just part of my move to redundancy (I am using 2 Cisco 7206 VXRs as my edge routers) and this distributes the routes to both FreeBSD routers and the 2600 and 7120.

For about a year I've been using openospfd and it's very stable, for me at least, and making changes is painless. After a few months I built a second, identical, machine to act as a backup, but didn't spend too much time on an automatic failover solution.

But, until I implemented a failover system, I was still basically looking at a single point of failure. So I decided to try out ifstated which I had played with but never really experimented with much.

Ifstated, which is available in the ports collection, allows you to use conditional statements to trigger "states" during which you can run scripts or pass commands. I installed ifstated on the second FreeBSD router (which has openospfd installed with a similar config). In this implementation I have a "master" router and a "slave" that checks the master and will assume it's aliases (which subnets use as their gateways). I was very careful to never assign one of the "real" IPs on my routers as the gateway address of a device. I wanted to be able to bring up the alias IPs on my slave router
without having to worry about removing the actual IPs from the master.

To get this installed you'll need to install from ports and add the following to your
/etc/rc.conf:

ifstated_enable="YES"

I only need 2 states - a primary state and a backup state. To implement this I setup
my ifstated.conf like this:

# indicates that the initial state is primary
init-state primary

# the evaluations. I don't believe that there is a restriction on the kind of
# evaluation that is conducted. You could evaulate whether a file existed or
# check the date, I don't believe it matters.

state primary {
# things to run when the state is initialized
init {
run "'Changing state to primary!'"
}
# because we want to check those interfaces and if they go down trigger a state change
# note the expression "!" indicating "not"
if ! ( $pingCheck1 && $pingCheck2 ) {
# so, if both fail change state
set-state backup
}
}

state backup {
init {
# when this state initializes run the script to add those alias IPs
run "/path/to/script/changetobackup.sh 'Changing state to backup!'"
}
# continue to evaluate those interfaces in case they return
if ( $pingCheck1 && $pingCheck2 ) {
# I had to remove those aliases here because when I had it run during the primary
# state's init{} it would throw errors and crash when starting up because those aliases
# don't exist when the daemon starts. This could be solved with a third state, but I didn't require that.
run "/path/to/script/changetorprimary.sh 'Reverting to Primary State from Backup State!'"
set-state primary
}
}

this does a ping on the primary IPs on my master router's dc0 and dc1 interfaces and, if it can't hit them, changes state to backup. When the primary state initializes it simply echoes the state. After the evaluation fails, and the state changes to backup, it executes a script that contains a list of alias IPs to add to the slave's NIC. Also during this backup state the evaluation continues. If it can hit both interfaces on the master router it executes a script to remove those alias IPs added in the "changetobackup.sh"
script prior to resuming the primary state. This file is highly customizable - google it and you'll find many examples illustrating how you can do different things here.

So that's my how-to. While there are other means of accomplishing what I've done, I found that
this method is accessible to both hardened BSD veterans as well as those relatively new to the
environment. Additionally be aware that this is by no means the limit of ifstated, which has the
capability to perform all sorts of evaluations and trigger events (scripts/commands/etc) when
they occur.

My hardware for the FreeBSD routers were identical Dell Power Edge 2300 servers with 4-port DLink
cards and 1 GB RAM each. Each server routes traffic at a rate of approximately 45 Mbps with very
low load. In the future I plan to evaluate the same system on the 64-bit release of FreeBSD.