最近在看VRF功能相关,想要系统了解一下,发现一篇很不错的文章大有裨益。
但是其中有一点我与文章中有不同见解:
1.文章中说VRF(虚拟路由器)是从L1,L2,L3这三层都做了虚拟隔离,但是根据文档记载,应该是只做了L3虚拟。文章原文翻译如下:
“VRF 设备结合 ip rules(策略路由)提供了在Linux 网络堆栈中创建虚拟路由和转发域(又名 VRF,具体来说是VRF-lite)。
一个用例是多租户问题,其中每个租户有自己独特的路由表,而且每个路由表要有一个默认网关。
通过将套接字绑定到 VRF 设备,进程可以“感知 VRF”。数据包通过套接字然后使用与 VRF 关联的路由表设备。 VRF 设备实现的一个重要特征是它仅影响第 3 层及更高层,因此 L2 工具(例如 LLDP)不受影响(即,它们不需要在每个 VRF 中运行)。该设计还允许使用更高优先级的策略路由(Policy Based Routing,PBR)采取优先于根据需要引导特定流量的 VRF 设备规则。
此外,VRF 设备允许 VRF 嵌套在命名空间中。比如网络命名空间在设备层,命名空间内接口上的 VLAN 提供 L2 分离,然后 VRF 设备提供 L3 分离。
”
以下为一篇重要文章中文翻译:
设计
使用关联的路由表创建 VRF 设备,然后网络接口被分配到给VRF 之后就叫做enslaved设备。
在enslaved设备(物理接口)上接收的数据包,然后在 IPv4 和 IPv6 处理堆栈中切换到 VRF 设备(master)对应的接收函数,给人的感觉是数据包仿佛是直接流经 VRF 设备送到内核处理的。
同样地,当内核要发送一个数据包地时候,首先将数据包发送到 VRF 设备驱动接口,然后在出口根据路由规则发出实际数据包。
允许tcpdump在VRF虚拟设备上抓包进出的包,这个VRF虚拟设备就像普通物理接口那样使用[1]。同样地,可以使用 VRF虚拟设备应用于 netfilter [2]和 tc规则,以指定适用于整个 VRF 域的规则。
[1]报文在转发状态的时候不流经这个设备,所以那些报文不会被tcpdump抓包抓到。这个限制后面会被重新审视。
[2] iptables在入口netfilter框架入口处支持 PREROUTING,将 skb->dev 设置为真正的入口设备,并且在INPUT 和 PREROUTING 规则处,将 skb->dev 设置为 VRF 设备。 对于出口 POSTROUTING 和 OUTPUT 规则可以使用 VRF 设备或真实出口设备。
Setup安装步骤
步骤说明 涉及命令实例
步骤一:VRF设备被创建并且关联上fib table
》》ip link add vrf-blue type vrf table 10
》》ip link set dev vrf-blue up
步骤二:一个 L3 master 设备直接查找关联的设备。一个单独的L3 master设备规则
l3mdev设备的FIB 规则将查找定向到与设备关联的fib表。 对于所有 VRF,一条 l3mdev 规则就足够了。 VRF 设备会在创建第一个设备时添加用于 IPv4 和 IPv6 的 l3mdev 规则,默认首选项为 1000。用户可以根据需要删除该规则并添加不同的优先级或安装每个 VRF 规则。
在 v4.8 内核之前,每个 VRF 设备都需要 iif 和 oif 规则:
》》ip ru add oif vrf-blue table 10
》》ip ru add iif vrf-blue table 10
步骤三:为vrf其中指定表设置默认路由(因此为 VRF 设置默认路由)。
》》ip route add table 10 unreachable default metric 4278198272
这个高度量值确保默认的不可达路由可以被路由协议套件覆盖。 FRRouting 将内核指标解释为组合的管理距离(高字节)和 riority(低 3 字节)。 因此,上述指标转换为 [255/8192]。
步骤四:将L3设备分配入vrf设备之后变为l3mdev。之后l3mdev涉及到的Local和直连路由都会被自动地移动到VRF设备关联的fib表中。任何l3mdev其他的路由会被丢弃,当l3mdev加入设备之后需要手动重新写入这些路由。
》》ip link set dev eth1 master vrf-blue
应用程序
应用程序涉及到VRF功能的需要绑定他们socket和VRF device在一起,具体使用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 选项:
sysctl -w net.ipv4.tcp_l3mdev_accept=1
sysctl -w net.ipv4.udp_l3mdev_accept=1
默认情况下禁用这些选项,以便仅为该 VRF 中的数据包选择 VRF 中的套接字。 RAW sockets也有类似的选项,出于向后兼容性的原因,默认情况下启用。这是为了用 cmsg 和 IP_PKTINFO 指定输出设备,但是使用socket未绑定到相应 VRF 的套接字。 这允许例如 旧版本的ping 实现在指定设备的情况下运行,但可以不使用VRF功能。可以禁用此选项,以便在VRF 中接收到的数据包上下文仅由绑定到 VRF 的原始套接字处理,而由默认 VRF 接收到的数据包,仅由未绑定到任何 VRF 的套接字处理:
sysctl -w net.ipv4.raw_l3mdev_accept=0
VRF 设备上的 netfilter 规则可用于限制对(运行在默认的 VRF 上下文中)服务的访问。