2 years ago I made a post about creating a high available system with KVM/Qemu and Bird.
Although I still use bird, I have tried it out using FreeBSD Jails and the bHyve hypervisor.

The bird setup is still the same, so you find it on the previous post.

For this setup you need Jails and PF, which are both installed by default.
Insert into the rc.conf:
jail_enable="YES"
pf_enabled="YES"
pf_rules="/usr/local/etc/pf.conf"

with this you have access to PF and Jails.

Kernel

For the networking I use VIMAGE, which isn’t available in the kernel and needs to be build.
You need to fetch the kernel sources and create a new kernel config: /usr/src/sys/amd64/conf/CUSTOM
include GENERIC
ident CUSTOM
options VIMAGE # VNET/Vimage support
options RACCT # Resource containers
options RCTL # same as above

This creates a new kernelconfig with the delta of the GENERIC kernel.

cd /usr/src
make buildkernel KERNCONF=CUSTOM
make installkernel KERNCONF=CUSTOM

With this we have our kernel.

Networking

We need NAT for this config to work.

In the /etc/rc.conf file we add:

cloned_interfaces="bridge0"
ifconfig_bridge0="inet 10.0.0.1 netmask 255.255.255.0"
ifconfig_bridge0_ipv6="inet6 2a02:898:166:d::1 prefixlen 64"

In the PF config file: /usr/local/etc/pf.conf

binat on em0 from 10.0.0.38/32 to any -> 185.52.224.38/32
nat on em0 from bridge0 to any -> 94.142.244.33

Jail

It’s pretty strait forward, create a ZFS volume with where you want your container:

zfs create zroot/jail/<container>

And create a file called: /etc/jail.conf
with the following config

allow.raw_sockets = "0";
allow.set_hostname = "0";
allow.sysvipc = "1";
allow.mount.devfs;
host.hostname = "${name}";
path = "/zroot/jail/${name}";
#mount.fstab = "/zroot/jail/etc/fstab.${name}";
mount.devfs = "1";
devfs_ruleset = "4";
exec.consolelog = "/var/log/jail_${name}_console.log";
<container> {
$if = "38";
$ip_addr = "10.0.0.${if}"; # Jail ip address
$ip_addr_pub = "185.52.224.${if}"; # Jail ip address
$ip_route = "10.0.0.1"; # Gateway or host's ip address
$ip_mask = "255.255.255.0"; # Netmask
$ip6_addr = "2a02:898:166:d::${if}"; # Jail ip address
$ip6_addr_pub = "2a02:898:166::${if}"; # Jail ip address
$ip6_route = "2a02:898:166:d::1"; # Gateway or host's ip address
$ip6_mask = "64"; # Netmask
vnet;
vnet.interface = "epair${if}b";
# Commands to run on host before jail is created
exec.prestart = "ifconfig epair${if} create up";
exec.prestart += "ifconfig epair${if}a up";
exec.prestart += "ifconfig bridge0 addm epair${if}a up";
# Commands to run in jail after it is created
exec.start = "/sbin/ifconfig lo0 127.0.0.1 up";
exec.start += "/sbin/ifconfig epair${if}b up";
exec.start += "/sbin/ifconfig epair${if}b ${ip_addr} netmask ${ip_mask} up";
exec.start += "/sbin/ifconfig epair${if}b inet6 ${ip6_addr} prefixlen ${ip6_mask} up";
exec.start += "/sbin/route add default ${ip_route}";
exec.start += "/sbin/route add -inet6 default ${ip6_route}";
exec.start += "/sbin/ifconfig epair${if}b $ip_addr_pub netmask 255.255.255.255 alias";
exec.start += "/sbin/ifconfig epair${if}b inet6 $ip6_addr_pub prefixlen 128 alias";
exec.start += "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.poststop = "ifconfig bridge0 deletem epair${if}a";
exec.poststop += "ifconfig epair${if}a destroy";
persist;
}

Now we need to install the container:

bsdinstall jail /zroot/jail/<container>

Configure the rc.conf in the container: /zroot/jail/<container>/etc/rc.conf

local_unbound_enable="YES"
ipv6_network_interfaces="auto"
ipv6_activate_all_interfaces="YES"

Now you can activate the container by using:

service jail start <container>

You will need to change the IP addresses with your own though, else it won’t work.