🌏

network namespaceで遊ぶ

2022/05/27に公開

network namespaceとは

Linuxに備わっているnetwork namespace機能を用いることで、IPに関する処理を1台のLinuxの中で複数に分割することができます。ネットワーク機器でいうところのVRF(Virtual Rouring and Forwarding)に近いことができます。

network namespaceを使うことで、Linux 1台だけで複数台の機器をエミュレートできるのでいろいろ遊べそう。

構成図

作ってみるネットワークはこんな感じ。
ルータ2台の両端に端末があるだけのthe simpleという構成。


物理NW構成図


論理NW構成図

作成

network namespace(≒仮想ノード)作成

ip netns addでnetwork namespeceを作成します。root権限で実行する必要があります。
先の物理NW図で箱が4個あるとおり、4個のnetwork namespaceを作成します。

# create network namespaces
ip netns add router1
ip netns add router2
ip netns add host1
ip netns add host2

これでrouter1, router2, host1, host2という4つのnetwork namespaceと最初から存在するデフォルトのnetwork namespaceの合計5個のnetwork namespaceが存在することになります。
この5個のnetwork namespaceはお互いに独立していてそれぞれ別のルーティングテーブル等を持ちます。

veth pair(≒仮想LANケーブル)作成

veth(Virtual ethernet interface) pairを作成します。
これは物理世界でいうとLANケーブル(とNICを合体させたもの)のようなもので、ip link add xxx type veth peer name yyyで両端のNIC名がxxxとyyyであるLANケーブルを作成します。
さらにnetnsキーワードをつけることで両端のNICを先ほど作成したnetwork namespaceの中に作成することができます。
こちらは先の物理NW図でケーブルが3本あるとおり、3個のveth pairを作成します。

# create cable(veth pairs)
ip link add eth0 netns host1 type veth peer name e1 netns router1
ip link add e0 netns router1 type veth peer name e0 netns router2
ip link add e1 netns router2 type veth peer name eth0 netns host2

IPアドレス設定

IPアドレスを設定します。
普通はip addr add 10.0.1.10/24 dev eth0というコマンドでIPアドレスを設定するのですが、network namespaceの中でIPアドレスを設定するには先頭にip netns exec NS名をつけます。
ルータはパケットをルーティングさせるためにip_forwardを1(有効)にしています。

# set IP address: host1
ip netns exec host1 ip addr add 10.0.1.10/24 dev eth0

# set IP address: host2
ip netns exec host2 ip addr add 10.0.2.10/24 dev eth0

# set IP address: router1
ip netns exec router1 sysctl -w net.ipv4.ip_forward=1
ip netns exec router1 ip addr add 10.0.0.1/24 dev e0
ip netns exec router1 ip addr add 10.0.1.1/24 dev e1

# set IP address: router2
ip netns exec router2 sysctl -w net.ipv4.ip_forward=1
ip netns exec router2 ip addr add 10.0.0.2/24 dev e0
ip netns exec router2 ip addr add 10.0.2.1/24 dev e1

異なるnetwork namespaceの中に同名のNICを作成することができます(上でのeth0とか)。
また、network namespaceごとにネットワーク関係の機能のON/OFFを設定できるので、ip_forwardはrouter1, router2それぞれで必要です[1]

veth pairは作成した段階ではlink down状態なので、link upさせていきます。
network namespaceを作成すると、自動的に作成されるloopback interface "lo"もlink upさせます。

# linkup & set routes (routes can not be set before linkup.)
ip netns exec router1 ip link set lo up
ip netns exec router1 ip link set e1 up
ip netns exec router1 ip link set e0 up

ip netns exec router2 ip link set lo up
ip netns exec router2 ip link set e0 up
ip netns exec router2 ip link set e1 up

ip netns exec host1 ip link set lo up
ip netns exec host1 ip link set eth0 up

ip netns exec host2 ip link set lo up
ip netns exec host2 ip link set eth0 up

