EC2-VPCでIPマルチキャスト/ブロードキャストを実現する(後編)

少し期間が開いてしまいましたが、前編では、クラウド上でのIPマルチキャスト/ブロードキャストを取り巻く現状と、ワークアラウンドについて考えてきました。
今回の後編では、実際にワークアラウンドを試して、EC2上でマルチキャスト/ブロードキャストで通信してみましょう。


環境

今回は下記の構成で検証します。

environment

送信元:Amazon Linux 2014.3 (64bit)

# ifconfig
eth0    Link encap:Ethernet HWaddr 06:A7:CE:8A:4F:13
          inet addr:172.31.4.93 Bcast:172.31.15.255 Mask:255.255.240.0
          inet6 addr: fe80::4a7:ceff:fe8a:4f13/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
          RX packets:4856911 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4546714 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000
          RX bytes:776876067 (740.8 MiB) TX bytes:728166952 (694.4 MiB) Interrupt:26

宛先A:Amazon Linux 2014.3 (64bit)

# ifconfig
eth0    Link encap:Ethernet HWaddr 06:01:B8:62:20:C0
          inet addr:172.31.3.135 Bcast:172.31.15.255 Mask:255.255.240.0
          inet6 addr: fe80::401:b8ff:fe62:20c0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
          RX packets:83196 errors:0 dropped:0 overruns:0 frame:0
          TX packets:55395 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000
          RX bytes:97004828 (92.5 MiB) TX bytes:7290779 (6.9 MiB) Interrupt:26

宛先B:Amazon Linux 2014.3 (64bit)

# ifconfig
eth0    Link encap:Ethernet  HWaddr 06:52:D3:DC:8A:4A  
          inet addr:172.31.4.105  Bcast:172.31.15.255  Mask:255.255.240.0
          inet6 addr: fe80::452:d3ff:fedc:8a4a/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:19285 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11453 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 
          RX bytes:27533244 (26.2 MiB)  TX bytes:775892 (757.7 KiB) Interrupt:26 

セットアップ

あらかじめ、送信元インスタンス、宛先インスタンスの間のICMPをセキュリティグループで許可しておきます。

宛先インスタンスのセットアップ

宛先インスタンスをセットアップします。
マネジメントコンソールやAPIから、宛先インスタンスのSource/Dest. CheckをDisabledにします。

Amazon LinuxはデフォルトでIPのブロードキャストアドレスに対するICMPに応答しない設定となっているので、宛先インスタンスがICMPに応答できるように設定変更します。

echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

送信元インスタンスのセットアップ

次に、送信元インスタンスをセットアップしていきます。
今回作成するスクリプトにはlibpcap-develが必要となるので、あらかじめインストールしておきます。
ちなみに、libpcapはAmazon Linuxにはデフォルトで入っています。

yum install libpcap-devel

Rubyをインストールします。
今回はRVMを使うので、まずRVMをインストール。

\curl -sSL https://get.rvm.io | bash

.bash_profileを編集してRVMを読み込むようにします。

vim ~/.bash_profile 

下記を追記します。

[ -s ${HOME}/.rvm/scripts/rvm ] && source ${HOME}/.rvm/scripts/rvm

初回は手で読ませます。

source ~/.bash_profile 

後述のPacketFuはRuby 2.0以降に対応していないため、Ruby 1.9をインストールします。

rvm install ruby-1.9.3-p484
rvm use ruby-1.9.3-p484

pcaprub, packetfuをインストールします。

gem install pcaprub
gem install packetfu

これで送信元インスタンス、宛先インスタンスの準備ができました。


ソースコード

送信元インスタンスでパケットをキャプチャし、イーサネットフレームの宛先MACアドレスのI/Gビットが1の場合にUnicastに書き換えます。
スクリプト自体は、@thekentiest さんのソースコードを流用させていただきます。

#!/usr/bin/ruby
require 'rubygems'
require 'packetfu'

dev = ARGV[0]
mac=`ip link show #{dev} | awk '/ether/ {print $2}'`.chomp
ARGV.shift
dests = ARGV

cap = PacketFu::Capture.new(
          :timeout => 4000,
          :iface => dev, :start => true,
          :filter => "ether src #{mac} and ether[0] & 1 = 1")
loop do
  cap.stream.each do |pkt|
    frame = PacketFu::IPPacket.parse(pkt)

    i = 0
    dests.each do |dest|
      frame.eth_daddr = dest
      frame.ip_header.ip_id = frame.ip_header.ip_id + i
      frame.ip_header.ip_sum = frame.ip_header.ip_calc_sum()
      frame.to_w(dev)
      i = i + 1
    end
  end
end

動作確認(IPブロードキャスト)

まずはIPブロードキャストを試してみます。

