Excerpt from the rdomain(4) man page:

The traditional kernel routing system had a single table for routes and allowed only non-conflicting IP address assignments. The rtable feature allows multiple lookup tables for routes. The rdomain feature provides a way to logically segment a router between network paths.

Setup

The following, non-persistent example uses VLAN 71 as the underlying interface. Of course, any physical device can be specified as well. Please note one should always configure the rdomain first, interface IP second. The last command executes the route command for our newly created rdomain 71, providing a default gateway for that very routing table.

# ifconfig vlan71 rdomain 71 
# ifconfig vlan71 192.168.71.1/24
# route -T71 -n add default 192.168.71.1

Our interface and rdomain should be up and running now. Note the newly appearing "rdomain 71":

$ ifconfig vlan71
vlan71: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> rdomain 71 mtu 1500
        lladdr 32:37:36:64:33:33
        index 15 priority 0 llprio 3
        vlan: 71 parent interface: vio0
        vnetid: 71
        parent: vio0
        groups: vlan
        status: active
        inet 192.168.71.1 netmask 0xffffff00 broadcast 192.168.71.255

To show the routing table content, issue the route command with the already learned -T flag:

$ route -T 71 -n show

Persistence!

In order to make that configuration survive a reboot, a hostname.vlan71 needs to be created in /etc as usual. It may look like this:

$ cat /etc/hostname.vlan71
rdomain 71
inet 192.168.71.1 255.255.255.0 NONE vlandev vio0
!route -T71 -n add default 192.168.71.1

Again, beware the order. rdomain definition first, IP assignments second.

rdomain-aware daemons

OpenBSD ships a number of daemons of which some are even rdomain-aware. Meaning, they are able to not only serve rdomain 0 but even 254 more :) One example is ntpd, that can be configured to offer network time for a specific routing table. Let's have a look at its self-explanatory configuration file:

$ cat /etc/ntpd.conf

listen on 192.168.26.1
listen on 192.168.71.1 rtable 71

server 0.ch.pool.ntp.org
server 1.ch.pool.ntp.org
server 2.ch.pool.ntp.org
server 3.ch.pool.ntp.org
sensor *
constraints from "https://www.google.com"

rdomain ignorance

However, not all daemons are able to handle rdomains themselves. There's a nice way overcoming this little issue: rcctl(8) to the rescue.

The following commands will 'clone' the dhcpd daemon resource script by soft-linking it, so rcctl(8) is able to treat them separately, with individual flags:

# ln -s /etc/rc.d/dhcpd /etc/rc.d/dhcpd71
# rcctl enable dhcpd71
# rcctl set dhcpd71 rtable 71
# rcctl set dhcpd71 flags "-c /etc/dhcpd71.conf"

One can always double check the generated rc(8) configuration file /etc/rc.conf.local. That's it! Of course, the content of dhcpd71.conf needs to be adjusted, so it only serves addresses for the newly created routing domain. One can now start/stop both dhcpd daemons:

# rcctl start dhcpd
dhcpd (ok)
# rcctl start dhcpd71
dhcpd71 (ok)

The ps(8) command is able to show which process is running in which routing domain, using the "-o rtable" flags (see last column):

# ps aux -o rtable | grep dhcp
_dhcp    63587  0.0  0.1   636  1508 ??  Isp   12:16PM    0:00.00 /usr/sbin/dhcpd       0
_dhcp    32192  0.0  0.1   588  1464 ??  Isp   12:20PM    0:00.05 /usr/sbin/dhcpd      71

Packet filtering

Depening on the use case, the OpenBSD packet filter is used to control the packet flow between routing domains. A couple of example rules will provide an idea of what's possible. More detailed information can be found in the according man pages: pfctl, pf.conf.

match out on rdomain 71 to !vlan71 nat-to egress rtable 0
pass in log on rdomain 71 proto tcp to port 80

Summary

OpenBSD rdomains are a very elegant way to isolate routing traffic from each other. Daemons can serve for specific rdomains which obsolete clunky ip or listener restrictions. Management of multiple daemons of a kind is easily possible using rcctl. Packet flow between routing domains is managed by the packet filter PF.

References

Virtualizing the OpenBSD Routing Table - Joel Knight