Implementing VRF in the Linux Operating System
Virtual Routing and Forwarding (VRF) allows a single Linux host to
maintain multiple, isolated Layer 3 routing tables simultaneously,
enabling multi-tenancy and complex network segmentation. This article
explores how modern Linux kernels natively implement VRF using Layer 3
master devices (l3mdev), the mechanics of packet path
isolation, and the step-by-step process to configure and run
applications inside isolated VRF domains using
iproute2.
The Architectural
Foundation: l3mdev
Prior to kernel version 4.3, network isolation on Linux primarily
relied on network namespaces (netns). While namespaces
duplicate the entire network stack—including device lists, firewall
rules, and sockets—VRF implements Layer 3 isolation within a single
network namespace.
The kernel achieves this through the Layer 3 Master Device
(l3mdev) infrastructure. Under this model:
- A VRF instance is represented as a virtual network device.
- Each VRF device is explicitly associated with an independent routing table ID.
- Physical or virtual network interfaces (such as
eth0or VLAN sub-interfaces) are enslaved to the VRF device as subordinate ports.
When an interface is enslaved to a VRF, all Layer 3 packet processing
on that interface is redirected from the kernel’s default routing tables
(local and main) to the routing table
associated with the VRF master device.
Ingress and Egress Packet Handling
- Ingress: When an IP packet arrives on an enslaved
interface, the kernel's core IP input function passes the packet through
the
l3mdev_l3_rcvhook. This hook identifies the master VRF device and selects its designated routing table for the route lookup, ensuring that destination decisions remain strictly within that VRF domain. - Egress: Locally generated traffic is steered into a
VRF via socket-level binding. By using the
SO_BINDTODEVICEsocket option, applications bind directly to the VRF master device. When the kernel performs the routing lookup for outbound packets, it selects the routing table bound to that VRF.
Configuring VRF with
iproute2
Linux manages VRF instances natively through the ip link
and ip route suites.
1. Create the VRF Device
Create a VRF device and map it to a designated routing table ID:
ip link add dev vrf-blue type vrf table 100
ip link set dev vrf-blue up2. Enslave Interfaces
Assign interfaces to the VRF device. This moves Layer 3 handling of these interfaces into table 100:
ip link set dev eth1 master vrf-blue
ip link set dev eth1 up3. Assign IP Addresses and Routes
IP addresses are assigned to the member interfaces as usual, but specific routes are added directly to the VRF’s routing table:
ip addr add 192.168.10.1/24 dev eth1
ip route add 10.0.0.0/8 via 192.168.10.254 dev eth1 table 100Running Applications in a VRF
To run standard, unmodified network utilities and daemons inside an
isolated VRF, Linux provides the ip vrf exec wrapper, which
relies on cgroups and the SO_BINDTODEVICE
socket option:
ip vrf exec vrf-blue ping 10.0.0.1
ip vrf exec vrf-blue ssh user@10.0.0.2Network daemons (such as BGP/OSPF engines or SSH servers) can also be
programmed natively to listen on specific VRF interfaces by utilizing
the SO_BINDTODEVICE or IP_PKTINFO socket
flags, allowing multi-instance routing services on a single operating
system.