虛擬路由和轉發 (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