OpenBSD provides some packet routing facilities. The
kernel maintains a routing information database, which is used in selecting
the appropriate network interface when transmitting packets.

A user process (or possibly multiple co-operating processes) maintains this
database by sending messages over a special kind of socket. This supplants
fixed size ioctl(2)'s used in
earlier releases. Routing table changes may only be carried out by the super
user.

The operating system may spontaneously emit routing messages in response to
external events, such as receipt of a redirect, or failure to locate a
suitable route for a request. The message types are described in greater
detail below.

Routing database entries come in two flavors: for a specific host, or for all
hosts on a generic subnetwork (as specified by a bit mask and value under the
mask). The effect of wildcard or default route may be achieved by using a mask
of all zeros, and there may be hierarchical routes.

When the system is booted and addresses are assigned to the network interfaces,
each protocol family installs a routing table entry for each interface when it
is ready for traffic. Normally the protocol specifies the route through each
interface as a “direct” connection to the destination host or
network. If the route is direct, the transport layer of a protocol family
usually requests the packet be sent to the same host specified in the packet.
Otherwise, the interface is requested to address the packet to the gateway
listed in the routing entry (i.e., the packet is forwarded).

When routing a packet, the kernel will attempt to find the most specific route
matching the destination. (If there are two different mask and
value-under-the-mask pairs that match, the more specific is the one with more
bits in the mask. A route to a host is regarded as being supplied with a mask
of as many ones as there are bits in the destination.) If no entry is found,
the destination is declared to be unreachable, and a routing-miss message is
generated if there are any listeners on the routing control socket described
below.

A wildcard routing entry is specified with a zero destination address value and
a mask of all zeroes. Wildcard routes will be used when the system fails to
find other routes matching the destination. The combination of wildcard routes
and routing redirects can provide an economical mechanism for routing traffic.
Routes created by redirects from wildcard routes and other routes will be
marked cloned, until their “parent”
from which they were created has disappeared.

Route labels can be attached to routes and may contain arbitrary information
about the route. Labels are sent over the routing socket (see below) as
sockaddr_rtlabel structures.

One opens the channel for passing routing control messages by using the
socket(2) call shown in the
SYNOPSIS above.

The family parameter may be
AF_UNSPEC, which will provide routing
information for all address families, or can be restricted to a specific
address family by specifying which one is desired. There can be more than one
routing socket open per system.

Messages are formed by a header followed by a small number of
sockaddr structures (which are variable
length), interpreted by position, and delimited by the length entry in the
sockaddr. An example of a message with four
addresses might be an IPv4 route addition: the destination, netmask, gateway,
and label, since both netmasks and labels are sent over the routing socket as
sockaddr structures. The interpretation of
which addresses are present is given by a bit mask within the header, and the
sequence is least significant to most significant bit within the vector.

Any messages sent to the kernel are returned, and copies are sent to all
interested listeners. The kernel will provide the process ID for the sender,
and the sender may use an additional sequence field to distinguish between
outstanding messages. However, message replies may be lost when kernel buffers
are exhausted.

The kernel may reject certain messages, and will indicate this by filling in the
rtm_errno field. The routing code returns
EEXIST if requested to duplicate an
existing entry, ESRCH if requested to
delete a non-existent entry, or ENOBUFS if
insufficient resources were available to install a new route. In the current
implementation, all routing processes run locally, and the values for
rtm_errno are available through the normal
errno mechanism, even if the routing reply
message is lost.

A process may avoid the expense of reading replies to its own messages by
issuing a setsockopt(2) call
indicating that the SO_USELOOPBACK option
at the SOL_SOCKET level is to be turned
off. A process may ignore all messages from the routing socket by doing a
shutdown(2) system call for
further input.

A process can specify an alternate routing table by using the
SO_RTABLEsetsockopt(2).

A process can specify which route message types it's interested in by using
ROUTE_FILTER(int type) and issuing a
setsockopt call with the ROUTE_MSGFILTER
option at the AF_ROUTE level. For example,
to only get interface specific messages:

Similarly, a process can specify that it is only interested in messages relating
to routes where the priority is no more than a certain value by issuing a
setsockopt call with the ROUTE_PRIOFILTER
option. For example, to select only local, directly connected and static
routes:

If a route is in use when it is deleted, the routing entry will be marked down
and removed from the routing table, but the resources associated with it will
not be reclaimed until all references to it are released. User processes can
obtain information about the routing entry to a specific destination by using
a RTM_GET message or via the
PF_ROUTEsysctl(2).

The RTM_IFINFO message uses an
if_msghdr header, the
RTM_NEWADDR and
RTM_DELADDR messages use an
ifa_msghdr header, the
RTM_IFANNOUNCE message uses an
if_announcemsghdr header, and all other
messages use the rt_msghdr header.

Only rmx_mtu,
rmx_expire,
rmx_pksent, and
rmx_locks are used by the kernel routing
table. All other values will be ignored when inserting them into the kernel
and are set to zero in routing messages sent by the kernel. They are left for
compatibility reasons with other systems.