LoginSignup
15
7

More than 1 year has passed since last update.

Network Namespace を使用してネットワークに触れてみる

Posted at

Network Namespaceとは?

スクリーンショット 2023-01-15 15.22.22.png

  • ネットワーク的にシステムから独立した環境の作成が出来る
  • IPに関する処理を1台のLinux内で複数に分割することが出来る
  • Dockerのようなコンテナ型仮想技術を構成する要素の一つ

環境

仮想マシンとしてUbuntuをインストールして、ubuntu上で検証します

Network Namespaceを使ってみる

$ sudo ip netns add practice
$ ip netns list
practice

practiceという名前のNetwork Namespaceを作成します

スクリーンショット 2023-01-15 15.24.51.png

ip netns listでは、作成されたNetwork Namespaceの確認をします

ネットワークインターフェイスと、ルーティングテーブルの確認

Network Namespace.
$ sudo ip netns exec practice ip address show
1: lo: <LOOPBACK> 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

先ほど作成したNetwork Namespace環境で$ ip address showコマンドの実行しています
1つのネットワークインターフェース(1: lo)が表示されています

今度は、Network Namespaceを使用せずに実行してみます

$ ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 02:d9:74:4e:9b:d3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
       valid_lft 82340sec preferred_lft 82340sec
    inet6 fe80::d9:74ff:fe4e:9bd3/64 scope link
       valid_lft forever preferred_lft forever

表示される内容は変わり、こちらの環境ではネットワークインターフェース(2: enp0s3)が表示されました

今度はルーティングテーブルの確認をします

(Network Namespaceを使用しない場合)

ip route show
default via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15
10.0.2.2 dev enp0s3 proto dhcp scope link src 10.0.2.15 metric 100

続いて、

(Network Namespace環境の場合)

Network Namespace.
$ sudo ip netns exec practice ip route show
Error: ipv4: FIB table does not exist.
Dump terminated

このエラーから、ルーティングテーブルが存在しないことが確認できます
Network Namespaceへルーティングエントリを登録していないためです

実際に繋いでみる

スクリーンショット 2023-01-15 17.15.20.png

2つのNetwork Namespaceを繋いでみます。
仮想的なネットワーク環境が2つあるようにイメージします。そのネットワークを仮想的なLANケーブルで繋いでみます。

まずは、それぞれのネットワークを作成します

$ sudo ip netns add practice1
$ sudo ip netns add practice2
$ sudo ip netns list
practice2
practice1

作成したネットワーク同士を繋ぎます

$ sudo ip link add practice1-veth0 type veth peer name practice2-veth0
$ ip link show | grep veth
3: practice2-veth0@practice1-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
4: practice1-veth0@practice2-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

practice1-veth0practice2-veth0は作成するネットワークインターフェイスの名前です。
ip link show | grep vethから無事作成できていることが確認できます

しかし、現状は作成したvethインターフェイスはNetwork Namespaceで使用できないため使えるようにしていきます
そのためにシステム領域 → Network Namespace領域へ移す必要があります

$ sudo ip link set practice1-veth0 netns practice1
$ sudo ip link set practice2-veth0 netns practice2

これで、vethインターフェイスがNetwork Namespaceで使用できるようになりました

$ ip link show | grep veth

システム側ではもう確認できないことが分かります
Network Namespace側で確認してみます

$ sudo ip netns exec practice1 ip link show | grep veth
4: practice1-veth0@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
$ sudo ip netns exec practice2 ip link show | grep veth
3: practice2-veth0@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

これで、Network Namespace同士が仮想的なLANケーブルにつながりました。

しかし、これだけでは通信が出来ないので設定を行なっていきます

通信の設定

IPを使用して通信を行うためにvethインターフェイスにIPアドレスを付与します

$ sudo ip netns exec practice1 ip address add 192.0.2.1/24 dev practice1-veth0
$ sudo ip netns exec practice2 ip address add 192.0.2.2/24 dev practice2-veth0

これでIPアドレスの付与が出来ました
これで、通信ができる?

$ sudo ip netns exec practice1 ip link show practice1-veth0 | grep state
4: practice1-veth0@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
$ sudo ip netns exec practice2 ip link show practice2-veth0 | grep state
3: practice2-veth0@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

まだ出来ないみたいです。
ネットワークインタフェースがstate DOWNになっています。
ネットワークインターフェースは初期状態ではDOWNになっていて通信が出来ないようです

