Network Namespaceを使って、Linux上で仮想のネットワーク環境を作る

はじめに

ネットワークで色々実験したいときに自分自身の環境内で完結するネットワークが欲しい時があると思います。この記事ではNetwork Namespaceを使って自分のPC内に仮想のネットワークを作ってpingコマンドを送信してみたいと思います。 最初にお断りしておきますが、この内容はLinuxで動かしながら学ぶTCP/IPネットワーク入門の内容に対して、自分で気になった点を少し深堀りしただけの内容となっております。めちゃくちゃわかりやすくて良い内容ですので、きちんと学びたい方は書籍の方をご購入ください。

Network Namespaceとは

Linux内のネットワークスタックをネームスペースで分離する機能です。ネームスペースは、自身のルートテーブル、firewall、ネットワークディバイスを持つことができます。あたかも別のLinuxを用意したように全く別のネットワークシステムとして扱うことができます。ネームスペースは開くことが可能な/var/run/netns/NAMEのファイルオブジェクトであり、ファイルディスクリプタがそのオブジェクトを掴み続けている限りネームスペースは生きている状態となります。
Network NamespaceはDockerなどの仮想化技術にも用いられているようです。

仮想のネットワークを作ってみる

Namespaceを作成する

ネームスペースを作成するにはipコマンドを用います。以下のコマンドを叩きます。

$ sudo ip netns add nw-1
$ sudo ip netns add nw-2

nw-1nw-2という名前のネームスペースを作成しました。今回はこの2つをネットワークとしてつなぎます。
作成したネームスペースをリストで表示するには以下のコマンドを叩きます。

$ ip netns list
nw-2
nw-1

作成したネームスペースはそのままでは永続化されません。再起動時に削除されます。
作ったネームスペースを明示的に削除する場合は以下のコマンドを実行します。

$ sudo ip netns delete [ネームスペース名]

ネットワークインターフェースの作成

作成したネームスペースにVirtual Ethernet Deviceという仮想ネットワークインタフェースを作成します。以下のコマンドを実行します。

$ sudo ip link add veth-1 type veth peer name veth-2

以下のコマンドで作成したネットワークインターフェースを確認することができます。

$ ip link show | grep veth
7: veth-2@veth-1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
8: veth-1@veth-2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

ちゃんと作成されているみたいですね。
上記の出力は2つのネットワークインターフェースが繋がった状態を表しており、LANで繋がれた二つのネットワークインターフェースのような感じになっているみたいです。

次に作成したインターフェースをそれぞれのネームスペースにセットしていきます。

$ sudo ip link set weth-1 netns nw-1
$ sudo ip link set weth-2 netns nw-2

これで2つのネームスペースが繋がった状態になりました。しかし、まだ仮想のLANで繋がっただけのような状態であり、通信を行なうためには設定が必要となります。

ネームスペースにIPアドレスを割り当てる

通信を行なうためにはIPアドレスが必要です。以下のコマンドを実行しveth-1veth-2に対してIPアドレスを割り当てます。

$ sudo ip netns exec nw-1 ip address add 192.0.2.1/24 dev veth-1
$ sudo ip netns exec nw-2 ip address add 192.0.2.2/24 dev veth-2

ちなみに使用しているIPアドレスドキュメンテーションアドレスと呼ばれRFC5737で定義さている。ドキュメントなどに用いるIPアドレスとなっています。以下のCIDRブロックがドキュメント用に事前に予約されています。

  • 192.0.2.0/24 (TEST-NET-1)
  • 198.51.100.0/24 (TEST-NET-2)
  • 203.0.113.0/24 (TEST-NET-3)

ネットワークインターフェースをUPの状態にする

まだ、通信を行なうことはできません。ネットワークインターフェースにはUP(有効状態)とDOWN(無効状態)が存在します。先程のip link showの結果をもう一度見てみます。

7: veth-2@veth-1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
8: veth-1@veth-2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

作成したネットワークインターフェースはDOWN状態となっています。つまり、通信を行なうためにはこれをUPの状態にしなければなりません。
以下のコマンドを実行してください。

$ sudo ip netns exec nw-1 ip link set veth-1 up
$ sudo ip netns exec nw-2 ip link set veth-2 up

これで、それぞれのネットワークインターフェースをUPの状態に変更できました。

いざ、pingを打つ!!!

ネームスペース上でコマンドを実行する際は以下のような形式でコマンドを入力します。

$ sudo ip netns exec [ネームスペース] [コマンド]

また、以下のように実行するとbashとして起動することも可能です。

$ sudo ip netns exec [ネームスペース] bash

では、nw-1からnw-2に向けてpingを打ちます。

sudo ip netns exec nw-1 bash
root@yuya-hirooka:~# sudo ip netns exec nw-1 ping -c 3 192.0.2.2
PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.055 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.055 ms

--- 192.0.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2040ms
rtt min/avg/max/mdev = 0.029/0.046/0.055/0.013 ms

疎通が行えているようですね! これで仮想のネットワークを作成することができました!