はじめに
Linux のネットワークは ifconfig コマンドで設定する時代が長く続きましたが、現在は ip コマンドへ置き換わりつつあります。慣れた方法が NG となるとイラっとするものです。メリットあるんだろうけど、今は手元の Linux に IP アドレスを設定できれば十分。ググると Qiita にあんちょこが見つかり事なきを得る(例えばこちら)。私もそんな風に過ごしてきました。ではメリットは何だろう、を簡単にまとめたのがこの記事です。
結論から
結論をひとことで言うと、ip(より正確には iproute2)はモダンネットワークを構成でき、ifconfig (より正確には net-tools) はできません。
ではモダンネットワークとは?
厳密な定義はさておき、大きな利点のひとつは図のようなネットワークの仮想化です。
ifconfig 時代のモダンでない Linux は「ネットワーク機能(ネットワークスタック)はカーネルに一つ」の前提で構築されていました。それも今や昔の話。今日 Linux を構築するならば、論理的・物理的に複数のインターフェイスを持つのが一般的です。単純にインターフェイスの数だけでなく、ネットワークスタックを1台の Linux に複数持たせられます。これをネットワークの仮想化と呼びます。つまり、ハイパーバイザーが無くても Linux の機能だけでネットワーク仮想化を実現できます。
なお、この記事では取り上げませんが、iproute2 はその他にもルーティング、フィルタリング、クラシフィケーションの強化を目指して開発された経緯があります。
試して理解を深める
ネットワーク名前空間の作成
ネットワーク仮想化の実現に重要な概念が「ネットワーク名前空間(Network Namespace)」です。新しくネットワーク名前空間を作ると、ネットワークスタックが複製されます。これには、ルーティングテーブル・ファイアウォール・インターフェイスを含みます。
実際にネットワーク名前空間を作るのは簡単です。ここでは例として2つの名前空間 NS1 と NS2 を作成してみます。
# ip netns add NS1 # ネットワーク名前空間 NS1 を作成
# ip netns add NS2 # ネットワーク名前空間 NS2 を作成
# ip netns list # ネットワーク名前空間の一覧を表示(list は省略可)
NS1
NS2
作成した名前空間 NS1 に対してコマンドを実施するには ip netns exec NS1 の後に実行したいコマンドを記載します。例として、ネットワークの基本情報を確認してみます:
# ip netns exec NS1 ip link # 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: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
インターフェイスは2つ登録されていることがわかります。
# ip netns exec NS1 ip route # ip route はルーティングテーブルを確認するコマンド
#
ルーティングテーブルは空です。
# ip netns exec NS1 ip neigh # ip neigh は ARP テーブルを確認するコマンド
#
ARPテーブルも空です。
2つのネットワーク名前空間を接続する設定
# ip link add VETH1 netns NS1 type veth peer name VETH2 netns NS2
# ip netns exec NS1 ip addr add 10.0.0.1/24 dev VETH1
# ip netns exec NS2 ip addr add 10.0.0.2/24 dev VETH2
# ip netns exec NS1 ip link set VETH1 up
# ip netns exec NS2 ip link set VETH2 up
1行目はもしかすると奇異に見えるかもしれません。リンクと仮想インターフェイスを同時に作成しています。これは次のような事情によります。
タイプとして veth を指定していますが、その名前から推測できるように仮想イーサネットインターフェイスです。veth 作成時には必ず2つのペアとして作成する必要があります。片方のインターフェイスへ送信したパケットは直ちにもう一方のインターフェイスから出てきます。このような事情から veth の作成は必ずペアで行います。
上記で設定は完了しています。疎通確認をします:
$ sudo ip netns exec NS1 ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.038 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.027 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.030 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.032 ms
再びルーティングテーブルと ARP テーブルを確認してみます:
# ip netns exec NS1 ip route
10.0.0.0/24 dev VETH1 proto kernel scope link src 10.0.0.1
# ip netns exec NS1 ip neigh
10.0.0.2 dev VETH1 lladdr d2:a1:3a:33:a9:b8 REACHABLE
おわりに
勘の良い方は既にお気づきのようにネットワーク名前空間はコンテナのネットワーク実現に不可欠な要素です。Docker を使っているのに ifconfig を使う、というのはどうも具合が悪そうです。Mac 等個人端末として使う場合には まだまだ ifconfig で十分かもしれません。
なお、モダンネットワークに対する厳密な定義は無さそうなので、ネットワーク仮想化以外にも着目すべき機能があるかもしれません。ご意見頂けるとうれしいです。
使用したバージョン
Ubuntu 18.04.3 LTS