APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

LinuxのNetwork Namespaceで手元にネットワークテスト環境を作る

はじめに

先進サービス開発事業部の山岡です。

最近Raw Socketで通信するプログラムを書いているのですが、試しにパケットを送って他所と上手く通信できるか確認したい時に実機を使うのは大変面倒です。こういった場合にLinuxのNetwork Namespaceを使えば手軽にルーティング環境を作ることができるので手順を残したいと思います。

構築する環境

以下のようにルーター1台を挟んでサーバー同士が通信できるネットワークを作ります。ちなみにアイコンはShownet Iconをお借りしました *1。ありがとうございます。

f:id:ryo-yamaoka:20190628003859p:plain
構成図

前提条件

以下の環境で構築しました。

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"

手順

特に複雑でもないコマンドの羅列なのでシェルスクリプトにしました。コピペ&実行すれば一発で構築できるはずです。

# !/bin/bash
set -eu

# Network Namespaceの作成
sudo ip netns add server1
sudo ip netns add router
sudo ip netns add server2

# インターフェースの作成
# peer で指定した相手と接続関係になる
sudo ip link add name server1-veth1 type veth peer name router-veth1
sudo ip link add name router-veth2 type veth peer name server2-veth1

# インターフェースを各Namespaceに所属させる
sudo ip link set server1-veth1 netns server1
sudo ip link set router-veth1 netns router
sudo ip link set router-veth2 netns router
sudo ip link set server2-veth1 netns server2

# 各インターフェースへIPアドレスを付与
sudo ip netns exec server1 ip addr add 10.0.0.1/24 dev server1-veth1
sudo ip netns exec router ip addr add 10.0.0.254/24 dev router-veth1
sudo ip netns exec router ip addr add 10.0.1.254/24 dev router-veth2
sudo ip netns exec server2 ip addr add 10.0.1.1/24 dev server2-veth1

# 各インターフェースの起動
# lo には自動的に 127.0.0.1/8 が割り当てられます
sudo ip netns exec server1 ip link set server1-veth1 up
sudo ip netns exec router ip link set router-veth1 up
sudo ip netns exec router ip link set router-veth2 up
sudo ip netns exec server2 ip link set server2-veth1 up
sudo ip netns exec server1 ip link set lo up
sudo ip netns exec router ip link set lo up
sudo ip netns exec server2 ip link set lo up

# サーバーのデフォルトルートを設定+ルーターでルーティングを有効化
sudo ip netns exec server1 ip route add 0.0.0.0/0 via 10.0.0.254
sudo ip netns exec server2 ip route add 0.0.0.0/0 via 10.0.1.254
sudo ip netns exec router sysctl -w net.ipv4.ip_forward=1

結果確認

インターフェースが以下のようになっていればOKです( lo は省略)。

$ sudo ip netns exec server1 ip addr && sudo ip netns exec server1 ip route
39: server1-veth1@if38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether ce:d6:72:f0:c8:03 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 10.0.0.1/24 scope global server1-veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::ccd6:72ff:fef0:c803/64 scope link
       valid_lft forever preferred_lft forever
default via 10.0.0.254 dev server1-veth1
10.0.0.0/24 dev server1-veth1 proto kernel scope link src 10.0.0.1

$ sudo ip netns exec server2 ip addr && sudo ip netns exec server2 ip route
40: server2-veth1@if41: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether a6:36:cb:38:ff:14 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.1.1/24 scope global server2-veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a436:cbff:fe38:ff14/64 scope link
       valid_lft forever preferred_lft forever
default via 10.0.1.254 dev server2-veth1
10.0.1.0/24 dev server2-veth1 proto kernel scope link src 10.0.1.1

$ sudo ip netns exec router ip addr && sudo ip netns exec router ip route
38: router-veth1@if39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether aa:6d:fb:d1:82:89 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.0.254/24 scope global router-veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a86d:fbff:fed1:8289/64 scope link
       valid_lft forever preferred_lft forever
41: router-veth2@if40: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 5e:a0:a5:5e:17:0c brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet 10.0.1.254/24 scope global router-veth2
       valid_lft forever preferred_lft forever
    inet6 fe80::5ca0:a5ff:fe5e:170c/64 scope link
       valid_lft forever preferred_lft forever
10.0.0.0/24 dev router-veth1 proto kernel scope link src 10.0.0.254
10.0.1.0/24 dev router-veth2 proto kernel scope link src 10.0.1.254

サーバー1からサーバー2へのtracepathの結果(きちんとルーティングされているのがわかります)。

$ sudo ip netns exec server1 tracepath -n 10.0.1.1
 1?: [LOCALHOST]                      pmtu 1500
 1:  10.0.0.254                                            0.055ms
 1:  10.0.0.254                                            0.169ms
 2:  10.0.1.1                                              0.114ms reached
     Resume: pmtu 1500 hops 2 back 2

使い方

既に散々手順に出てきていますが、各ネットワーク内部で何かをしたい場合は sudo ip netns exec <namespace> <command> で実行できます。これはVMやコンテナと違いあくまでネットワークだけが分離されているので、ローカルで使用可能なものは各Namespace内でもそのまま実行することができます。

例えばルーターでパケットキャプチャーをしつつサーバー1からサーバー2にPingを打ちたい場合は以下のようになります(シェルを2つ起動するといいでしょう)。

# シェル1
$ sudo ip netns exec server1 ping 10.0.1.1
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
64 bytes from 10.0.1.1: icmp_seq=1 ttl=63 time=0.027 ms
# シェル2
$ sudo ip netns exec router tcpdump -nn -l
[sudo] password for ca:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on router-veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
00:20:02.180211 IP 10.0.0.1 > 10.0.1.1: ICMP echo request, id 14454, seq 1, length 64
00:20:02.180230 IP 10.0.1.1 > 10.0.0.1: ICMP echo reply, id 14454, seq 1, length 64

オマケ:ベンチマークしてみた

仮想的なネットワークでハードウェアの制約を受けないためか凄い速度が出ます。これは仮想環境(VirtualBox)の結果ですが、実機に直接OSをインストールした環境では50Gbpsくらい出ました。

# シェル1
$ sudo ip netns exec server1 iperf3 -c 10.0.1.1
# シェル2
$ sudo ip netns exec server2 iperf3 -s
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------
Accepted connection from 10.0.0.1, port 48870
[  5] local 10.0.1.1 port 5201 connected to 10.0.0.1 port 48872
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-1.00   sec  3.74 GBytes  32.1 Gbits/sec
[  5]   1.00-2.00   sec  3.93 GBytes  33.7 Gbits/sec
[  5]   2.00-3.00   sec  3.85 GBytes  33.1 Gbits/sec
[  5]   3.00-4.00   sec  3.95 GBytes  33.9 Gbits/sec
[  5]   4.00-5.00   sec  3.93 GBytes  33.8 Gbits/sec
[  5]   5.00-6.00   sec  4.01 GBytes  34.4 Gbits/sec
[  5]   6.00-7.00   sec  4.03 GBytes  34.6 Gbits/sec
[  5]   7.00-8.00   sec  4.01 GBytes  34.4 Gbits/sec
[  5]   8.00-9.00   sec  3.98 GBytes  34.2 Gbits/sec
[  5]   9.00-10.00  sec  4.02 GBytes  34.5 Gbits/sec
[  5]  10.00-10.04  sec   158 MBytes  34.3 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-10.04  sec  0.00 Bytes  0.00 bits/sec                  sender
[  5]   0.00-10.04  sec  39.6 GBytes  33.9 Gbits/sec                  receiver