久しぶりに VXLAN について調べたところ、カーネルの機能で VXLAN インターフェイスが作れるようになってたので試してみた。 ここでいう VXLAN というのは、RFC7348 で定義されている Virtual eXtensible Local Area Network というプロトコルを指す。 このプロトコルを使うと Layer 2 のトンネリングが実現できる。
使った環境は次の通り。
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=18.04 DISTRIB_CODENAME=bionic DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS" $ uname -r 4.15.0-76-generic $ dpkg -l | grep iproute2 ii iproute2 4.15.0-2ubuntu1 amd64 networking and traffic control tools $ lsmod | grep -i vxlan vxlan 57344 0 ip6_udp_tunnel 16384 1 vxlan udp_tunnel 16384 1 vxlan
もくじ
ネットワークの構成
検証には Network Namespace と veth インターフェイスを使って作ったネットワークを用いる。
ネットワークの物理的な構成は次のとおり。
ネットワークは、全部で 3 つの Network Namespace からできている。
真ん中の router
はルータとして動作し、残りの ns1
と ns2
はホストとして動作する。
端点をもった線はインターフェイスのつながりを表している。
その中でも、緑の破線はトンネリングによって仮想的なつながりがあることを示している。
ネットワークの論理的な構成は次のとおり。
ネットワークは、全部で 3 つのセグメントからできている。
192.0.2.0/24
と 198.51.100.0/24
は、通常のルーティングをする。
対して、203.0.113.0/24
は VXLAN によって延伸されたブロードキャストドメインで動作する。
下準備
あらかじめ、必要なパッケージをひととおりインストールしておく。
$ sudo apt-get -y install iproute2 iputils-ping tcpdump
ネットワークを作る
まずは Network Namespace を用意する。
$ sudo ip netns add ns1 $ sudo ip netns add router $ sudo ip netns add ns2
つづいて veth インターフェイスを用意する。
$ sudo ip link add ns1-veth0 type veth peer name gw-veth0 $ sudo ip link add ns2-veth0 type veth peer name gw-veth1
作成した veth インターフェイスを Network Namespace に所属させていく。
$ sudo ip link set ns1-veth0 netns ns1 $ sudo ip link set gw-veth0 netns router $ sudo ip link set gw-veth1 netns router $ sudo ip link set ns2-veth0 netns ns2
インターフェイスの状態を UP に設定する。
$ sudo ip netns exec ns1 ip link set ns1-veth0 up $ sudo ip netns exec router ip link set gw-veth0 up $ sudo ip netns exec router ip link set gw-veth1 up $ sudo ip netns exec ns2 ip link set ns2-veth0 up
インターフェイスに IP アドレスを付与する。
$ sudo ip netns exec ns1 ip address add 192.0.2.1/24 dev ns1-veth0 $ sudo ip netns exec router ip address add 192.0.2.254/24 dev gw-veth0 $ sudo ip netns exec router ip address add 198.51.100.254/24 dev gw-veth1 $ sudo ip netns exec ns2 ip address add 198.51.100.1/24 dev ns2-veth0
ns1
と ns2
のデフォルトルートを router
の IP アドレスに向ける。
$ sudo ip netns exec ns1 ip route add default via 192.0.2.254 $ sudo ip netns exec ns2 ip route add default via 198.51.100.254
rotuer
がルータとして動作するようにカーネルパラメータを設定する。
$ sudo ip netns exec router sysctl net.ipv4.ip_forward=1
ひとまず、通常のルーティングが動作することを確認しておく。
$ sudo ip netns exec ns1 ping -c 3 198.51.100.1 -I 192.0.2.1 PING 198.51.100.1 (198.51.100.1) from 192.0.2.1 : 56(84) bytes of data. 64 bytes from 198.51.100.1: icmp_seq=1 ttl=63 time=0.217 ms 64 bytes from 198.51.100.1: icmp_seq=2 ttl=63 time=0.043 ms 64 bytes from 198.51.100.1: icmp_seq=3 ttl=63 time=0.191 ms --- 198.51.100.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2026ms rtt min/avg/max/mdev = 0.043/0.150/0.217/0.077 ms
VXLAN を設定する
つづいて、今回の主眼である VXLAN のインターフェイスを用意する。 VNI には 100 を使った。
まずは ns1
に VXLAN インターフェイスを作る。
$ sudo ip netns exec ns1 \ ip link add ns1-vxlan0 \ type vxlan \ id 100 \ remote 198.51.100.1 \ dstport 4789 \ dev ns1-veth0
つづいて ns2
にも VXLAN インターフェイスを作る。
$ sudo ip netns exec ns2 \ ip link add ns2-vxlan0 \ type vxlan \ id 100 \ remote 192.0.2.1 \ dstport 4789 \ dev ns2-veth0
あとは、作った VXLAN インターフェイスに IP アドレスを付与したら状態を UP に設定するだけ。
$ sudo ip netns exec ns1 ip link set ns1-vxlan0 up $ sudo ip netns exec ns1 ip address add 203.0.113.1/24 dev ns1-vxlan0 $ sudo ip netns exec ns2 ip link set ns2-vxlan0 up $ sudo ip netns exec ns2 ip address add 203.0.113.2/24 dev ns2-vxlan0
パケットキャプチャするために ns2
のインターフェイスに tcpdump をしかけておく。
$ sudo ip netns exec ns2 tcpdump -tnl -i ns2-veth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ns2-veth0, link-type EN10MB (Ethernet), capture size 262144 bytes
ns1
から ns2
に向けて Ping を打つ。
指定する IP アドレスは VXLAN インターフェイスのものを使う。
$ sudo ip netns exec ns1 ping -c 3 203.0.113.2 -I 203.0.113.1 PING 203.0.113.2 (203.0.113.2) from 203.0.113.1 : 56(84) bytes of data. 64 bytes from 203.0.113.2: icmp_seq=1 ttl=64 time=0.541 ms 64 bytes from 203.0.113.2: icmp_seq=2 ttl=64 time=0.094 ms 64 bytes from 203.0.113.2: icmp_seq=3 ttl=64 time=0.074 ms --- 203.0.113.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2010ms rtt min/avg/max/mdev = 0.074/0.236/0.541/0.215 ms
ちゃんとトンネリングが成功して、Ping の疎通がある。
先ほどしかけた tcpdump にも、VXLAN のパケットがキャプチャされている。 VXLAN のペイロードになっているパケット (フレーム) も一度に確認できるようだ。
$ sudo ip netns exec ns2 tcpdump -tnl -i ns2-veth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ns2-veth0, link-type EN10MB (Ethernet), capture size 262144 bytes IP 192.0.2.1.52760 > 198.51.100.1.4789: VXLAN, flags [I] (0x08), vni 100 IP 203.0.113.1 > 203.0.113.2: ICMP echo request, id 9404, seq 1, length 64 IP 198.51.100.1.52760 > 192.0.2.1.4789: VXLAN, flags [I] (0x08), vni 100 IP 203.0.113.2 > 203.0.113.1: ICMP echo reply, id 9404, seq 1, length 64 IP 192.0.2.1.52760 > 198.51.100.1.4789: VXLAN, flags [I] (0x08), vni 100 IP 203.0.113.1 > 203.0.113.2: ICMP echo request, id 9404, seq 2, length 64 IP 198.51.100.1.52760 > 192.0.2.1.4789: VXLAN, flags [I] (0x08), vni 100 IP 203.0.113.2 > 203.0.113.1: ICMP echo reply, id 9404, seq 2, length 64 IP 192.0.2.1.52760 > 198.51.100.1.4789: VXLAN, flags [I] (0x08), vni 100 IP 203.0.113.1 > 203.0.113.2: ICMP echo request, id 9404, seq 3, length 64 IP 198.51.100.1.52760 > 192.0.2.1.4789: VXLAN, flags [I] (0x08), vni 100 IP 203.0.113.2 > 203.0.113.1: ICMP echo reply, id 9404, seq 3, length 64
VXLAN インターフェイスの方で tcpdump をかけると、もちろん ICMP しか観測できない。
$ sudo ip netns exec ns2 tcpdump -tnl -i ns2-vxlan0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ns2-vxlan0, link-type EN10MB (Ethernet), capture size 262144 bytes IP 203.0.113.1 > 203.0.113.2: ICMP echo request, id 9408, seq 1, length 64 IP 203.0.113.2 > 203.0.113.1: ICMP echo reply, id 9408, seq 1, length 64 IP 203.0.113.1 > 203.0.113.2: ICMP echo request, id 9408, seq 2, length 64 IP 203.0.113.2 > 203.0.113.1: ICMP echo reply, id 9408, seq 2, length 64 IP 203.0.113.1 > 203.0.113.2: ICMP echo request, id 9408, seq 3, length 64 IP 203.0.113.2 > 203.0.113.1: ICMP echo reply, id 9408, seq 3, length 64
いじょう。
参考文献
https://www.kernel.org/doc/Documentation/networking/vxlan.txt
備考
ネットワークの物理的な構成を図示するのに使った blockdiag の定義は次のとおり。
blockdiag { ns1-vxlan0 [shape = endpoint]; ns1-veth0 [shape = minidiamond]; gw-veth0 [shape = minidiamond]; gw-veth1 [shape = minidiamond]; ns2-veth0 [shape = minidiamond]; ns2-vxlan0 [shape = endpoint]; group ns1 { orientation = portrait; label = 'ns1'; color = '#CCCCFF'; shape = line; ns1-veth0; ns1-vxlan0; } group router { label = 'router'; color = '#CCCCFF'; shape = line; gw-veth0; gw-veth1; } group ns2 { orientation = portrait; label = 'ns2'; color = '#CCCCFF'; shape = line; ns2-veth0; ns2-vxlan0; } ns1-vxlan0 -- ns1-veth0 [style = dotted]; ns1-veth0 -- gw-veth0; gw-veth1 -- ns2-veth0; ns2-veth0 -- ns2-vxlan0 [style = dotted]; ns1-vxlan0 -- ns2-vxlan0 [color = '#77FF77', style = dashed]; }
ネットワークの論理的な構成を図示するのに使った nwdiag の定義は次のとおり。
nwdiag { network { address = '192.0.2.0/24'; ns1[address = 'ns1-veth0, 192.0.2.1']; router[address = 'gw-veth0, 192.0.2.254']; } network { address = '198.51.100.0/24'; router[address = 'gw-veth1, 198.51.100.254']; ns2[address = 'ns2-veth0, 198.51.100.1']; } network { address = '203.0.113.0/24'; ns1[address = 'ns1-vxlan0, 203.0.113.1']; ns2[address = 'ns2-vxlan0, 203.0.113.2']; } }