CARP provides a way to build redundant, fault tolerant services using FreeBSD and standard PC hardware. It was origonaly designed after Cisco’s VRRP (Virtual Router Redundancy Protocol) but can be used to make almost any service redundant. CARP was first created in OpenBSD and then ported over to FreeBSD.
How does it work?
CARP sets up a virtual interface (carpX) on two (or more) hosts that can then share a common IP address between the hosts. The CARP interface is only active on one host at a given time but can automatically switch over to another host should a failure be detected. This allows for the common IP address to always be available. If you setup services on both hosts that are bound to the common IP address, then the services will always be availavle should a server go down.
How it’s done in FreeBSD
The following variables need to be added or changed in /etc/rc.conf
FreeBSD first needs to create the CARP interfaces. The cloned_interfaces variable is used to setup the interfaces. If you have more than one interface to setup, then separare the interface names by spaces.
cloned_interfaces="carpXX"
Add an ifconfig variable for each CARP interface that was created.
ifconfig_carpXX="vhid <interface-ID> advskew <priority> pass <password> <carp-ip-address>"
The <interface-ID> is an identifier that groups the CARP interface with it’s counterpart interface on the other hosts. The common IP address is shared with all interfaces that have the same <interface-ID>. The <interface-ID> may be anything but must match on all the hosts. The <priority> should be different on each host. The <priority> value on the master host should be less than the backup hosts. <password> is a string used to validate the CARP exchanges between the hosts. This can be any string you want but must be the same on all hosts that share a common <interface-ID>. The <carp-ip-address> is the virtual IP address that the CARP interface will have. This IP address must be in the network block assigned to one of the physical interfaces. CARP uses this IP address to figure out what physical interface to assign the CARP interface too.
Example
The following example uses CARP to create redundant interfaces on two firewall hosts, P (primary) and B (backup). These two hosts each have an internal and external interface that we would like to fail over should some thing happen to the primary host.
On the P (primary) Host.
The real physical interfaces need to be setup in /etc/rc.conf as usual for a FreeBSD server. The following ifconfig variables are used to setup an IP address of 10.0.1.2 on the external interface (bge0) and an IP address of 192.168.10.2 on the internal interface (bge1).
ifconfig_bge0="inet 10.0.1.2 netmask 255.0.0.0"
ifconfig_bge1="inet 192.168.10.2 netmask 255.255.255.0"
Create the CARP interfaces now. One for the internal interface and one for the external interface.
cloned_interfaces="carp1 carp2"
ifconfig_carp1="vhid 10 advskew 50 pass pass4carp1 10.0.1.1"
ifconfig_carp2="vhid 20 advskew 50 pass pass4carp2 192.168.10.1"
In /etc/sysctl.conf we need to add a sysctl variable. This will make sure that if one interface on a host goes down, then all the CARP interfaces will switch over. Without this is would be possible for the internal interface to be working on the primary and the external on the backup.
net.inet.carp.preempt=1
On the B (backup) Host.
Add the ifconfig variables to /etc/rc.conf for the physical interfaces.
ifconfig_bge0="inet 10.0.1.3 netmask 255.0.0.0"
ifconfig_bge1="inet 192.168.10.3 netmask 255.255.255.0"
Create the carp interfaces on the backup host. Notice that these variables are exactly the same as the primary ones except for the advskew <priority>. This value is what tells the system the it is the backup host.
cloned_interfaces="carp1 carp2"
ifconfig_carp1="vhid 10 advskew 80 pass pass4carp1 10.0.1.1"
ifconfig_carp2="vhid 20 advskew 80 pass pass4carp2 192.168.10.1"
Include the sysctl variable into /etc/sysctl.conf to turn on CARP preemption so that all the interfaces fail over at the same time.
net.inet.carp.preempt=1
Useful sysctl variables
net.inet.carp.log
0 = Disable logging
1 = Enable logging of bad CARP protocol packets
Over 1 = Enable logging of CARP state changes
net.inet.carp.preempt
Allows the virtual hosts to preempt each other. This makes it possable for all interfaces to fail over at the same time.
net.inet.carp.allow
Accept incoming CARP packets. (On by default)