Linux VRF with L3 Master Device
Linux kernel 4.4から登場した、L3 Master Device (l3mdev) によるVirtual Routing and Forwading (VRF) を軽く触ってみたメモ。
そもそも何をするためのものなのか
Linuxのネットワーク廻りを触っていると、たまに「特定のネットワークインタフェースから入ってきた通信に、特定のルーティングルールを適用したい」といった場面がある。こうしたケースでは、以前より Routing Policy Database (RPDB) を利用して Policy Based Routing (PBR) を行う方法が知られている。
一方、ネットワーク機器の世界では一般的に、L3ドメインを分割する手段として Virtual Routing and Forwarding (VRF) という機能が PBR とは別に存在している。VRFは、あるネットワークインタフェース群に適用されるルーティングテーブルを分離させるためのものである。このような概念をLinux上で実現するために登場したのが、L3 Master Device である。
net: L3 master device [LWN.net]
kernel/git/davem/net-next.git - David Miller's -next networking tree
使用方法
前提として、カーネルが4.4以降かつ NET_L3_MASTER_DEV=y
でコンパイルされている必要がある。たとえばFedoraの場合、4.11以前のパッケージではこのオプションが無効であるため注意が必要。また、iproute2
のバージョンが古いと、後述するl3mdevが暗黙的に追加するポリシーが ip rule
コマンドで正しく表示されないので同様に注意する必要がある。
Bug 1428530 – Set NET_L3_MASTER_DEV=y to enable ipvlan module
設定のおおまかな流れとしては次の3ステップ。
- L3 Master Device (l3mdev) のネットワークインタフェースを作成する
- 既存のネットワークインタフェースのmasterとしてl3madevを指定する
- VRF毎にルーティングを設定する
流れ自体はbridge interfaceを作成する場合と似ている。l3mdev は通常のネットワークインタフェース (net_device) と同様に振る舞うので、l3mdev自体にIPアドレスを振ることも可能。ネットワーク機器で言うところのloopback address的な使い方が可能。
使用例
まずはl3mdevを作成する。ここでは vrf-x
と vrf-y
の2個のVRFを作成する。
# ip link add dev vrf-x type vrf table 10 # ip link set dev vrf-x up # ip link add dev vrf-y type vrf table 20 # ip link set dev vrf-y up
ip link
コマンドを実行すると、2個のインタフェースが作成されていることが分かる。
$ ip link 2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:15:7f:1c brd ff:ff:ff:ff:ff:ff 3: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:4e:69:5d brd ff:ff:ff:ff:ff:ff 4: ens6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:cb:ef:bd brd ff:ff:ff:ff:ff:ff 5: ens7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:f1:2e:11 brd ff:ff:ff:ff:ff:ff 6: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:83:4c:ca brd ff:ff:ff:ff:ff:ff 9: vrf-x: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 5a:b6:1d:4a:84:21 brd ff:ff:ff:ff:ff:ff 11: vrf-y: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 76:c3:e8:67:00:01 brd ff:ff:ff:ff:ff:ff
ここでは ens4
, ens5
を vrf-x
に、ens6
, ens7
を vrf-y
に所属させることにする。
# ip link set dev ens4 master vrf-x # ip link set dev ens5 master vrf-x # ip link set dev ens6 master vrf-y # ip link set dev ens7 master vrf-y
再度 ip link
コマンドを実行すると、ens[4-7]
のmasterが設定されていることが分かる。
$ ip link 2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-x state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:15:7f:1c brd ff:ff:ff:ff:ff:ff 3: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-x state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:4e:69:5d brd ff:ff:ff:ff:ff:ff 4: ens6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-y state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:cb:ef:bd brd ff:ff:ff:ff:ff:ff 5: ens7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-y state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:f1:2e:11 brd ff:ff:ff:ff:ff:ff 6: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:83:4c:ca brd ff:ff:ff:ff:ff:ff 9: vrf-x: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 5a:b6:1d:4a:84:21 brd ff:ff:ff:ff:ff:ff 11: vrf-y: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 76:c3:e8:67:00:01 brd ff:ff:ff:ff:ff:ff
また、ip rule
コマンドを実行すると、priority 1000に l3mdev-table
というポリシーが自動的に追加されていることが分かる。なお、この機能はkernel 4.8から実装されたもの*1なので、4.4~4.7のカーネルでl3mdevを使用する場合、手動でルールを追加する必要がある。
$ ip rule 0: from all lookup local 1000: from all lookup [l3mdev-table] 32766: from all lookup main 32767: from all lookup default
ここで、例として 172.16.0.1/32
の経路を各VRFに追加する。
$ ip addr 2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-x state UP group default qlen 1000 link/ether 52:54:00:15:7f:1c brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 scope global ens4 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:fe15:7f1c/64 scope link valid_lft forever preferred_lft forever 3: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-x state UP group default qlen 1000 link/ether 52:54:00:4e:69:5d brd ff:ff:ff:ff:ff:ff inet 192.168.2.1/24 scope global ens5 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:fe4e:695d/64 scope link valid_lft forever preferred_lft forever 4: ens6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-y state UP group default qlen 1000 link/ether 52:54:00:cb:ef:bd brd ff:ff:ff:ff:ff:ff inet 10.0.1.1/24 scope global ens6 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:fecb:efbd/64 scope link valid_lft forever preferred_lft forever 5: ens7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master vrf-y state UP group default qlen 1000 link/ether 52:54:00:f1:2e:11 brd ff:ff:ff:ff:ff:ff inet 10.0.2.1/24 scope global ens7 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:fef1:2e11/64 scope link valid_lft forever preferred_lft forever 6: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 52:54:00:83:4c:ca brd ff:ff:ff:ff:ff:ff inet 10.168.20.201/24 brd 10.168.20.255 scope global ens3 valid_lft forever preferred_lft forever inet6 fe80::24fd:811e:6432:bd36/64 scope link valid_lft forever preferred_lft forever 9: vrf-x: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP group default qlen 1000 link/ether 5a:b6:1d:4a:84:21 brd ff:ff:ff:ff:ff:ff 11: vrf-y: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP group default qlen 1000 link/ether 76:c3:e8:67:00:01 brd ff:ff:ff:ff:ff:ff
# ip route add 172.16.0.1/32 via 192.168.1.2 table 10 # ip route add 172.16.0.1/32 via 10.0.1.2 table 20
ip route list
を見ると、デフォルトおよび各VRF毎に独立したルーティングテーブルが設定されていることが確認できる。
$ ip route list default via 10.168.20.1 dev ens3 proto static metric 100 10.168.20.0/24 dev ens3 proto kernel scope link src 10.168.20.201 metric 100 $ ip route list vrf vrf-x 172.16.0.1 via 192.168.1.2 dev ens4 192.168.1.0/24 dev ens4 proto kernel scope link src 192.168.1.1 192.168.2.0/24 dev ens5 proto kernel scope link src 192.168.2.1 $ ip route list vrf vrf-y 10.0.1.0/24 dev ens6 proto kernel scope link src 10.0.1.1 10.0.2.0/24 dev ens7 proto kernel scope link src 10.0.2.1 172.16.0.1 via 10.0.1.2 dev ens6
Network Namespaceとの比較
Linuxのネットワークリソースを分離・独立させる手段としては、最近はNetwork Namespaceがポピュラーである。Network Namespaceはネットワークスタック全体を分離するのに対し、l3mdevはL3のルーティングのみを分離する。l3mdevのモデルは、L3ドメインをまたいでプロセスを実行したい場合、具体的にはルーティングデーモンを実行する場合に都合が良い。このあたりの背景は、L3 Master Deviceの提案者であるDavid Ahernが書いた記事が詳しい。
アプリケーション側の挙動に関しては、カーネル付随ドキュメントの Applications セクションに記載がある通り sysctl
で net.ipv4.tcp_l3mdev_accept
/ net.ipv4.udp_l3mdev_accept
によって変化するようである。このあたりはまた別途触ってみる予定。
Reference
- https://www.kernel.org/doc/Documentation/networking/vrf.txt
- カーネルに付随するドキュメント。
- VRF for Linux — a contribution to the Linux Kernel - Cumulus Networks Blog
- l3mdevの提案者、David Ahernによるエントリ。VRF実装が必要とされるコンテキストが詳細に述べられている。
- What is an L3 Master Device?
- 同じくDavid Ahernによるnetdev 1.2での発表資料。実装面やパフォーマンスについても述べられている。