ルーティング設定

いよいよ最終段階です。各network namespaceにルーティング(デフォルトゲートウェイ)を設定していきます。

ip netns exec router1 ip route add default via 10.0.0.2
ip netns exec router2 ip route add default via 10.0.0.1
ip netns exec host1 ip route add default via 10.0.1.1
ip netns exec host2 ip route add default via 10.0.2.1

なんとなく設定の流れとしてはIPアドレスを設定したときにルーティング設定もしたくなるのですが、インターフェイスがlink upしてないとip addr addコマンドがエラーとなるのでこの段階でルーティング設定します。

動作確認

ping

pingで疎通確認します。これまで何度か紹介したとおり、network namespaceの中に入ってコマンドを打つときは、いつも使っているpingコマンドの先頭にip netns exec NS名をつけます。

# ip netns exec host1 ping -c 10 10.0.2.10
PING 10.0.2.10 (10.0.2.10) 56(84) bytes of data.
64 bytes from 10.0.2.10: icmp_seq=1 ttl=62 time=0.036 ms
64 bytes from 10.0.2.10: icmp_seq=2 ttl=62 time=0.037 ms
64 bytes from 10.0.2.10: icmp_seq=3 ttl=62 time=0.037 ms
64 bytes from 10.0.2.10: icmp_seq=4 ttl=62 time=0.050 ms
64 bytes from 10.0.2.10: icmp_seq=5 ttl=62 time=0.049 ms
64 bytes from 10.0.2.10: icmp_seq=6 ttl=62 time=0.104 ms
64 bytes from 10.0.2.10: icmp_seq=7 ttl=62 time=0.035 ms
64 bytes from 10.0.2.10: icmp_seq=8 ttl=62 time=0.038 ms
64 bytes from 10.0.2.10: icmp_seq=9 ttl=62 time=0.037 ms
64 bytes from 10.0.2.10: icmp_seq=10 ttl=62 time=0.047 ms

--- 10.0.2.10 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9184ms
rtt min/avg/max/mdev = 0.035/0.047/0.104/0.019 ms

無事通りました。
TTLが62となっています。
TTLは初期値が64, 128, 255のどれかになっていることが多いので、TTLが62ということは、最初は64だったTTLがL3装置を2ホップして62になったと推定できます。論理NW構成図通りでちゃんと想定通りの動作をしていると考えることができます。

arp

L3レベルで通っているということはL2レベルも通っているはずですが、念のためarpコマンドでL2も確認しておきます。
host1から見たrouter1のMACアドレスと、router1に付与されたMACアドレスがどちらも同じ値(以下の例だと2a:05:9c:9f:93:b1)になっていて、ARP解決が無事にできているとわかります。

# ip netns exec host1 arp -an
? (10.0.1.1) at 2a:05:9c:9f:93:b1 [ether] on eth0
# ip netns exec router1 ip link show e1
2: e1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 2a:05:9c:9f:93:b1 brd ff:ff:ff:ff:ff:ff link-netns host1

お掃除

実験が終わったら、再起動すればこのページで設定したものは消えます。

再起動なしに削除したいときはこちら。

ip netns exec host1 ip link del eth0
ip netns exec router1 ip link del e0
ip netns exec router2 ip link del e1
ip netns del host1
ip netns del host2
ip netns del router1
ip netns del router2

参考:動作確認を行った環境について

# cat /etc/issue
Ubuntu 22.04 LTS \n \l

# uname -r
5.15.0-30-generic
# dpkg -l iproute2
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version         Architecture Description
+++-==============-===============-============-====================================
ii  iproute2       5.15.0-1ubuntu2 amd64        networking and traffic control tools
脚注
  1. デフォルトnetwork namespaceの設定を引き継ぐので、デフォルトnetwork namespaceでsysctl -w net.ipv4.ip_forward=1として、router1, router2 network namespaceでは何もしない、というのも可です。 ↩︎

Discussion