秒速でネットワーク作成 [veth peer]

記事タイトルとURLをコピーする

技術三課の手塚です。入社から半年が過ぎましたが、もっと長く在籍しているような感覚もあり、大変密度の濃い時間を過ごしています。 さて、本記事は秒速でネットワークを作成する方法です。 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 を追加 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 作成 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 を紐づけ 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 を紐づけ 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 アドレス追加 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) 記事一覧はコチラ

クラウドインテグレーション部所属。AWS認定10冠。2019/2入社のネットワークエンジニア。シリアルコンソールがマネジメントコンソールに変わったがスイッチ愛は今も変わらず。