ネットワークインターフェースのリンクをUPへ変更し、通信ができるようにします

$ sudo ip netns exec practice1 ip link set practice1-veth0 up
$ sudo ip netns exec practice2 ip link set practice2-veth0 up

ここまで来れば、pingコマンドで疎通の確認をしてみます

$ sudo ip netns exec practice1 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=2.19 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.056 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.054 ms

--- 192.0.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2022ms
rtt min/avg/max/mdev = 0.054/0.765/2.185/1.004 ms

これで、TCP/IP環境が出来上がりました
practice1 → practice2 へpingで疎通確認を行なってみます

$ sudo ip netns exec practice1 ping -c 3 192.0.2.2 -I 192.0.2.1
PING 192.0.2.2 (192.0.2.2) from 192.0.2.1 : 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.033 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.043 ms

--- 192.0.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms
rtt min/avg/max/mdev = 0.033/0.040/0.044/0.005 ms

-Iオプションの後の、192.0.2.1が送信元のIPアドレスです。
返答がある事を確認できました

ルータは必要ないのか?

ここまでの構築では ルータを使用することなくIPを使ったネットワークが構築出来ました。
ルータ無しでなぜ通信が出来たのか?

それは、IPで構築されたネットワークのセグメントが関係しています

同じセグメントに属するIP同士はルータがなくても互いに通信を行うことが出来ます

セグメント・・・ネットワーク部とホスト部を識別するためにあります。
例えば、192.0.2.1/24のIPアドレスの場合は192.0.2.0がネットワークアドレスになります
ネットワーク部(192.0.2)が同じIPアドレスは、同じセグメントに属しているということになります

先ほど構築したvethインターフェイスを例にとってみます。

スクリーンショット 2023-01-27 0.51.48.png

/24。つまり、先頭から24bitなので赤字の部分がネットワーク部になります。

両方に同じセグメントのIPが振られているのでルータがなくても通信が可能になります

実際にルータを入れてみる

スクリーンショット 2023-01-27 1.28.52.png

ルータを使用したネットワークを作成します。
ルータがあるということは、セグメントが2つになります

構成図は以下です。

スクリーンショット 2023-01-28 8.43.26.png

ルータを合わせたNetwork namespaceが1つ増えて3つになりました。

ここでは、セグメントを跨いだ通信をします。
つまり、間にルータがある状態でpractice1とpractice2の間をパケット通信してみます

実際にネットワークを作っていく

最初に作成したネットワークをまずは消しておきます

$ sudo ip list
practice1
practice2

listで確認してから先ほど作成したnetwork namespaceを全て削除します

$ sudo ip --all netns delete

ルータも含めた3つのnetwork namespace を作成します

$ sudo ip netns add practice1
$ sudo ip netns add practice2
$ sudo ip netns add router
$ sudo ip netns list
router
practice2
practice1

続いて、インターフェースを作成します

セグメント practice ルータ側
1 practice1-veth0 gw-veth0
2 practice2-veth0 gw-veth1
$ sudo ip link add practice1-veth0 type veth peer name gw-veth0
$ sudo ip link add practice2-veth0 type veth peer name gw-veth1

それぞれのNetWork Namespace へインターフェースを所属させて、UPします

NetWork Namespace インターフェース
practice1 practice1-veth0
router gw-veth0 & gw-veth1
practice2 practice2-veth0
$ sudo ip link set practice1-veth0 netns practice1
$ sudo ip link set gw-veth0 netns router
$ sudo ip link set gw-veth1 netns router
$ sudo ip link set practice2-veth0 netns practice2

vagrant@ubuntu-focal:~$ sudo ip netns exec practice1 ip link set practice1-veth0 up
vagrant@ubuntu-focal:~$ sudo ip netns exec router ip link set gw-veth0 up
vagrant@ubuntu-focal:~$ sudo ip netns exec router ip link set gw-veth1 up
vagrant@ubuntu-focal:~$ sudo ip netns exec practice2 ip link set practice2-veth0 up

続いて、IPアドレスの設定を行います

Network Namespace IPアドレス インターフェース
practice1 192.0.2.1/24 practice1-veth0
router 192.0.2.254/24 gw-veth0
router 192.51.100.254/24 gw-veth1
practice2 192.51.100.1/24 practice2-veth0

practice1とrouter間の設定を行います。
それぞれのインターフェースに同セグメントのIPを当てます

