OpenVPN routing with BIRD on FreeBSD

If you run OpenVPN as an unprivileged user and/or in a chroot environment, it can't dynamically modify routes. This becomes a problem if you run multiple OpenVPN daemons, no matter whether they run on the same box or on different servers. When a client disconnects from one instance and later connects to another instance, you have to update your internal routing information for that client. To solve this, I've been using the BIRD Internet Routing Daemon.
The relevant part of my /usr/local/etc/openvpn.conf looks like this:

mode server
chroot /usr/local/etc/openvpn/chroot
client-connect /bin/cc.sh
client-disconnect /bin/cc.sh
script-security 2
user openvpn
group openvpn
Note that the location of the client-connect and client-disconnect script /bin/cc.sh is relative to the chroot directory /usr/local/etc/openvpn/chroot, which contains three subdirectories:
drwxr-xr-x  2 root  wheel    bin
drwxr-xr-x  2 root  wheel    ccd
drwxrwxr-x  2 root  openvpn  tmp
When an OpenVPN client connects, cc.sh reads its ip address and routes from the config file in ccd, writes this information in BIRD compatible syntax to the config file in tmp, and informs BIRD to reload its configuration.
When a client disconnects, cc.sh just empties the config file in tmp, and reloads BIRD.
My /usr/local/etc/bird.conf looks like this:
router id 10.23.42.1;
log syslog all;
filter rfc1918 {
  if net ~ 192.168.0.0/16 then accept;
  else reject;
}
protocol kernel {
  persist;
  scan time 0;
  import all;
  export all;
}
protocol device {
  scan time 0;
  import all;
  export all;
}
protocol direct {
}
protocol static {
  include "/usr/local/etc/openvpn/chroot/tmp/*.conf";
  import filter rfc1918;
  export none;
}
Usually, BIRD creates its control socket in /var/run. In order to have it somewhere else, you have to tweak /etc/rc.conf:
bird_config="/usr/local/etc/bird.conf -s /usr/local/etc/openvpn/chroot/tmp/bird.ctl"
Of course you can download my cc.sh script and put it to /usr/local/openvpn/chroot/bin.