SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

AWSの深いところ見せちゃいます! by AWSクラウドサポートエンジニア

AWSネットワークの論理的な側面 ~ AWSのバックボーンネットワークに関するDeepな話(2)

AWSの深いところ見せちゃいます! by AWSクラウドサポートエンジニア 第2回

VPCにおける同一サブネット内の通信(2)

パケットの送信と受信

 送信元ゲストOSではパケットの送信に必要な情報がそろったので、早速パケットを送信します。送信元Serverは再度パケットを横取りし、VPC IDでカプセル化した上で、送信先Serverへ向かってカプセル化されたパケットを送りつけます。EC2インスタンスにとっては同一サブネット内の通信ですが、送信先Serverは物理的(ネットワーク的)には別の場所にある可能性が高いので、レイヤ2の通信ではなくルーターも含めたレイヤ3の通信となります。

 その際のパケットはこんな見かけになります。左側がパケットの先頭になります。"dst Guest MAC"から右が送信元ゲストOSが生成したパケットになり、「VPC IDでカプセル化」とはこんなパケットを生成することを指しています。

 パケットを受け取った送信先Serverは、まず送信元ゲストOSが確かに送信元Serverに存在するかを確認するためMapping Serviceにお伺いをたてます。その理由は、各Serverに問題が発生し勝手な(ゲストOSが送ってない)パケットを送りつけてきても、受信側Serverでそれを破棄できるようにするためです。このプロセスを初めて知った時はセキュリティを最優先事項とするAWSらしい設計だなと思いました。

 そして、上記の確認がとれ次第、送信先Serverは受信したパケットからVPC IDによるカプセル化を外し、送信元ゲストOSが送った元々のパケットを送信先ゲストOSへと送ります。

 このようなプロセスを経ることで同じサブネットにいるゲスト同士が物理的にはネットワークのどこにいてもお互いに(同一サブネットにいるかのように)通信することができ、VPCにおけるL2トポロジーを実際の物理トポロジーから独立させることができるのです!

 なお、VPCのサブネットは必ず1つのアベイラビリティーゾーン内に含まれているので、ここまでのプロセスは低遅延で実施されます。

実際のパケット

 では、試しに同一サブネット内のEC2インスタンス(instance1)から別のインスタンス(instance2)へpingをして、実際のパケットを見てみましょう。前提として、それ以前にはまったく通信が無かった(ARPのキャッシュが無い)インスタンス間の通信であるとします。

 まず、それぞれのインスタンスのMACアドレス、プライベートIPアドレスは次の通りです。

instance1$ ip addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP gup default qlen 1000
    link/ether 06:58:86:91:36:49 brd ff:ff:ff:ff:ff:ff
    inet 172.31.24.51/20 brd 172.31.31.255 scope global eth0

instance2$ ip addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP gup default qlen 1000
    link/ether 06:dc:da:0f:68:d9 brd ff:ff:ff:ff:ff:ff
    inet 172.31.24.206/20 brd 172.31.31.255 scope global eth0

instance1にinstance2のIPアドレスに関するARPキャッシュが無いことを確認します。

instance1$ arp -n 172.31.24.206
172.31.24.206 (172.31.24.206) -- no entry

 この状態でそれぞれのインスタンスでtcpdumpを実行しながらinstance1からinstance2へpingをしてみます。

instance1$ ping -c1 172.31.24.206
PING 172.31.24.206 (172.31.24.206) 56(84) bytes of data.
64 bytes from 172.31.24.206: icmp_seq=1 ttl=64 time=0.640 ms

--- 172.31.24.206 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.640/0.640/0.640/0.000 ms

 その際のtcpdumpの出力はそれぞれ以下の通りです。

instance1$ sudo tcpdump -etni eth0 icmp or arp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
06:58:86:91:36:49 > Broadcast, ethertype ARP (0x0806), length 42: Request who-h 172.31.24.206 tell 172.31.24.51, length 28
06:dc:da:0f:68:d9 > 06:58:86:91:36:49, ethertype ARP (0x0806), length 56: Reply72.31.24.206 is-at 06:dc:da:0f:68:d9, length 42
06:58:86:91:36:49 > 06:dc:da:0f:68:d9, ethertype IPv4 (0x0800), length 98: 172..24.51 > 172.31.24.206: ICMP echo request, id 25098, seq 1, length 64
06:dc:da:0f:68:d9 > 06:58:86:91:36:49, ethertype IPv4 (0x0800), length 98: 172..24.206 > 172.31.24.51: ICMP echo reply, id 25098, seq 1, length 64