$ sudo ip netns exec practice1 ip address add 192.0.2.1/24 dev practice1-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 192.51.100.254/24 dev gw-veth1
$ sudo ip netns exec practice2 ip address add 192.51.100.1/24 dev practice2-veth0

ここまでできれば、practice1 - router 間の疎通確認を行います

$ sudo ip netns exec practice1 ping -c 3 192.0.2.254 -I 192.0.2.1
PING 192.0.2.254 (192.0.2.254) from 192.0.2.1 : 56(84) bytes of data.
64 bytes from 192.0.2.254: icmp_seq=1 ttl=64 time=2.78 ms
64 bytes from 192.0.2.254: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 192.0.2.254: icmp_seq=3 ttl=64 time=0.047 ms

--- 192.0.2.254 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.047/0.959/2.782/1.289 ms

practice2 - router 間も同様に

$ sudo ip netns exec practice2 ping -c 3 192.51.100.254 -I 192.51.100.1
PING 192.51.100.254 (192.51.100.254) from 192.51.100.1 : 56(84) bytes of data.
64 bytes from 192.51.100.254: icmp_seq=1 ttl=64 time=1.79 ms
64 bytes from 192.51.100.254: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 192.51.100.254: icmp_seq=3 ttl=64 time=0.048 ms

--- 192.51.100.254 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms
rtt min/avg/max/mdev = 0.047/0.627/1.786/0.819 ms

続いて、セグメントを超えた通信が可能か試してみます。

practice1 → practice2 へpingで疎通確認してみます

$ sudo ip netns exec practice1 ping -c 3 4/24 dev gw-veth1 192.51.100.1 -I 192.0.2.1
ping: 4/24: Temporary failure in name resolution

しかし、先ほどと同じ方法では疎通に失敗してしまいました。

Network Namespaceにルーティングの設定が必要になります
現状のNetwork Namespaceのルーティングを確認してみます

$ sudo ip netns exec practice1 ip route show
192.0.2.0/24 dev practice1-veth0 proto kernel scope link src 192.0.2.1

practice1にはルーティングエントリーが1つあります。
内容は、practice1-veth0というインターフェイスで192.0.2.0/24宛に通信を行うとあるので、
practice1と、practice2は直接はつながっていません

どうすればいいのか?🤔

ルーティングテーブルに新たにルーティングエントリを追加する必要があります

ルーティングエントリとして、デフォルトルート(すべてのルートを表す) を追加します

practice1にデフォルトルートを追加します

$ sudo ip netns exec practice1 ip route add default via 192.0.2.254
$ sudo ip netns exec practice1 ip route show
default via 192.0.2.254 dev practice1-veth0
192.0.2.0/24 dev practice1-veth0 proto kernel scope link src 192.0.2.1

192.0.2.254はルータのipアドレスで、デフォルトルートをルータに向けました

practice2にも、同様にデフォルトルートとなるルーティングエントリを追加します

$ sudo ip netns exec practice2 ip route add default via 192.51.100.254
$ sudo ip netns exec practice2 ip route show
default via 192.51.100.254 dev practice2-veth0
192.51.100.0/24 dev practice2-veth0 proto kernel scope link src 192.51.100.1

ここまで来れば、再度、practice1 → practice2への疎通確認をしてみます

~$ sudo ip netns exec practice1 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.

--- 198.51.100.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2035ms

エラーは出ませんでしたが、100% packet lossとあるように返答が無かったみたいです

ipフォワードの設定が必要になります

ここで、「IPフォワード」という技術が用意されています。この技術は、その名の通り、2つのNICの間でパケットを転送するという技術です。これにより、パケットが異なるネットワークの間を往き来できるようになります。
LinuxでIPフォワードを有効にするには、「/etc/sysctl.conf」ファイルに、「net.ipv4.ip_forward=1」という記述を行い(デフォルトではnet.ipv4.ip_forward=0)、ネットワークを再起動します。
https://linuc.org/study/knowledge/422/

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

これでもう一度試してみます

$ sudo ip netns exec practice1 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.
From 192.0.2.254 icmp_seq=1 Destination Net Unreachable
From 192.0.2.254 icmp_seq=2 Destination Net Unreachable
From 192.0.2.254 icmp_seq=3 Destination Net Unreachable

--- 198.51.100.1 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2031ms

今度は疎通が出来ました

おしまい

参考

15
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
7