Network Namespaceを使ってみた

はじめに

LinuxのNetwork Namespaceを使って簡単なネットワークを構築してみました。

環境

  • 20.04.5 LTS

構築する環境


namespace( 仮装ノード)作成

$ sudo ip netns add host1
$ sudo ip netns add router
$ sudo ip netns add host2

namespaceが作成されたことを確認

$ ip netns list
host2
router
host1

veth(仮装ネットワークインターフェース)作成

host1とrouter、routerとhost2を疎通させるためにvethを作成します

$ sudo ip link add host1-veth0 type veth peer name router-veth0
$ sudo ip link add host2-veth1 type veth peer name router-veth1

vethが作成されたことを確認

$ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 02:cd:6a:13:84:49 brd ff:ff:ff:ff:ff:ff
3: router-veth0@host1-veth0: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 9a:6c:9f:8a:2f:d4 brd ff:ff:ff:ff:ff:ff
4: host1-veth0@router-veth0: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether da:dd:38:f8:83:70 brd ff:ff:ff:ff:ff:ff
5: router-veth1@host2-veth1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 06:90:17:48:f0:ff brd ff:ff:ff:ff:ff:ff
6: host2-veth1@router-veth1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 1a:ee:a4:59:b6:4f brd ff:ff:ff:ff:ff:ff

vethをnamespaceに所属させる

$ sudo ip link set host1-veth0 netns host1
veth一覧からhost1-veth0@router-veth0が消えていることを確認
$ ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 02:cd:6a:13:84:49 brd ff:ff:ff:ff:ff:ff
3: router-veth0@if4: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 9a:6c:9f:8a:2f:d4 brd ff:ff:ff:ff:ff:ff link-netns host1
5: router-veth1@host2-veth1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 06:90:17:48:f0:ff brd ff:ff:ff:ff:ff:ff
6: host2-veth1@router-veth1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 1a:ee:a4:59:b6:4f brd ff:ff:ff:ff:ff:ff
他のvethも同様に所属させます
$ sudo ip link set router-veth0 netns router
$ sudo ip link set router-veth1 netns router
$ sudo ip link set host2-veth1 netns host2

vethを有効化する

$ sudo ip netns exec host1 ip link set host1-veth0 up
$ sudo ip netns exec router ip link set router-veth0 up
$ sudo ip netns exec router ip link set router-veth1 up
$ sudo ip netns exec host2 ip link set host2-veth1 up

IPアドレスを付与

各vethにそれぞれのセグメント内のIPアドレスを付与させます

sudo ip netns exec host1 ip address add 192.0.1.1/24 dev host1-veth0
host1-veth0にIPアドレスが付与されていることを確認
inetはIPv4 アドレスを表すのでIPアドレスが付与されていることがわかります
sudo ip netns exec host1 ip address show
1: lo: mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: host1-veth0@if3: mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether da:dd:38:f8:83:70 brd ff:ff:ff:ff:ff:ff link-netns router
inet 192.0.1.1/24 scope global host1-veth0
valid_lft forever preferred_lft forever
inet6 fe80::d8dd:38ff:fef8:8370/64 scope link
valid_lft forever preferred_lft forever
他のvethも同様にIPアドレスを付与します
$ sudo ip netns exec router ip address add 192.0.1.254/24 dev router-veth0
$ sudo ip netns exec router ip address add 196.0.1.254/24 dev router-veth1
$ sudo ip netns exec host2 ip address add 196.0.1.1/24 dev host2-veth1

疎通確認

host1からrouterへの疎通を確認

$ sudo ip netns exec host1 ping -c 3 192.0.1.254 -I 192.0.1.1
PING 192.0.1.254 (192.0.1.254) from 192.0.1.1 : 56(84) bytes of data.
64 bytes from 192.0.1.254: icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from 192.0.1.254: icmp_seq=2 ttl=64 time=0.034 ms
64 bytes from 192.0.1.254: icmp_seq=3 ttl=64 time=0.033 ms

--- 192.0.1.254 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2032ms
rtt min/avg/max/mdev = 0.031/0.032/0.034/0.001 ms

疎通が通れていることがわかったのでrouterからhost2への疎通を確認します
$ sudo ip netns exec router ping -c 3 196.0.1.1 -I 196.0.1.254
PING 196.0.1.1 (196.0.1.1) from 196.0.1.254 : 56(84) bytes of data.
64 bytes from 196.0.1.1: icmp_seq=1 ttl=64 time=0.135 ms
64 bytes from 196.0.1.1: icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from 196.0.1.1: icmp_seq=3 ttl=64 time=0.115 ms

--- 196.0.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2054ms
rtt min/avg/max/mdev = 0.051/0.100/0.135/0.035 ms

routerを介して通信する

同じセグメント内での疎通は確認できたので、host1からhost2へ疎通がとれるようにしていきます
現在は通信をしようとするとエラーが起きます

$ sudo ip netns exec host1 ping -c 3 196.0.1.1 -I 192.0.1.1
PING 196.0.1.1 (196.0.1.1) from 192.0.1.1 : 56(84) bytes of data.
ping: sendmsg: Network is unreachable
ping: sendmsg: Network is unreachable
ping: sendmsg: Network is unreachable

--- 196.0.1.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2059ms

host1にデフォルトルートを追加

現在のhost1のルーティングテーブルを確認するとhost1と違うセグメントに対する設定がされていないようです
そのためデフォルートをrouterへと向けます

$ sudo ip netns exec host1 ip route show
192.0.1.0/24 dev host1-veth0 proto kernel scope link src 192.0.1.1

デフォルトルートを追加できました

$ sudo ip netns exec host1 ip route show
default via 192.0.1.254 dev host1-veth0
192.0.1.0/24 dev host1-veth0 proto kernel scope link src 192.0.1.1
host2にも同様にデフォルトルートを追加します
$ sudo ip netns exec host2 ip route add default via 196.0.1.254

routerとして設定

最後にrouterをrouterとして動くように設定します

$ sudo ip netns exec router sysctl net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

疎通確認

host1からhost2への疎通確認をします

$ sudo ip netns exec host1 ping -c 3 196.0.1.1 -I 192.0.1.1
PING 196.0.1.1 (196.0.1.1) from 192.0.1.1 : 56(84) bytes of data.
64 bytes from 196.0.1.1: icmp_seq=1 ttl=63 time=0.029 ms
64 bytes from 196.0.1.1: icmp_seq=2 ttl=63 time=0.060 ms
64 bytes from 196.0.1.1: icmp_seq=3 ttl=63 time=0.044 ms

--- 196.0.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2051ms
rtt min/avg/max/mdev = 0.029/0.044/0.060/0.012 ms

無事に疎通を確認できました

最後に

今回はrouterを用いた簡単なネットワークを構築してみました。
Network Namespaceは手軽にネットワークに関する実験ができるのでネットワーク学習に最適だなと思いました。
これ以外にもWANやNATの設定などもできるので試してみてはいかがでしょうか。