技術三課の手塚です。入社から半年が過ぎましたが、もっと長く在籍しているような感覚もあり、大変密度の濃い時間を過ごしています。 さて、本記事は秒速でネットワークを作成する方法です。 Network namespace(以下 netns) と veth peer で軽量な仮想ネットワークを作成します。 - 結果と手順をすぐ知りたい方 => まとめ - 時間はあるので詳しく見たい方 => 詳細
まとめ
- Linux 上に 2 ノード直結のネットワークを作成しました
- この設定に netns と veth peer を使用しました
- この手順を実行したところ、秒速でネットワーク作成が完了しました
構成図
[caption id="attachment_71865" align="alignnone" width="424"] 検証構成[/caption]
事前準備
root 権限でネットワーク変更を行うため、もし壊れても問題がない、使い捨て可能なサーバの使用を強く推奨します。 1. 検証用の Amazon EC2 を 1 台、新規作成します - 参考: Linux 仮想マシンの起動 / クラウドならアマゾン ウェブ サービス 【AWS 公式】 - 本記事の確認環境: AMI:Amazon Linux 2 (ami-0c3fd0f5d33134a76)、インスタンスタイプ:t2.micro 2. SSH クライアントから Amazon Linux 2 にログインします - 参考: EC2で構築したLinux ServerへのSSHログイン方法について(Windows環境版) / サーバーワークス エンジニアブログ
手順とコマンド
- ネットワーク作成後に疎通確認を行い、最後に作成したネットワークを削除します
- 各 ip コマンドの実行には root 権限が必要です
[ファイル] testnw
# 1. netns 作成
ip netns add ns1
ip netns add ns2
# 2. veth peer 作成
ip link add eth0-ns1 type veth peer name eth0-ns2
# 3. netns と veth 紐づけ
ip link set eth0-ns1 netns ns1
ip link set eth0-ns2 netns ns2
# 4. IP アドレスを追加
ip netns exec ns1 ip address add 192.168.0.101/24 dev eth0-ns1
ip netns exec ns2 ip address add 192.168.0.102/24 dev eth0-ns2
# 5. NIC 有効化
ip netns exec ns1 ip link set lo up
ip netns exec ns2 ip link set lo up
ip netns exec ns1 ip link set eth0-ns1 up
ip netns exec ns2 ip link set eth0-ns2 up
# 6. 疎通確認
ip netns exec ns1 ping 192.168.0.102 -c 3 -i 0
# 7. netns 削除
ip -all netns delete
実行時間
約 0.1 秒です。確認した限りでは 0.07 秒から 0.12 秒程度のばらつきがありました。
$ time sudo sh testnw
PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
64 bytes from 192.168.0.102: icmp_seq=1 ttl=255 time=0.029 ms
64 bytes from 192.168.0.102: icmp_seq=2 ttl=255 time=0.013 ms
64 bytes from 192.168.0.102: icmp_seq=3 ttl=255 time=0.005 ms
--- 192.168.0.102 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.005/0.015/0.029/0.011 ms, ipg/ewma 0.077/0.024 ms
real 0m0.093s
user 0m0.035s
sys 0m0.006s
$
今後は各種ツールやブリッジやルータ等を交えた検証を進めます。 以上、まとめでした。
詳細
以降は用語やコマンドの説明です。
略語の定義
- netns : Network namespace
- veth: Virtual Ethernet device
- NIC : Network Interface Card
- ホスト : Linux もしくは Amazon Linux 2
netns とは?
netns は独立したネットワークを提供します。ホストのネットワークも netns です。 例えば、1 つの netns には同じ名前の NIC を複数追加できません。
$ # ホストに eth1 を追加
$ sudo ip link add name eth1 type dummy
$
$ # ホストに eth1 を再度追加はできず
$ sudo ip link add name eth1 type dummy
RTNETLINK answers: File exists
一方、netns が異なれば、他の netns に存在する NIC 名を他の netns でも利用可能です。下記は新規 netns とホストの NIC 名が同じですが、エラーはありません。
$ # 新規 netns、nsnew を作成し、これに eth0 を追加 $ sudo ip netns add nsnew $ sudo ip netns exec nsnew ip link add eth0 type dummy $ $ # 新規 netns の NIC 一覧 $ sudo ip netns exec nsnew ip link 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 12:5e:4b:f6:94:3a brd ff:ff:ff:ff:ff:ff $ $ # ホスト(デフォルトの netns)の NIC 一覧 $ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:ca:e0:3a:e7:f8 brd ff:ff:ff:ff:ff:ff
また lo と eth0、計 4 つのリソースは全て独立したリソースです。上記は NIC の例ですが、IP アドレスや経路情報等のリソースも netns 毎に独立しています。
veth peer とは?
veth peer は netns 間の接続を提供します。 Twinax ケーブルのように、LAN ケーブルの両端に NIC が接続されているようなリソースとして扱えます。
$ # eth1 と eth2 の veth peer を作成 $ sudo ip link add name eth1 type veth peer name eth2 $ ip link (略) 88: eth2@eth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 52:65:83:a6:12:e4 brd ff:ff:ff:ff:ff:ff 89: eth1@eth2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 22:21:74:96:9b:75 brd ff:ff:ff:ff:ff:ff $ $ # peer の ifindex を確認 $ ethtool -S eth1 NIC statistics: peer_ifindex: 88 $ ethtool -S eth2 NIC statistics: peer_ifindex: 89
手順とコマンドの詳細
1. netns 作成
ip netns add <NETNS名>
netns を追加します。
$ sudo ip netns add ns1
$ sudo ip netns add ns2
[caption id="attachment_71867" align="alignnone" width="424"] netns を追加[/caption]
ip netns [list]
netns 一覧を表示します。
[確認] ns1, ns2 があること
$ ip netns
ns2
ns1
ip [-all] netns exec [NETNS名] <実行コマンド>
netns 上でコマンドを実行します。
[確認] ns1 と ns2 のインターフェイスが lo のみであること state DOWN は後の手順で修正します。
$ sudo ip -all netns exec ip link netns: ns2 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 netns: ns1 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 $
[参考] ホストのネットワークデバイス eth0 と lo があります。eth0 は ns1, ns2 に存在しません。またホストの lo は state UNKNOWN のため、先ほど確認した ns1, ns2 とは異なるネットワークデバイスです。
$ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:f7:9e:27:3c:ae brd ff:ff:ff:ff:ff:ff $
2. veth peer 作成
ip link add <VETH名1> type veth peer name <VETH名2>
eth0-ns1 と eth0-ns2 の veth peer 作成します。
$ sudo ip link add eth0-ns1 type veth peer name eth0-ns2
[caption id="attachment_71868" align="alignnone" width="424"] veth peer 作成[/caption]
[確認] ホストのネットワークデバイスに eth0-ns1 と eth0-ns2 が追加されること
$ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:f7:9e:27:3c:ae brd ff:ff:ff:ff:ff:ff 45: eth0-ns2@eth0-ns1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether fa:68:c9:cc:ee:70 brd ff:ff:ff:ff:ff:ff 46: eth0-ns1@eth0-ns2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 2a:83:db:95:38:85 brd ff:ff:ff:ff:ff:ff $
3. netns と veth 紐づけ
ip link set <NIC名> netns <NETNS名>
eth0-ns1 と ns1 を紐づけます。
$ sudo ip link set eth0-ns1 netns ns1
[caption id="attachment_71869" align="alignnone" width="424"] eth0-ns1 と ns1 を紐づけ[/caption]
[確認] ns1 の NIC 一覧に eth0-ns1 が追加されること
$ sudo ip netns exec ns1 ip link 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 46: eth0-ns1@if45: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 2a:83:db:95:38:85 brd ff:ff:ff:ff:ff:ff link-netnsid 0 $
[確認] ホストの NIC 一覧から eth0-ns1 が消えること
$ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:f7:9e:27:3c:ae brd ff:ff:ff:ff:ff:ff 45: eth0-ns2@if46: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether fa:68:c9:cc:ee:70 brd ff:ff:ff:ff:ff:ff link-netnsid 0 $
同様に eth0-ns2 と ns2 を紐づけます。
$ sudo ip link set eth0-ns2 netns ns2
[caption id="attachment_71870" align="alignnone" width="424"] eth0-ns2 と ns2 を紐づけ[/caption]
[確認] ns2 の NIC 一覧に eth0-ns2 が追加されること
$ sudo ip netns exec ns2 ip link 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 45: eth0-ns2@if46: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether fa:68:c9:cc:ee:70 brd ff:ff:ff:ff:ff:ff link-netnsid 0 $
[確認] ホストの NIC 一覧から eth0-ns2 が消えること
$ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:f7:9e:27:3c:ae brd ff:ff:ff:ff:ff:ff $
4. IP アドレス追加
ip address add <IPアドレス/サブネットマスク長> dev <NIC名>
eth0-ns1 と eth0-ns2 に IP アドレスを追加します。
$ sudo ip netns exec ns1 ip address add 192.168.0.101/24 dev eth0-ns1
$ sudo ip netns exec ns2 ip address add 192.168.0.102/24 dev eth0-ns2
[caption id="attachment_71871" align="alignnone" width="424"] IP アドレス追加[/caption]
[確認] eth0-ns1 と eth-ns2 に正しい IP アドレスが付与されていること
$ sudo ip -all netns exec ip address netns: ns2 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 45: eth0-ns2@if46: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether fa:68:c9:cc:ee:70 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.0.102/24 scope global eth0-ns2 valid_lft forever preferred_lft forever netns: ns1 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 46: eth0-ns1@if45: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 2a:83:db:95:38:85 brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet 192.168.0.101/24 scope global eth0-ns1 valid_lft forever preferred_lft forever $
5. NIC 有効化
ip link set <NIC名> up
全ての NIC を有効化します。
$ sudo ip netns exec ns1 ip link set lo up
$ sudo ip netns exec ns2 ip link set lo up
$ sudo ip netns exec ns1 ip link set eth0-ns1 up
$ sudo ip netns exec ns2 ip link set eth0-ns2 up
[caption id="attachment_71865" align="alignnone" width="424"] ネットワークデバイス有効化[/caption]
[確認] 全ての NIC が UP, LOWER_UP であること
$ sudo ip -all netns exec ip address netns: ns2 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 45: eth0-ns2@if46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether fa:68:c9:cc:ee:70 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.0.102/24 scope global eth0-ns2 valid_lft forever preferred_lft forever inet6 fe80::f868:c9ff:fecc:ee70/64 scope link valid_lft forever preferred_lft forever netns: ns1 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 46: eth0-ns1@if45: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 2a:83:db:95:38:85 brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet 192.168.0.101/24 scope global eth0-ns1 valid_lft forever preferred_lft forever inet6 fe80::2883:dbff:fe95:3885/64 scope link valid_lft forever preferred_lft forever $
lo は無効でも veth peer 間の疎通は可能ですが、特に理由がなければ有効化します。
6. 疎通確認
ns1 から ns2 に ping が通ります。
$ sudo ip netns exec ns1 ping 192.168.0.102 -c 3
PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
64 bytes from 192.168.0.102: icmp_seq=1 ttl=255 time=0.034 ms
64 bytes from 192.168.0.102: icmp_seq=2 ttl=255 time=0.033 ms
64 bytes from 192.168.0.102: icmp_seq=3 ttl=255 time=0.034 ms
--- 192.168.0.102 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2046ms
rtt min/avg/max/mdev = 0.033/0.033/0.034/0.006 ms
$
[参考] 宛先 IP アドレスに対応する宛先 MAC アドレスが veth peer 経由で存在
$ sudo ip -all netns exec ip neighbor
netns: ns2
192.168.0.101 dev eth0-ns2 lladdr 2a:83:db:95:38:85 REACHABLE
netns: ns1
192.168.0.102 dev eth0-ns1 lladdr fa:68:c9:cc:ee:70 REACHABLE
[参考] ping に -i
オプションを追加すると送信間隔を変更可能
7. netns 削除
ip [-all] netns delete [NETNS名]
疎通確認が完了したので、netns を削除します。
$ sudo ip -all netns delete
[確認] 新規 netns が存在しないこと(ns1, ns2 が表示されないこと)
$ ip netns
$
[確認] ホストの NIC が lo と eth0 のみであること(ns1, ns2, eth0-ns1, eth0-ns2 が表示されないこと)
$ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:f7:9e:27:3c:ae brd ff:ff:ff:ff:ff:ff $
ip link delete <NIC名>
もし netns と veth peer の紐付けがない場合、netns を削除してもホスト上にある veth peer は自動で削除されません。この場合、veth peer のうち、どちらか一方の veth をホストから削除すると、両方の veth が削除されます。
$ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:ca:e0:3a:e7:f8 brd ff:ff:ff:ff:ff:ff 37: eth0-ns2@eth0-ns1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 02:bd:23:87:4a:b4 brd ff:ff:ff:ff:ff:ff 38: eth0-ns1@eth0-ns2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 16:90:50:67:c6:57 brd ff:ff:ff:ff:ff:ff $ $ # veth peer のうち、一方の veth をホストから削除 $ sudo ip link delete eth0-ns1 $ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 06:ca:e0:3a:e7:f8 brd ff:ff:ff:ff:ff:ff $
もし初期化が手間な場合は EC2 の再構築も有効と考えます。
最後に
秒速で記事を作成したい!
以上
手塚 忠 (Tadashi Tetsuka) 記事一覧はコチラ
カスタマーサクセス部所属、2019 年 2 月入社のネットワークエンジニア。シリアルコンソールがマネジメントコンソールに変わったが、スイッチ愛は今も変わらず。 2023 Japan AWS Top Engineers (Networking), 2023 AWS ALL Certifications Engineers