そのまま試した場合

何も仕込まない状態でEC2上でのIPブロードキャストが通らないことを確認します。

#ping -b 172.31.15.255
WARNING: pinging broadcast address
PING 172.31.15.255 (172.31.15.255) 56(84) bytes of data.
^C
--- 172.31.15.255 ping statistics ---
7 packets transmitted, 0 received, 100% packet loss, time 6788ms

通りません。

Multi-unicastingを使用した場合

送信元インスタンスで、上記のソースコードを動作させます。

ruby mcast.rb eth0 06:01:b8:62:20:c0 06:52:d3:dc:8a:4a  

では、IPのブロードキャストアドレスである172.31.15.255に対してpingを実行してみます。

# ping -b 172.31.15.255
WARNING: pinging broadcast address
PING 172.31.15.255 (172.31.15.255) 56(84) bytes of data.
64 bytes from 172.31.3.135: icmp_seq=1 ttl=64 time=112 ms
64 bytes from 172.31.4.105: icmp_seq=1 ttl=64 time=114 ms (DUP!)
64 bytes from 172.31.3.135: icmp_seq=2 ttl=64 time=5.55 ms
64 bytes from 172.31.4.105: icmp_seq=2 ttl=64 time=8.03 ms (DUP!)
64 bytes from 172.31.3.135: icmp_seq=3 ttl=64 time=4.37 ms
64 bytes from 172.31.4.105: icmp_seq=3 ttl=64 time=122 ms (DUP!)
64 bytes from 172.31.3.135: icmp_seq=4 ttl=64 time=3.20 ms
64 bytes from 172.31.4.105: icmp_seq=4 ttl=64 time=7.19 ms (DUP!)
64 bytes from 172.31.3.135: icmp_seq=5 ttl=64 time=4.19 ms
64 bytes from 172.31.4.105: icmp_seq=5 ttl=64 time=7.83 ms (DUP!)
^C
--- 172.31.15.255 ping statistics ---
5 packets transmitted, 5 received, +5 duplicates, 0% packet loss, time 4911ms
rtt min/avg/max/mdev = 3.201/39.026/122.603/50.877 ms

通りました。


動作確認(IPマルチキャスト)

次にIPマルチキャストを試してみます。
マルチキャストの送受信用のスクリプトには、下記のソースコードを流用します。

UDPでマルチキャストを使う(マルチキャストを送信する) – Geekなページ
UDPでマルチキャストを使う(マルチキャストを受信する) – Geekなページ

そのまま試した場合

何も仕込まない状態でEC2上でのIPブロードキャストが通らないことを確認します。

宛先インスタンス側で、マルチキャスト受信用スクリプトを動作させておきます。
このスクリプトは、マルチキャストパケットを受信すると、受信したメッセージを標準出力に出力して終了します。

ruby ./mcast_recv.rb

上記のスクリプトを動かした状態で netstat -g を実行すると、マルチキャストグループ(239.192.1.2)に所属できていることがわかります。

# netstat -g
IPv6/IPv4 Group Memberships
Interface       RefCnt Group
--------------- ------ ---------------------
lo              1      all-systems.mcast.net
eth0            1      239.192.1.2
eth0            1      all-systems.mcast.net
lo              1      ff02::1
lo              1      ff01::1
eth0            1      ff02::1:ffdc:8a4a
eth0            1      ff02::1
eth0            1      ff01::1

では、送信元インスタンスから、マルチキャスト送信用スクリプトを実行させます。

ruby ./mcast_send.rb

宛先インスタンス側で、スクリプトが何も出力しておらず、終了していません。
これは、マルチキャストパケットを受信できていないことを意味しています。

Multi-unicastingを使用した場合

IPブロードキャストのときと同様、送信元インスタンスで、上記のソースコードを動作させます。

ruby mcast.rb eth0 06:01:b8:62:20:c0 06:52:d3:dc:8a:4a  

宛先インスタンス側で、マルチキャスト受信用スクリプトを動作させておきます。

ruby ./mcast_recv.rb

では、送信元インスタンスから、マルチキャスト送信用スクリプトを実行させます。

ruby ./mcast_send.rb

宛先インスタンスのコンソールを見ると、”Hello”と出力されています。

"HELLO"

以上の通り、IPマルチキャストのパケットが宛先インスタンスに到達したことを確認できました。


おわりに

今回、前編・後編の2回に分けて、EC2-VPCでのマルチキャスト/ブロードキャストを考えてきました。
マルチキャストがサポートされていないEC2-VPCでも、ユースケースによってはこれらのワークアラウンドが使えるかと思います。


参考資料

  1. トラックバックはまだありません。

コメントを残す

  • WordPress.com で次のようなサイトをデザイン
    始めてみよう