instance2$ sudo tcpdump -etni eth0 arp or icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
06:58:86:91:36:49 > 06:dc:da:0f:68:d9, ethertype IPv4 (0x0800), length 98: 172..24.51 > 172.31.24.206: ICMP echo request, id 25098, seq 1, length 64
06:dc:da:0f:68:d9 > Broadcast, ethertype ARP (0x0806), length 42: Request who-h 172.31.24.51 tell 172.31.24.206, length 28
06:58:86:91:36:49 > 06:dc:da:0f:68:d9, ethertype ARP (0x0806), length 56: Reply72.31.24.51 is-at 06:58:86:91:36:49, length 42
06:dc:da:0f:68:d9 > 06:58:86:91:36:49, ethertype IPv4 (0x0800), length 98: 172..24.206 > 172.31.24.51: ICMP echo reply, id 25098, seq 1, length 64

 普通のEthernetならinstance2にpingのリクエスト(ICMP echo request)が届く前にinstance1からのARPリクエスト(Request who-has 172.31.24.206)がブロードキャストで届くはずですが、ご覧の通り届いていません。

 ARPリクエストが届いていれば、リクエスト元に対するARPキャッシュを生成するので、上記のinstance2からinstance1へのARPリクエストは不要となりますが、実施にはARPリクエストは届いておらず、結果ARPキャッシュにはinstance1のMACアドレスが無いため、instance2は送信元ゲストに対するARPリクエスト(Request who-has 172.31.24.51)を送ってからpingの応答(ICMP echo reply)を返してます。なお、同じくinstance2からinstance1へ送っているARPリクエストもinstance1へは届いていません。

 これは、VPCではARPの処理をそのまま実現している(ARPパケットをインスタンス間でやりとりしている)のではなくMapping Serviceによって実現しているためです。逆に言うと、VPCのFAQの「Q: Amazon VPC は、マルチキャストまたはブロードキャストをサポートしますか?」に「いいえ」とあるように、ブロードキャストがサポートされていないため、Mapping Serviceを使う必要がある、ともいえます。

MACアドレスに関する余談

 上記出力のMACアドレスを見ると、ぱっと見06とか0aで始まるものが多いことに気づかれるかもしれません。他で適当にピックアップしたMACアドレスも、次の通り06とか0aで始まってます。

  • 06:f2:97:41:38:48
  • 0a:14:57:86:19:f2
  • 06:a9:1a:12:bf:d2
  • 06:5a:a0:c6:ab:c5

 これは、AWSではGLビットが0の「ローカルアドレス」をMACアドレスとして使っているためです。したがって、最初の一オクテットの値は4n-2(nは1以上の整数)になります(と言いつつ「02」とか「0e」とか「12」で始まるものをすぐに見つけられなかったのですが……)。

 ローカルアドレスというのは単に世界中で一意とは限らないというだけで、実際の利用上は普通のMACアドレスと同じです。

Mapping Serviceのキャッシュ

 ところで、以上のようにMapping Serviceはすべての通信に関係してくるためSingle Point of Failureになり得ます。しかし、実際には各Serverがそのコンテンツのキャッシュを必ず持っており、毎回Mapping Serviceへリクエストが送られるわけではありません。

 たとえば、もし一度目のリクエストがMapping Serviceへ送られ、その後はキャッシュから返される、といった仕組みになっているとすると、Mapping Serviceの応答、つまりARP解決の遅延に多少なりとも変動を観測できるはずです。しかし、簡単に計測した範囲では、新規に立ち上げたインスタンスのARP解決が特に遅いといったことはありませんでした。

 これは、上述の通り各Serverが常にMapping Serverのキャッシュを持っていることを示唆しています。

次のページ
VPCにおける異なるサブネットとの通信

この記事は参考になりましたか?

AWSの深いところ見せちゃいます! by AWSクラウドサポートエンジニア連載記事一覧

もっと読む

この記事の著者

有賀 征爾(アマゾン ウェブ サービス ジャパン株式会社)(アリガ セイジ)

 AWSクラウドサポートエンジニア。大学院にてインターネット分野の研究をした後、大手通信キャリアにて国際インターネットバックボーンの設計・構築・運用に携わる。その後、国内インターネットバックボーンの設計にも携わり、IPv6、セキュリティサービス等の開発などを担当する。2015年春にクラウドサポートエ...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/9790 2016/11/29 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー