虚拟路由和转发 (VRF)¶
VRF 设备¶
VRF 设备与 ip 规则结合使用,可以在 Linux 网络堆栈中创建虚拟路由和转发域(也称为 VRF,具体来说是 VRF-lite)。一个用例是多租户问题,其中每个租户都有自己唯一的路由表,并且至少需要不同的默认网关。
进程可以通过将套接字绑定到 VRF 设备来“感知 VRF”。然后,通过套接字的数据包使用与 VRF 设备关联的路由表。VRF 设备实现的一个重要特性是它仅影响第 3 层及以上,因此 L2 工具(例如,LLDP)不受影响(即,它们不需要在每个 VRF 中运行)。该设计还允许使用更高优先级的 ip 规则(基于策略的路由,PBR)优先于 VRF 设备规则,从而根据需要定向特定流量。
此外,VRF 设备允许将 VRF 嵌套在命名空间中。例如,网络命名空间提供设备层网络接口的隔离,命名空间中接口上的 VLAN 提供 L2 隔离,然后 VRF 设备提供 L3 隔离。
设计¶
创建一个 VRF 设备,并关联一个路由表。然后将网络接口绑定到 VRF 设备。
+-----------------------------+
| vrf-blue | ===> route table 10
+-----------------------------+
| | |
+------+ +------+ +-------------+
| eth1 | | eth2 | ... | bond1 |
+------+ +------+ +-------------+
| |
+------+ +------+
| eth8 | | eth9 |
+------+ +------+
在从属设备上接收到的数据包在 IPv4 和 IPv6 处理堆栈中切换到 VRF 设备,给人一种数据包流经 VRF 设备的印象。类似地,在出口路由规则用于将数据包发送到 VRF 设备驱动程序,然后通过实际接口发送出去。这允许在 VRF 设备上使用 tcpdump 捕获进出整个 VRF 的所有数据包[1]。类似地,可以使用 VRF 设备应用 netfilter[2] 和 tc 规则,以指定适用于整个 VRF 域的规则。
设置¶
创建 VRF 设备,并关联到 FIB 表。例如,
ip link add vrf-blue type vrf table 10 ip link set dev vrf-blue up
l3mdev FIB 规则将查找定向到与设备关联的表。单个 l3mdev 规则足以满足所有 VRF。当使用默认优先级 1000 创建第一个设备时,VRF 设备会为 IPv4 和 IPv6 添加 l3mdev 规则。如果需要,用户可以删除该规则并添加具有不同优先级的规则,或者安装每个 VRF 的规则。
在 v4.8 内核之前,每个 VRF 设备都需要 iif 和 oif 规则。
ip ru add oif vrf-blue table 10 ip ru add iif vrf-blue table 10
设置表的默认路由(因此也是 VRF 的默认路由)。
ip route add table 10 unreachable default metric 4278198272
此高指标值确保默认的不可达路由可以被路由协议套件覆盖。FRRouting 将内核指标解释为组合的管理距离(高位字节)和优先级(低 3 个字节)。因此,上述指标转换为 [255/8192]。
将 L3 接口绑定到 VRF 设备
ip link set dev eth1 master vrf-blue
绑定设备的本地路由和连接路由会自动移动到与 VRF 设备关联的表。任何依赖于绑定设备的附加路由都将被删除,并且在绑定后需要重新插入到 VRF FIB 表中。
可以启用 IPv6 sysctl 选项 keep_addr_on_down,以便在 VRF 绑定更改时保留 IPv6 全局地址。
sysctl -w net.ipv6.conf.all.keep_addr_on_down=1
将其他 VRF 路由添加到关联的表
ip route add table 10 ...
应用¶
要在 VRF 中工作的应用程序需要将其套接字绑定到 VRF 设备
setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, strlen(dev)+1);
或使用 cmsg 和 IP_PKTINFO 指定输出设备。
默认情况下,未绑定套接字的端口绑定的范围限制为默认 VRF。也就是说,它不会与在绑定到 l3mdev 的接口上到达的数据包匹配,并且进程可以绑定到同一端口,只要它们绑定到 l3mdev。
在默认 VRF 上下文中运行的 TCP 和 UDP 服务(即,未绑定到任何 VRF 设备)可以通过启用 tcp_l3mdev_accept 和 udp_l3mdev_accept sysctl 选项来跨所有 VRF 域工作。
sysctl -w net.ipv4.tcp_l3mdev_accept=1
sysctl -w net.ipv4.udp_l3mdev_accept=1
默认情况下禁用这些选项,以便仅为该 VRF 中的数据包选择 VRF 中的套接字。RAW 套接字有一个类似的选项,出于向后兼容性的原因,默认情况下启用该选项。这是为了使用 cmsg 和 IP_PKTINFO 指定输出设备,但使用未绑定到相应 VRF 的套接字。这允许例如使用指定设备运行较旧的 ping 实现,而无需在 VRF 中执行它。可以禁用此选项,以便在 VRF 上下文中接收的数据包仅由绑定到 VRF 的原始套接字处理,并且默认 VRF 中的数据包仅由未绑定到任何 VRF 的套接字处理。
sysctl -w net.ipv4.raw_l3mdev_accept=0
VRF 设备上的 netfilter 规则也可用于限制对默认 VRF 上下文中运行的服务的访问。
将 VRF 感知应用程序(同时在 VRF 内外创建套接字的应用程序)与 net.ipv4.tcp_l3mdev_accept=1
结合使用是可能的,但在某些情况下可能会导致问题。使用该 sysctl 值,未指定将选择哪个侦听套接字来处理 VRF 流量的连接;即,绑定到 VRF 的套接字或未绑定的套接字可用于接受来自 VRF 的新连接。如果使用额外的选项(例如,TCP MD5 密钥)配置套接字,并且期望 VRF 流量将专门由绑定到 VRF 的套接字处理,那么这种有点意外的行为可能会导致问题,就像 net.ipv4.tcp_l3mdev_accept=0
的情况一样。最后,提醒一下,无论选择哪个侦听套接字,都将基于入口接口在 VRF 中创建已建立的套接字,如前所述。
将 iproute2 用于 VRF¶
从 v4.7 开始,iproute2 支持 vrf 关键字。为了向后兼容,本节列出了适当的命令,包括带有 vrf 关键字的和没有 vrf 关键字的旧格式。
创建 VRF
要实例化 VRF 设备并将其与表关联
$ ip link add dev NAME type vrf table ID
从 v4.8 开始,内核支持 l3mdev FIB 规则,其中单个规则覆盖所有 VRF。首次创建设备时,会为 IPv4 和 IPv6 创建 l3mdev 规则。
列出 VRF
要列出已创建的 VRF
$ ip [-d] link show type vrf NOTE: The -d option is needed to show the table id
例如
$ ip -d link show type vrf 11: mgmt: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 72:b3:ba:91:e2:24 brd ff:ff:ff:ff:ff:ff promiscuity 0 vrf table 1 addrgenmode eui64 12: red: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether b6:6f:6e:f6:da:73 brd ff:ff:ff:ff:ff:ff promiscuity 0 vrf table 10 addrgenmode eui64 13: blue: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 36:62:e8:7d:bb:8c brd ff:ff:ff:ff:ff:ff promiscuity 0 vrf table 66 addrgenmode eui64 14: green: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether e6:28:b8:63:70:bb brd ff:ff:ff:ff:ff:ff promiscuity 0 vrf table 81 addrgenmode eui64
或在简短输出中
$ ip -br link show type vrf mgmt UP 72:b3:ba:91:e2:24 <NOARP,MASTER,UP,LOWER_UP> red UP b6:6f:6e:f6:da:73 <NOARP,MASTER,UP,LOWER_UP> blue UP 36:62:e8:7d:bb:8c <NOARP,MASTER,UP,LOWER_UP> green UP e6:28:b8:63:70:bb <NOARP,MASTER,UP,LOWER_UP>
将网络接口分配给 VRF
通过将网络设备绑定到 VRF 设备,将网络接口分配给 VRF
$ ip link set dev NAME master NAME
在绑定时,连接的路由和本地路由会自动移动到与 VRF 设备关联的表。
例如
$ ip link set dev eth0 master mgmt
显示分配给 VRF 的设备
要显示已分配给特定 VRF 的设备,请将 master 选项添加到 ip 命令
$ ip link show vrf NAME $ ip link show master NAME
例如
$ ip link show vrf red 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP mode DEFAULT group default qlen 1000 link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff 4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP mode DEFAULT group default qlen 1000 link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff 7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master red state DOWN mode DEFAULT group default qlen 1000 link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
或使用简短输出
$ ip -br link show vrf red eth1 UP 02:00:00:00:02:02 <BROADCAST,MULTICAST,UP,LOWER_UP> eth2 UP 02:00:00:00:02:03 <BROADCAST,MULTICAST,UP,LOWER_UP> eth5 DOWN 02:00:00:00:02:06 <BROADCAST,MULTICAST>
显示 VRF 的邻居条目
要列出与绑定到 VRF 设备的设备关联的邻居条目,请将 master 选项添加到 ip 命令
$ ip [-6] neigh show vrf NAME $ ip [-6] neigh show master NAME
例如
$ ip neigh show vrf red 10.2.1.254 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE 10.2.2.254 dev eth2 lladdr 5e:54:01:6a:ee:80 REACHABLE $ ip -6 neigh show vrf red 2002:1::64 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
显示 VRF 的地址
要显示与 VRF 关联的接口的地址,请将 master 选项添加到 ip 命令
$ ip addr show vrf NAME $ ip addr show master NAME
例如
$ ip addr show vrf red 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP group default qlen 1000 link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff inet 10.2.1.2/24 brd 10.2.1.255 scope global eth1 valid_lft forever preferred_lft forever inet6 2002:1::2/120 scope global valid_lft forever preferred_lft forever inet6 fe80::ff:fe00:202/64 scope link valid_lft forever preferred_lft forever 4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP group default qlen 1000 link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff inet 10.2.2.2/24 brd 10.2.2.255 scope global eth2 valid_lft forever preferred_lft forever inet6 2002:2::2/120 scope global valid_lft forever preferred_lft forever inet6 fe80::ff:fe00:203/64 scope link valid_lft forever preferred_lft forever 7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master red state DOWN group default qlen 1000 link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
或以简短格式
$ ip -br addr show vrf red eth1 UP 10.2.1.2/24 2002:1::2/120 fe80::ff:fe00:202/64 eth2 UP 10.2.2.2/24 2002:2::2/120 fe80::ff:fe00:203/64 eth5 DOWN
显示 VRF 的路由
要显示 VRF 的路由,请使用 ip 命令显示与 VRF 设备关联的表
$ ip [-6] route show vrf NAME $ ip [-6] route show table ID
例如
$ ip route show vrf red unreachable default metric 4278198272 broadcast 10.2.1.0 dev eth1 proto kernel scope link src 10.2.1.2 10.2.1.0/24 dev eth1 proto kernel scope link src 10.2.1.2 local 10.2.1.2 dev eth1 proto kernel scope host src 10.2.1.2 broadcast 10.2.1.255 dev eth1 proto kernel scope link src 10.2.1.2 broadcast 10.2.2.0 dev eth2 proto kernel scope link src 10.2.2.2 10.2.2.0/24 dev eth2 proto kernel scope link src 10.2.2.2 local 10.2.2.2 dev eth2 proto kernel scope host src 10.2.2.2 broadcast 10.2.2.255 dev eth2 proto kernel scope link src 10.2.2.2 $ ip -6 route show vrf red local 2002:1:: dev lo proto none metric 0 pref medium local 2002:1::2 dev lo proto none metric 0 pref medium 2002:1::/120 dev eth1 proto kernel metric 256 pref medium local 2002:2:: dev lo proto none metric 0 pref medium local 2002:2::2 dev lo proto none metric 0 pref medium 2002:2::/120 dev eth2 proto kernel metric 256 pref medium local fe80:: dev lo proto none metric 0 pref medium local fe80:: dev lo proto none metric 0 pref medium local fe80::ff:fe00:202 dev lo proto none metric 0 pref medium local fe80::ff:fe00:203 dev lo proto none metric 0 pref medium fe80::/64 dev eth1 proto kernel metric 256 pref medium fe80::/64 dev eth2 proto kernel metric 256 pref medium ff00::/8 dev red metric 256 pref medium ff00::/8 dev eth1 metric 256 pref medium ff00::/8 dev eth2 metric 256 pref medium unreachable default dev lo metric 4278198272 error -101 pref medium
VRF 的路由查找
可以为 VRF 完成测试路由查找
$ ip [-6] route get vrf NAME ADDRESS $ ip [-6] route get oif NAME ADDRESS
例如
$ ip route get 10.2.1.40 vrf red 10.2.1.40 dev eth1 table red src 10.2.1.2 cache $ ip -6 route get 2002:1::32 vrf red 2002:1::32 from :: dev eth1 table red proto kernel src 2002:1::2 metric 256 pref medium
从 VRF 中移除网络接口
通过断开与 VRF 设备的绑定,从 VRF 中移除网络接口
$ ip link set dev NAME nomaster
连接的路由移回默认表,本地条目移至本地表。
例如
$ ip link set dev eth0 nomaster
本示例中使用的命令
cat >> /etc/iproute2/rt_tables.d/vrf.conf <<EOF
1 mgmt
10 red
66 blue
81 green
EOF
function vrf_create
{
VRF=$1
TBID=$2
# create VRF device
ip link add ${VRF} type vrf table ${TBID}
if [ "${VRF}" != "mgmt" ]; then
ip route add table ${TBID} unreachable default metric 4278198272
fi
ip link set dev ${VRF} up
}
vrf_create mgmt 1
ip link set dev eth0 master mgmt
vrf_create red 10
ip link set dev eth1 master red
ip link set dev eth2 master red
ip link set dev eth5 master red
vrf_create blue 66
ip link set dev eth3 master blue
vrf_create green 81
ip link set dev eth4 master green
Interface addresses from /etc/network/interfaces:
auto eth0
iface eth0 inet static
address 10.0.0.2
netmask 255.255.255.0
gateway 10.0.0.254
iface eth0 inet6 static
address 2000:1::2
netmask 120
auto eth1
iface eth1 inet static
address 10.2.1.2
netmask 255.255.255.0
iface eth1 inet6 static
address 2002:1::2
netmask 120
auto eth2
iface eth2 inet static
address 10.2.2.2
netmask 255.255.255.0
iface eth2 inet6 static
address 2002:2::2
netmask 120
auto eth3
iface eth3 inet static
address 10.2.3.2
netmask 255.255.255.0
iface eth3 inet6 static
address 2002:3::2
netmask 120
auto eth4
iface eth4 inet static
address 10.2.4.2
netmask 255.255.255.0
iface eth4 inet6 static
address 2002:4::2
netmask 120