2014年4月15日火曜日

気になるSDNニュース Interop Tokyo 2014の事前登録やってます

Interop Tokyo 2014の事前登録が始まっています。

主にネットワークコンピューティングに関する製品の展示や基調講演などが行われます。
昨年も行きましたが、昨年はSDN ShowCaseなどの特別展示もありました。

会期は6月11日~13日の3日間、場所は千葉県の幕張メッセです。
入場料は5,000円ですが、事前登録をすれば無料で入場できます。

HPを見た限りだと、今年の展示や無料セミナーの内容等があまり明らかになっていない部分もあるようですが、無料セミナーはそのうち満席になってしまうと思うので、興味のある方はとりあえず事前登録しておいてはどうでしょうか。

展示会とは別に6月9日、10日に東京品川でカンファレンスもあるようですが、そちらは有料みたいです。


◆Interop Tokyo 展示会HP
http://www.interop.jp/2014/index2.html

◆Interop Tokyo カンファレンスHP
http://www.interop.jp/2014/conf/index.html


2014年4月4日金曜日

気になるSDNニュース 今後のSDN、NFVの国内市場動向分析

4月3日、IDC Japan(IT調査会社)がSDN、NFVの国内市場動向の分析結果を発表しました。
SDN、NFVが2013年までのブームに比べ、SDNの導入が現実的なものとして捉えられ始めているようです。

詳しい内容はIDC Japanの報道資料を見てもらうとして。
(さらに詳しい内容を知りたい場合はレポートを購入していただくとして・・・。)

企業ネットワークSDN市場はデータセンターの1/4とみられているようなので、SDN、NFVのメインターゲットはやはりデータセンターになるのでしょうね。

◆報道資料
http://www.idcjapan.co.jp/Press/Current/20140403Apr.html

◆関連リンク
http://www.itmedia.co.jp/enterprise/articles/1404/03/news085.html
http://cloud.watch.impress.co.jp/docs/news/20140403_642726.html

2014年4月1日火曜日

気になるSDN関連ニュース NECが仮想環境全体の管理、運用を自動化しました

3月27日、NECが「IaaS運用自動化ソリューション」を発売しました。
Microsoftの「System Center」とNECのSDNコントローラ「UNIVERGE PF6800」を連携させ、仮想スイッチの「UNIVERGE PF1000」と連携することで仮想サーバ、ネットワークの運用、管理の自動化が実現したようです。

仕組みとしては以下の様です。
・Hyper-Vの仮想スイッチを「UNIVERGE PF1000」というソフトウェアでOpenFlowに対応したスイッチに拡張する
・「System Center 2012 R2 Virtual Machine Manager」からPF6800を介してPF1000を制御する

つまりSystem Centerで仮想ネットワークも管理できるイメージですかね。
これで仮想サーバ、ネットワークのリソース払い出しが従来よりも迅速に行えるようになるそうです。

◆報道資料
http://jpn.nec.com/press/201403/20140327_01.html

◆関連リンク
http://japan.zdnet.com/datacenter/analysis/35045774/
http://ascii.jp/elem/000/000/880/880101/

◆UNIVERGE PF1000について
http://jpn.nec.com/univerge/pflow/spec_pfvs.html
http://itpro.nikkeibp.co.jp/article/Active/20120912/422303/

◆System Center 2012について
http://www.microsoft.com/ja-jp/server-cloud/system-center/default.aspx http://www.atmarkit.co.jp/ait/articles/1209/20/news142.html

2014年3月26日水曜日

気になるSDN関連ニュース A10 Forum 2014開催

A10 Forum 2014が、東京は4月17日(木)13:00~、大阪は4月25日(金)13:00~に開催されます。
内容としては「最新のADC、大規模DDoS攻撃防御、SDN/NFV・IPv6移行」と言う事です。

参加は無料で、事前登録が必要です。
東京は定員が300名なので、興味がある場合は早く申込した方が良いかもです。


◆報道資料
http://www.a10networks.co.jp/eventinfo/2014/a10forum.html
◆関連トピック
http://news.mynavi.jp/news/2014/03/26/063/
http://headlines.yahoo.co.jp/hl?a=20140326-00000019-mycomj-sci

2014年3月22日土曜日

気になるSDN関連ニュース Brocade Vyatta vRouter国内で本格展開開始!?

3月19日にブロケード社とCTC社およびネットワールド社とのBrocade Vyatta vRouterのディストリビュータ契約の締結が発表されました。

Brocade Vyatta vRouterとはルーティング、ファイアウォール、VPNといった機能を備えた仮想ルータです。動作確認の為に評価版を60日無償で試すこともできるみたいです。

今後はCTC社とネットワールド社が国内販売代理店として機能することになり、国内販売を本格化する狙いのようです。
Brocade Vyatta vRouterは、今は主にNFVに注力しているようですが、SDNでの活用も期待されます。

◆報道資料
http://www.brocadejapan.com/news/20140319

◆関連トピック
http://itpro.nikkeibp.co.jp/article/NEWS/20140319/544643/
http://japan.zdnet.com/datacenter/analysis/35045499/
http://prtimes.jp/main/html/rd/p/000000026.000008113.html
http://cloud.watch.impress.co.jp/docs/news/20140320_640506.html
http://businessnetwork.jp/Detail/tabid/65/artid/3334/Default.aspx

2014年3月18日火曜日

OpenFlow Mininetでフローテーブルを確認する方法

Mininetでフローテーブルを確認する方法を調べてみました。

以下のコマンドで表示できます。

dpctl dump-flows
sh ovs-ofctl dump-flows s1

実行すると以下のように表示されます。

mininet@mininet-vm:~$ sudo mn
*** Creating network
(省略)
*** Starting CLI:
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
mininet> sh ovs-ofctl dump-flows s1
NXST_FLOW reply (xid=0x4):

まだフローテーブルには何もフロールールが追加されていません。
1回ホスト1(h1)からホスト2にpingを実行してから、フローテーブルを表示します。

mininet> h1 ping -c 1 h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=1.68 ms

--- 10.0.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.682/1.682/1.682/0.000 ms
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=9.01s, table=0, n_packets=1, n_bytes=98, idle_timeout=60, idle_age=9, priority=0,icmp,in_port=2,vlan_tci=0x0000,dl_src=32:b1:55:2d:00:5e,dl_dst=46:16:7f:f7:0d:da,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:1
 cookie=0x0, duration=9.01s, table=0, n_packets=1, n_bytes=98, idle_timeout=60, idle_age=9, priority=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=46:16:7f:f7:0d:da,dl_dst=32:b1:55:2d:00:5e,nw_src=10.0.0.1,nw_dst=10.0.0.2,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:2
 cookie=0x0, duration=9.01s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=9, priority=0,arp,in_port=2,vlan_tci=0x0000,dl_src=32:b1:55:2d:00:5e,dl_dst=46:16:7f:f7:0d:da,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=2 actions=output:1
 cookie=0x0, duration=4.001s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=4, priority=0,arp,in_port=2,vlan_tci=0x0000,dl_src=32:b1:55:2d:00:5e,dl_dst=46:16:7f:f7:0d:da,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=1 actions=output:1
 cookie=0x0, duration=4s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=4, priority=0,arp,in_port=1,vlan_tci=0x0000,dl_src=46:16:7f:f7:0d:da,dl_dst=32:b1:55:2d:00:5e,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=2 actions=output:2
mininet>
mininet>
mininet> sh ovs-ofctl dump-flows s1
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=15.212s, table=0, n_packets=1, n_bytes=98, idle_timeout=60, idle_age=15, priority=0,icmp,in_port=2,vlan_tci=0x0000,dl_src=32:b1:55:2d:00:5e,dl_dst=46:16:7f:f7:0d:da,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:1
 cookie=0x0, duration=15.212s, table=0, n_packets=1, n_bytes=98, idle_timeout=60, idle_age=15, priority=0,icmp,in_port=1,vlan_tci=0x0000,dl_src=46:16:7f:f7:0d:da,dl_dst=32:b1:55:2d:00:5e,nw_src=10.0.0.1,nw_dst=10.0.0.2,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:2
 cookie=0x0, duration=15.212s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=15, priority=0,arp,in_port=2,vlan_tci=0x0000,dl_src=32:b1:55:2d:00:5e,dl_dst=46:16:7f:f7:0d:da,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=2 actions=output:1
 cookie=0x0, duration=10.203s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=10, priority=0,arp,in_port=2,vlan_tci=0x0000,dl_src=32:b1:55:2d:00:5e,dl_dst=46:16:7f:f7:0d:da,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=1 actions=output:1
 cookie=0x0, duration=10.202s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=10, priority=0,arp,in_port=1,vlan_tci=0x0000,dl_src=46:16:7f:f7:0d:da,dl_dst=32:b1:55:2d:00:5e,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=2 actions=output:2


他にもIPとポート番号を指定して表示する方法があるようです。

s1 ovs-ofctl dump-flows tcp:127.0.0.1:6634

ただし、前に作ったトポロジー(test_topo.py)でこのコマンドを実行すると以下のようなエラーが出ます。

mininet> s1 ovs-ofctl dump-flows tcp:127.0.0.1:6634
ovs-ofctl: connecting to tcp:127.0.0.1:6634 (Connection refused)

このコマンドで表示するにはトポロジーを少し直して、listenPortの指定をします。

■変更前
net = Mininet()

■変更後
net = Mininet(listenPort=6634)

以上になります。

2014年3月16日日曜日

O3プロジェクトシンポジウムに行ってきました。

3月14日に開催されたO3プロジェクトシンポジウムに行ってきました。

会場は秋葉原から徒歩1~2分位、会場には結構な人数が集まっていました。
何人ぐらいかな?200~300人位?

今までSDNと言えばデータセンターや社内ネットワークなどで活用が主でしたが、このプロジェクトはもっと広域なネットワークにもSDNを活用するための研究のようです。
今回のシンポジウムでは講演、研究報告と展示が行われました。

講演では、ONFのエグゼクディブディレクターのDan Pitt氏の基調講演もあり、聞き慣れないOpenSDNって言葉が出てきました。
Googleで検索しても英語ばかりなので、まだ日本には浸透していないのかもしれません。

そのほか、NECの岩田氏の研究報告、CASLの三上氏の講演、パネルディスカッションがありました。

研究成果の展示もされていたので見てきました。
OpenvSwitchより高速なソフトウェアスイッチの展示や、OpenFlowを拡張して光コアネットワークの制御をする技術など、8個のブースで展示がされていました。

今後、広域ネットワークにもSDNが使われてSDNが身近なものになり、当たり前の技術になるかもしれません。
あとはSDNがガラパゴスにならないことを祈るばかり。

2014年3月13日木曜日

OpenFlow Mininetのトポロジーをカスタマイズしてみる4

前回の続きで、別のゲストOS上で動いているOpenFlowコントローラに接続してみます。

まずは環境の説明です。

OpenFlowコントローラを動かすゲストOSをサーバ1とします。
IPアドレスは「192.168.56.10」です。

Mininetを動かすゲストOSをサーバ2とします。
IPアドレスは「192.168.56.20」とします。

まずはサーバ1でOpenFlowコントローラを起動します。
起動するプログラムは、ここではTremaのサンプルプログラムから「repeater_hub」を使用します。

まずは以下のコマンドでコントローラを起動します。

trema run ./repeater-hub.rb

サンプルプログラムをログインディレクトリ等にコピーしてから実行したほうが良いかもしれません。

実行すると以下のように表示されます。

$ trema run repeater-hub.rb


次にサーバ2でMininetを実行します。

sudo python ./topo_test.py

実行したら確認してみます。

~$ sudo python ./topo_test.py
mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
s1 lo:  s1-eth1:h1-eth0 s1-eth2:h2-eth0
c1
mininet> dump
<Host h1: h1-eth0:192.168.100.1 pid=1852>
<Host h2: h2-eth0:192.168.100.2 pid=1853>
<OVSSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=1845>
<RemoteController c1: 192.168.56.10:6653 pid=1838>
mininet> ping all
*** Unknown command: ping all
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (2/2 received)
mininet>
mininet> h1 ping -c3 h2
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_req=1 ttl=64 time=3.22 ms
64 bytes from 192.168.100.2: icmp_req=2 ttl=64 time=0.093 ms
64 bytes from 192.168.100.2: icmp_req=3 ttl=64 time=0.109 ms

--- 192.168.100.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.093/1.143/3.229/1.475 ms
mininet>
mininet> h2 ping -c3 h1
PING 192.168.100.1 (192.168.100.1) 56(84) bytes of data.
64 bytes from 192.168.100.1: icmp_req=1 ttl=64 time=0.672 ms
64 bytes from 192.168.100.1: icmp_req=2 ttl=64 time=0.106 ms
64 bytes from 192.168.100.1: icmp_req=3 ttl=64 time=0.089 ms

--- 192.168.100.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.089/0.289/0.672/0.270 ms
mininet> exit

コントローラと接続できて、仮想ホスト1(h1)と仮想ホスト2(h2)で通信ができました。

今回は以上になります。

2014年3月12日水曜日

OpenFlow Mininetのトポロジーをカスタマイズしてみる3

今回はMininetのトポロジーを変更して、Mininetを動かすゲストOSとは別のゲストOS上で動いているOpenFlowコントローラにつないでみます。

別のゲストOS上のコントローラに接続するためには、RemotoControllerクラスを使えるようにしなければいけません。
まずは以下の宣言をファイルの先頭部分に追加します。

from mininet.node import RemoteController

次にコントローラを追加する処理を変更します。
変更前は以下のようになっています。

    c1 = net.addController('c1')

コントローラを追加する時に、コントローラが起動しているサーバとポート番号を指定します。
ここではコントローラが起動しているサーバは192.168.56.10、コントローラの待ち受けポートは6653を指定しています。

    c1 = net.addController('c1',controller=RemoteController,ip='192.168.56.10',port=6653)


変更後のトポロジーは以下のようになります。

(topo_test.py)
#!/usr/bin/env python

from mininet.net import Mininet
from mininet.cli import CLI
from mininet.link import Link
from mininet.node import RemoteController

if '__main__' == __name__:

    net = Mininet()

    c1 = net.addController('c1',controller=RemoteController,ip='192.168.56.10',p
ort=6653)
    s1 = net.addSwitch('s1')
    h1 = net.addHost('h1', mac='a4:aa:aa:aa:aa:01',ip='192.168.100.1/24')
    h2 = net.addHost('h2', mac='a5:aa:aa:aa:aa:02',ip='192.168.100.2/24')

    #Link( h1, s1)
    #Link( h2, s1)
    h1.linkTo(s1)
    h2.linkTo(s1)

    net.start()
    CLI(net)
    net.stop()


次回は実行してコントローラに接続してみます。

2014年3月11日火曜日

気になるSDN関連ニュース O3プロジェクトシンポジウム開催(2014年3月14日)

O3プロジェクトシンポジウムが、3月14日に東京 秋葉原で開催されます。

O3プロジェクトとは、SDNを広域ネットワークに適用する研究開発のようです。
このようなプロジェクトがあったことを初めて知りました。

展示やデモンストレーションの他、研究発表、基調講演があります。
ONF(Open Networking Foundation)の偉い人も基調講演に来るようです。

詳しくは以下のURLを参照してください。

◆O3プロジェクト Webサイト
http://www.itevent.jp/o3sympo/index.html

◆関連トピック
http://japan.internet.com/busnews/20140305/4.html
http://jpn.nec.com/press/201309/20130917_01.html

2014年3月8日土曜日

気になるSDN関連ニュース NECとHPがSDNで協業

3月4日にNECとHPがSDNでの協業を発表しました。
今後、企業ネットワークへのSDN利用拡大を見込んだものに思えます。

両者が協業した内容は主に以下があります。
・SDNに対応するアプリケーションの開発環境を広く市場に提供する
・仮想ネットワーク操作のためのAPIの標準化を推進する
・SDNコントローラとSDN対応スイッチの相互接続の強化
・NECの仮想技術「Virtual Tenant Network」とHPのSDNコントローラとの接続性検証

より詳しい内容は以下を参照してください。

◆報道資料
http://jpn.nec.com/press/201403/20140304_01.html
http://www8.hp.com/jp/ja/hp-news/press-release.html?id=1594971


◆関連トピック
http://japan.zdnet.com/datacenter/analysis/35044758/
http://cloud.watch.impress.co.jp/docs/news/20140305_638026.html
http://itpro.nikkeibp.co.jp/article/NEWS/20140304/541115/

2014年3月6日木曜日

OpenFlow Mininetのトポロジーをカスタマイズしてみる2

以前、Mininetのトポロジーのカスタマイズという事で、仮想ホストのIPアドレスの割り当てをしました。
今回は仮想ホストのmacアドレスを任意のmacアドレスにしてみたいと思います。

Mininetのトポロジーで仮想ホストのIPアドレスを指定する場合、ホストの追加を以下のように書きました。

h1 = net.addHost('h1', ip='192.168.2.10/24')

任意のmacアドレスを設定する場合は、この部分の記述を少し変えてあげます。

h1 = net.addHost('h1', mac='aa:aa:aa:aa:aa:01', ip='192.168.2.10/24')

この例は仮想ホスト「h1」は、macアドレスが「aa:aa:aa:aa:aa:01」でIPアドレスが「192.168.2.10」のインターフェイスが設定されることになります。

以前作ったトポロジーにmacアドレスの設定を追加してみます。
ホスト1のmacアドレスは「aa:aa:aa:aa:aa:01」を設定します。
ホスト2のmacアドレスは「aa:aa:aa:aa:aa:02」を設定します。

(topo_test.py)
#!/usr/bin/env python

from mininet.net import Mininet
from mininet.cli import CLI
from mininet.link import Link

if '__main__' == __name__:

    net = Mininet()

    c1 = net.addController('c1')
    s1 = net.addSwitch('s1')
    h1 = net.addHost('h1', mac='aa:aa:aa:aa:aa:01',ip='192.168.100.1/24')
    h2 = net.addHost('h2', mac='aa:aa:aa:aa:aa:02',ip='192.168.100.2/24')

    #Link( h1, s1)
    #Link( h2, s1)
    h1.linkTo(s1)
    h2.linkTo(s1)

    net.start()
    CLI(net)
    net.stop()

このようになります。
気を付けるのは、macアドレスの先頭から8bit目は0にする事です。
I/Gビットにあたる部分のようです。

参考:http://itpro.nikkeibp.co.jp/article/COLUMN/20070829/280708/

あと、ネットワーク接続の記述の部分で、別の記述方法があるみたいなのでを少し変えてみました。
こういう書き方もできるみたいです。

    #Link( h1, s1)
    #Link( h2, s1)
    h1.linkTo(s1)
    h2.linkTo(s1)


実行して確認してみます。

$ sudo python topo_test.py
mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
s1 lo:  s1-eth1:h1-eth0 s1-eth2:h2-eth0
c1
mininet> dump
<Host h1: h1-eth0:192.168.100.1 pid=20973>
<Host h2: h2-eth0:192.168.100.2 pid=20974>
<OVSSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=20966>
<Controller c1: 127.0.0.1:6633 pid=20958>
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (2/2 received)
mininet> h1 ifconfig
h1-eth0   Link encap:Ethernet  HWaddr aa:aa:aa:aa:aa:01
          inet addr:192.168.100.1  Bcast:192.168.100.255  Mask:255.255.255.0
          inet6 addr: fe80::a8aa:aaff:feaa:aa01/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:9 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:658 (658.0 B)  TX bytes:838 (838.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

mininet> h2 ifconfig
h2-eth0   Link encap:Ethernet  HWaddr aa:aa:aa:aa:aa:02
          inet addr:192.168.100.2  Bcast:192.168.100.255  Mask:255.255.255.0
          inet6 addr: fe80::a8aa:aaff:feaa:aa02/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:9 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:658 (658.0 B)  TX bytes:838 (838.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

mininet> exit


ホスト1のmacアドレスが「aa:aa:aa:aa:aa:01」、ホスト2は「aa:aa:aa:aa:aa:02」になりました。

以上です。

2014年3月4日火曜日

trema バージョンアップされています

以前、Ubuntu13.にtremaをインストールしたところ、tremaのバージョンが上がっていました。

インストールしたtremaのバージョンは0.4.6です。
以前インストールしたのは0.3.19でした。

tremaのバージョンアップでは、本体のみならずサンプルプログラムも変更されていたようです。
とりあえず変わっていることに気付いたのはsimple-routerのサンプルコードです。
他にも変わっているサンプルソースがあるかもしれません。

simple-routerのサンプルコードは以前掲載しましたが、個人的に特に変わったと感じたのがrouter-util.rbのソースが無くなってたことです。
router-util.rbはルータの機能を実装するために、ARPとICMPパケットを作るプログラムです。
今のサンプルコードではrouter-util.rbの代わりにpioというモジュールを使っているようです。

pioと言うのは、ARPやICMP、LLDPのパケット作成や、解析をするが簡単にできるライブラリです。

コードのサンプル等は以下のリンク先を参考にして下さい。

https://github.com/trema/pio

このサンプルを見ると、容易にARPやICMPパケットが送れるようです。

2014年2月27日木曜日

SDNの今後の展望!?

興味深い記事がありました。

SDNに関するぶしつけな質問にシスコが本音で答えてくれた
http://ascii.jp/elem/000/000/864/864091/

まだSDNではカバーできない部分がいくらでもあります。
従来のNW技術者も必要ですね。

うまく組み合わせて使うことが重要になるのでしょう。

2014年2月26日水曜日

気になるSDN関連ニュース 東京駅にSDN導入

ソチオリンピックが終わりました。
世界のトップ選手の技術は目を見張るものがあります。
ボブスレー。自分が一生やる事はないかもしれないのに、放送しているとうっかり見てしまう。

閑話休題。
東京駅の駅構内ネットワークにNECのSDN技術が活用されるようです。

今までにも病院やTV局、DCなど、いくつものSDN導入事例がありましたが、今回は東京駅です。
NECはDC以外への展開にも積極的な印象です。

◆報道資料
http://jpn.nec.com/press/201402/20140224_01.html

◆関連トピック
http://ascii.jp/elem/000/000/869/869703/
http://cloud.watch.impress.co.jp/docs/news/20140224_636627.html
http://itpro.nikkeibp.co.jp/article/NEWS/20140224/538604/

2014年2月23日日曜日

Trema Day #5に行ってきました

2月22日(土)に開催されたTrema Day #5に行ってきました。

到着が少し遅れてしまい、初めの方のお話を聞きそびれてしまいました。

Trema Dayって何をやっているのかと言うと(個人的感想)。
 ・Tremaを使ってこんな事やりました
 ・試しにこんなプログラム作っちゃいました
 ・こういうツール使うと便利ですよー

みたいな感じで、スライドを使って発表します。

自分にとっては難しい内容だったりして、結構話についていけてなかったりしています(;^_^A
他の参加者の方が今回の内容をまとめてくださったようなので、リンクをつけておきます。

http://gvtkne.blogspot.jp/2014/02/trema-day-5.html

だいたい、3か月毎に開かれているので、次は5月頃ですかね?

2014年2月21日金曜日

OpenFlow Mininetのバージョンとトポロジー

2月19日に載せたMininetのトポロジーのサンプルですが、最近のバージョンだとエラーになってしまうようですね。

前は動いたのになぜ!?と思ったら、動いたのはUbuntu11.10上(古い!)のMininetでした・・・。
このMininetのバージョンは、mininetディレクトリ内のLICENSEというファイルをみると1.0.0のようです。

最近のMininetでは、以下でバージョンを表示できます。

$ sudo mn --version
2.1.0

2月20日に載せたMininetのトポロジーはバージョン2.1.0で動きました。
ちなみにこのMininetはUbutu13.04上で動いています。

残念ながら新しいバージョンのMininetでは、19日に載せたトポロジーをそのまま動かすことはできませんでしたが、トポロジーの書き方の参考にはなりました。
また、Mininetのトポロジーの書き方を調べてみると、結構いろいろな書き方ができるようです。

また何か良いものを見つけたら載せたいと思います。

OpenFlow Mininetのトポロジーをカスタマイズしてみる

今回はMininetのトポロジーを作ってみます。

Mininetのトポロジーの書き方は、以下も参考にしました。

http://osrg.github.io/ryu-book/ja/html/spanning_tree.html?highlight=mininet


スイッチ1つ、ホスト2つのトポロジーを作ってみます。
ホスト1のIPアドレスは「192.168.100.1」を割り当てます。
ホスト2のIPアドレスは「192.168.100.2」を割り当てます。

スクリプトの名前は「topo_test.py」とします。

#!/usr/bin/env python

from mininet.net import Mininet
from mininet.cli import CLI
from mininet.link import Link

if '__main__' == __name__:

    net = Mininet()

    c1 = net.addController('c1')
    s1 = net.addSwitch('s1')
    h1 = net.addHost('h1', ip='192.168.100.1/24')
    h2 = net.addHost('h2', ip='192.168.100.2/24')

    Link( h1, s1)
    Link( h2, s1)

    net.start()
    CLI(net)
    net.stop()

スクリプトを書いたら、以下のコマンドで実行します。

sudo python ./topo_test.py

実行すると「sudo mn」でMininetを起動したときのように、仮想ネットワークのCLI(コマンドラインインターフェイス)に切り替わります。
いくつかコマンドを打って、仮想環境の状態を確認してみます。

net
dump
pingall

mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
s1 lo:  s1-eth1:h1-eth0 s1-eth2:h2-eth0
c1
mininet> dump
<host h1-eth0:192.168.100.1="" pid="1649">
<host h2-eth0:192.168.100.2="" pid="1650">
<ovsswitch lo:127.0.0.1="" pid="1642" s1-eth1:none="" s1-eth2:none="">
<controller 127.0.0.1:6633="" pid="1634">
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (2/2 received)

終了するときは「exit」と打ちます。

簡単ではありますが、仮想環境ができました。
以上になります。

2014年2月19日水曜日

OpenFlow Mininetのトポロジーって何だ!?

今回はMininetのトポロジーについてです。

ここで言うトポロジーとは、ネットワークの接続形態の事を指しています。
Mininetでは、スクリプトを書いてトポロジー作れば、任意の仮想ネットワークを作ることができます。

ただ、トポロジーの書き方をネットで調べていましたが、どう書くのか良くわかりませんでした。
pythonで書けば良いという事は分かったのですが。

ところが先日、分かりやすいスクリプトが見つかりました。
そのスクリプトがこれです。

from mininet.net import Mininet
from mininet.node import Controller, OVSKernelSwitch, RemoteController
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.util import createLink

    # Create an empty network.
    net = Mininet(controller=RemoteController, switch=OVSKernelSwitch)
    net.addController('c0')

    # Creating nodes in the network.
    h0 = net.addHost('h0')
    s0 = net.addSwitch('s0')
    h1 = net.addHost('h1')
    s1 = net.addSwitch('s1')

    # Creating links between nodes in network.
    h0int, s0int = createLink(h0, s0)
    h1int, s1int = createLink(h1, s1)
    s0pint, s1pint = createLink(s0, s1)

    # Configuration of IP addresses in interfaces
    s0.setIP(s0int, '192.168.1.1', 26)
    h0.setIP(h0int, '192.168.1.2', 26)
    s1.setIP(s1int, '192.168.1.65', 26)
    h1.setIP(h1int, '192.168.1.66', 26)
    s0.setIP(s0pint, '192.168.1.129', 26)
    s1.setIP(s1pint, '192.168.1.130', 26)

    # start stuff and present CLI
    net.start()
    CLI(net)
    net.stop()

参考:http://lists.noxrepo.org/pipermail/pox-dev-noxrepo.org/2012-September/000231.html

このスクリプトでスイッチ2台、ホスト2台の仮想環境が作れます。
また、それぞれのインターフェイスに任意のIPアドレスを振っています。

このスクリプトを参考にして、トポロジーをカスタマイズしてみようと思います。

2014年2月18日火曜日

Trema Day #5が開催されます

こんにちは、鯵王です。

2月22日(土)にTrema Day #5が開催されます。
SDNやOpenFlow開発者のためのイベントです。

詳しくは以下のページを参照してください。

http://atnd.org/event/E0024377

Tremaが中心になりそうですが、Trema以外の話題もあったりします。
興味がある人は参加してみてはどうでしょうか。

SDN Conference 2014 行ってきました

今日はSDNカンファレンスに行ってきました。

テレビ朝日のSDN導入事例や、IBM、マクニカ、NEC、ブロケードなどのベンダーの製品情報などが聞けました。

初めはテレビ朝日の導入事例で、EX THEATERやEX TOWERにSDNを使っているというお話。
こちらはNECのSDN製品を使用したようです。

つないだ機器のMACアドレスで認証し、適切なネットワークに接続する技術が使われいるみたいです。
その他にもネットワークのレイヤー管理など。

他のベンダーは、大体は製品紹介が主でした。
前から言われている事だと思いますが、サーバの仮想化が進んだものの、ネットワークが足かせになっている。
それをどうにかする製品を用意した、といった感じです。
他には大体どの製品も以下の共通点があるようです。

・主なターゲットはデータセンターやクラウド
・GUIでネットワークの設定ができること
・OpenStackなどのオーケストレーターとの連携ができる

NECはデータセンターと、テレビ朝日のようなオフィスLANへの導入が半々ぐらいと聞きました。
いずれにしても、サーバやスイッチの数が数十、数百といった規模でないと、メリットが受けられない可能性があるようです。

あと、今の課題としてはエンジニア不足や監視や管理の方法が不十分、トラブルの原因特定方法、この技術が続くかが不確定といった事があるそうです。

2014年2月17日月曜日

OpenFlow Mininetで別サーバのコントローラに接続する

今回もMininetとTremaを使います。

今回はMininetを動かしているゲストOSとは別のゲストOSで起動しているTrema(コントローラ)に接続してみます。
前に掲載した「Openflow MininetのコントローラをTremaにしてみる その2」と「VirtualBoxのゲストOS同士で通信する」の組み合わせです。

ゲストOS #1
・Trema(コントローラ)を動かしているゲストOS
・IPアドレスは192.168.56.10

ゲストOS #2
・Mininetを動かしているゲストOS
・IPアドレスは192.168.56.20

まずはゲストOS #1でTremaを起動します。
コントローラのプログラムは、例によってhello-tremaです。

trema run hello-trema.rb

次にゲストOS #2でMininetを起動します。
以前と違うのは、コントローラが起動しているサーバのIPを指定することです。

sudo mn --controller remote,ip=192.168.56.10,port=6653

Mininetを起動するとゲストOS #1のTremaを起動した画面に以下のようなメッセージが表示されました。

$ trema run hello-trema.rb
Hello 0x1!

今後は、この環境を使っていろいろ試してみたいと思います。

2014年2月15日土曜日

VirtualBoxのゲストOS同士で通信する

今回はVirtualBoxの中のゲストOS同士で通信をします。

VirtualBoxのバージョンは4.3.6です。

1.VirtualBoxの設定

ホストOS側の仮想環境とのインターフェイスの設定をします。
メニューから、ファイル>環境設定で設定画面を開きます。

ネットワークをクリックし、ホストオンリーネットワークのタブを開きます。
「VirtualBox Host-Only Ethernet Adapter」をダブルクリック(もしくは選択して画面右側にあるドライバーのアイコンをクリック)します。


IPV4アドレスを入力します。
今回はデフォルト値(192.168.56.1)を使います。


次にゲストOSのネットワーク設定を行います。

メイン画面で、変更するゲストOSをクリックし、上部の「設定」アイコンをクリックします。

設定画面左側のネットワークをクリックします。
続いて画面右側のアダプタータブで設定を変更します。


【アダプター1のタブ】
 ・「ネットワークアダプターを有効化」にチェック入れます。
 ・割り当ては「NAT」を選択します

【アダプター2のタブ】
 ・「ネットワークアダプターを有効化」にチェック入れます
 ・割り当ては「ホストオンリーアダプター」を選択します
 ・名前は「VirtualBox Host-Only Ethernet Adapter」を選択します

アダプター1はインターネットなどができるように、NATにしておきます。
ホストOSからゲストOSにsshでログインできるように、アダプター2はホストオンリーアダプターにします。
ホストオンリーアダプターでもゲストOS同士の通信ができるようです。

今回使用するゲストOS(ゲストOS #1、ゲストOS #2とします)に同じ設定をします。


2.ゲストOSのネットワーク設定

ゲストOSを起動し、固定IPアドレスを変更します。
今回は以下のように設定します。

【ゲストOS #1】
 eth0 IPアドレス:DHCP
 eth1 IPアドレス:192.168.56.10

【ゲストOS #2】
 eth0 IPアドレス:DHCP
 eth1 IPアドレス:192.168.56.20

変更をする前に、ifconfigコマンドで変更前の情報を表示しておくと良いと思います。

vi等で設定ファイルを書き換えます。ゲストOS #1の場合は以下のようにします。

設定ファイル:/etc/network/interfaces

auto eth0
iface eth0 dhcp

auto eth1
iface eth1 inet static
address 192.168.56.10
netmask 255.255.255.0

↓この設定は残しておきます。

auto lo
iface lo inet loopback

設定を変更したら、有効にするためインターフェースの再起動をします。
再起動しても変わらなかったり、画面がちゃんと表示されなくなるようだったらOSを再起動した方がよさそうです。

sudo service networking restart

もしくは

sudo /etc/init.d/networking restart

ゲストOS #2も同様に(IPはゲストOS #2にIPで)設定します。


3.通信してみる

ゲストOS #1からpingを3回送ります。

ping -c3 192.168.56.10

$ ping -c3 192.168.56.20
PING 192.168.56.20 (192.168.56.20) 56(84) bytes of data.
64 bytes from 192.168.56.20: icmp_seq=1 ttl=64 time=0.395 ms
64 bytes from 192.168.56.20: icmp_seq=2 ttl=64 time=0.764 ms
64 bytes from 192.168.56.20: icmp_seq=3 ttl=64 time=0.775 ms

--- 192.168.56.20 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.395/0.644/0.775/0.179 ms

ゲストOS #2からpingを送ります。

ping -c3 192.168.56.20

$ ping -c3 192.168.56.10
PING 192.168.56.10 (192.168.56.10) 56(84) bytes of data.
64 bytes from 192.168.56.10: icmp_req=1 ttl=64 time=0.335 ms
64 bytes from 192.168.56.10: icmp_req=2 ttl=64 time=1.05 ms
64 bytes from 192.168.56.10: icmp_req=3 ttl=64 time=0.844 ms

--- 192.168.56.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.335/0.746/1.059/0.303 ms

ゲストOS同士で通信出来ました。
後はホストOSからゲストOSにログインしてみます。

teratermなどでゲストOSのeth1に設定したIPアドレスで接続して、ログインできればOKです。

今回は以上になります。

2014年2月12日水曜日

Openflow MininetのコントローラをTremaにしてみる その2

以前「Openflow MininetのコントローラをTremaにしてみる」の中で一部うまくいかなかった所が解決しました。

内容は、Mininetで使用するコントローラをTremaにしてみましたが、vmwareに作ったUbuntu13.10、Trema0.4.6では接続できなかった件です。

原因はTremaの待ち受けポートが6633から6653に変わっていたためです。
以下のリンクからその事がわかりました。

https://github.com/trema/trema/commit/0699ffd3a73f56e810096a9ce3c5ea9781596783
http://trema.hatenablog.jp/entry/20120312/1331548450

うまく動いた環境のTremaは、バージョンが少し古く、まだポート番号が6633だったのでしょう。

以下ではMininet側の接続ポートを6653にして試してみます。
前回同様、端末を2つ用意し、まずはTremaを起動します。

trema run hello-trema.rb

続いてMininetを起動します。
今回は「port=6653」を追加します。

sudo mn --controller remote,port=6653

Mininetが起動するとTremaを起動した端末に以下のメッセージが表示されました。

$ trema run hello-trema.rb
Hello 0x1!

コントローラのプログラムがhello-tremaなので通信は出来ませんが、Mininetのスイッチと接続出来ました!

2014年2月7日金曜日

気になるSDN関連ニュース OpenDaylightを使った新製品

IBMからSDNの新製品である「IBM SDN VE OpenFlow Edition」と「IBM SDN VE KVM Edition」が発表されました。

 「SDN VE OpenFlow Edition」はOpenDaylightをベースにした初の商品という事です。
OpenDaylightは先日書きましたが、2月4日にリリースされたばかりですね。
この商品はOpenFlow1.0に準拠した仮想、物理スイッチを管理できるようです。

「IBM SDN VE KVM Edition」はKVMの仮想環境でのオーバーレイネットワークの構築や、VMwareと混在したネットワークの構築、管理が可能という事です。

◆報道資料
http://www-06.ibm.com/jp/press/2014/02/0501.html

◆関連トピック
http://itpro.nikkeibp.co.jp/article/NEWS/20140205/534922/?ST=openflow
http://cloud.watch.impress.co.jp/docs/news/20140206_634108.html
http://enterprisezine.jp/article/detail/5581

◆OpenDaylightについてはこちら
http://www.opendaylight.org/

2014年2月6日木曜日

SDN OpenDaylightリリース

当初2013年12月に最初のリリースされる予定だったOpenDaylightですが、米国時間の2月4日にとうとうリリースされました。
そういえばリリースされてなかったですね、忘れていました。

OpenDaylightと言えばSDNのオープンソースのプロジェクトで、多数の企業がそのプロジェクトに参加しています。

今回のリリースされたのは「Hydrogen」と言うらしいです。
個人でダウンロードして試す事も出来るようです。

コチラからダウンロードできます。
http://www.opendaylight.org/software/downloads

◆OpenDaylightプロジェクト
http://www.opendaylight.org/

◆関連ニュース
http://www.atmarkit.co.jp/ait/articles/1402/05/news050.html
http://sourceforge.jp/magazine/14/02/06/144500
http://news.mynavi.jp/news/2014/02/05/304/
http://www.publickey1.jp/blog/14/sdnopendaylighthydrogen.html

2014年2月5日水曜日

Openflow MininetのコントローラをTremaにしてみる

今回はMininetのコントローラにTremaを使ってみます。

まずTremaを起動します。
今回は試しにhello_trema.rbで。

trema run ./hello-trema.rb

次に、別の端末でMininetを起動します。

sudo mn --controller remote

Mininetを起動するとTremaを起動した端末にメッセージが表示されます

$ trema run ./hello-trema.rb
hello 0x1!

Mininetが起動したら、pingを投げてみます。

h1 ping -c2 h2

hello-tremaはパケットを処理する機能が実装されていないので、当然pingは通りません。
しかし、コントローラがTremaになったことは確認できました。
ここまではVirtualBoxに作ったUbuntu12.04、Tremaのバージョン0.3.20の話。

vmwareに作ったUbuntu13.10、Trema0.4.6では上手くいきませんでした。

何かわかったらまたお知らせします。

2014年1月31日金曜日

OpenFlow  UbuntuにTremaをインストールしてみる

今回はUbuntuにtremaをインストールしてみます。

tremaのインストールは以前実施していますが、今回はOS(Ubuntu)のバージョンが12.04から13.10に上がっています。
まずは一度、前回と同じ手順でインストールしてみます。

$ sudo apt-get install gcc make ruby1.8 rubygems1.8 ruby1.8-dev libpcap-dev libsqlite3-dev
$ sudo gem install trema

tremaのインストールでエラーが発生しました。

(省略)
No package 'glib-2.0' found
gcc -I.  -I../../../include -DHAVE_CONFIG_H -I../wireshark-1.0.0-includes -I/usr/local/include -I/usr/local/include -DINET6 -D_U_=__attribute__\(\(unused\)\) -Wall -Wpointer-arith -g -I/usr/local/include -DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API -pthread -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/local/include/glib-2.0 -I/usr/lib/glib-2.0/include -fPIC -DPIC -D_LITTLE_ENDIAN_ -DOPENFLOW_DST_TCP_PORT=6633   -c -o packet-openflow.o packet-openflow.c
packet-openflow.c:19:18: fatal error: glib.h: そのようなファイルやディレクトリはありません
 #include 
                  ^
compilation terminated.
make: *** [packet-openflow.o] エラー 1
rake aborted!
(省略)

glib.hファイルが見つからないといったが内容のようです。

解決方法をネットで見つけました。
libglibc2.0-devをインストールすればよさそうです。

$ sudo apt-get install libglib2.0-dev

tremaのインストールを再実行してみます。

$ sudo gem install trema
Building native extensions.  This could take a while...
Successfully installed trema-0.4.6
1 gem installed
Installing ri documentation for trema-0.4.6...
Installing RDoc documentation for trema-0.4.6...

インストールが完了しました。
tremaのバージョンを確認します。

$ trema --version
trema version 0.4.6

tremaのバージョン上がってました!
前回は0.3.19でした。

今回は以上になります。

2014年1月29日水曜日

VMware PlayerでゲストOSのバックアップ

今回はVMware PlayerのゲストOSのバックアップについて調べました。

使用するのはVMware Playerのバージョン6です。

VMware Workstationの方は、スナップショットやクローンの作成が出来るようですが、VMware Playerの方はそういった機能はなさそうで、VMイメージがあるフォルダごとバックアップをとってしまうようです。

Windows8の場合、VMのイメージファイルは以下にあります。

C:\Users\<username>\Documents\Virtual Machines
<username>は現在ログインしているユーザーの名前です。

このフォルダの中にゲストOSと同じ名前のフォルダがあるので、それを丸ごとコピーします。

バックアップはこれだけです。
以下はバックアップから戻す方法と、VMイメージを別のゲストOSにする方法です。

【バックアップから戻す】

1.バックアップ元のゲストOSをVMware Playerからファイルごと削除します。

2.コピーしたフォルダを元の場所に戻します。(フォルダ名、ファイル名は以前のままになっている事)

3.VMware Playerを起動し、仮想マシンを開くをクリックします。

4.ファイルの選択ダイアログで、元に戻したフォルダまで移動し「.vmx」ファイルを選択します。


【コピーしたVMイメージを別の名前のゲストOSにする】

1.コピーしたフォルダの名前を新しいゲストOS名にします。

2.そのフォルダ内に、コピー元のゲストOSの名前が付いたファイルあるので、それを新しいゲストOS名に変更します。

3.フォルダ内にある「.vmx」ファイルをテキストエディタで開き、コピー元のゲストOSの名前を新しいゲストOSの名前に置き換えます。

4.VMware Playerを起動し、仮想マシンを開くをクリックします。

5.先ほどコピーした新しいゲストOSのフォルダに移動し、「.vmx」のファイルを開きます。

6.「この仮想マシンは移動またはコピーされた可能性があります・・・」とメッセージが出るので、「コピーしました」をクリックします。

2014年1月28日火曜日

OpenFlow MininetのVMイメージを使う

今回はMininetを使用するもう一つの方法、VMイメージを使うパターンを試してみます。

推奨はVirtualBoxみたいなので、VirtualBoxを使います。

1.VMイメージのダウンロード

http://mininet.org/のページからVMイメージをダウンロードします。
画面左下や右側メニューの「Get Started」や「Download」のリンクからインストール関連のページに移動します。

「Option 1: Mininet VM Installation (easy, recommended)」の下にある「2.1.0」のリンクから以下のダウンロードページに移動します。

https://bitbucket.org/mininet/mininet-vm-images/downloads


今回は「mininet-2.1.0-130919-ubuntu-13.04-server-i386-ovf.zip」をダウンロードします。


2.VirtualBoxの設定

VirtualBoxを起動し、「新規」で仮想環境を作ります。
















名前とオペレーティングシステムはの各項目を入力し、次へをクリックします
 名前   :任意の名前を入力します
 タイプ  :Linuxを選択します
 バージョン:Ubuntu (64bit)を選択します


















メモリーサイズは任意のサイズを指定します


















ハードドライブは「仮想ハードドライブを追加しない」を選択し、作成をクリックします。


















VirtualBoxのイメージ保存先(Windows8の場合、C:\Users\<username>\VirtualBox VMs)の下に新規作成したゲストOS名と同じフォルダがあるので、ダウンロードしたMininetのVMイメージファイルを解凍します。


新規作成したVMを選択し、設定をクリックします















画面の左側でストレージを選択し、ハードディスクの追加のアイコン(コントローラーIDEの右側のアイコン)をクリックします















質問ダイアログで「既存のディスクを選択」をクリックし、ファイル選択ダイアログで解凍したVMイメージを選択します













新規作成したゲストOSを選択して起動ボタンをクリックします
















ログイン画面が表示されたら以下のアカウントでログインします。
 ユーザ:mininet
 パスワード:mininet


OpenFlow Mininetの使い方

今回はMininetの使い方を調べてみました。

ただし、もっといろいろオプションの指定が出来そうです。
また新しい発見があったら載せたいと思います。


【Mininetの起動方法】

sudo mn -h
起動オプションを表示します

sudo mn
デフォルトのトポロジと、NOXのコントローラの構成で起動します

sudo mn --controller remote
同一サーバ内の任意のコントローラを使用出来ます。
コントローラの方をあらかじめ起動しておきます。

sudo mn --controller remote, ip=[IPアドレス], port=[ポート番号]
別サーバの任意のコントローラを使用出来ます。
コントローラの方をあらかじめ起動しておきます。

sudo mn --test pingpair
デフォルトの構成で起動し、pingのテストを実施します。

sudo mn --topo=single,3
一つのスイッチに3つのホストがつながった構成で起動します

sudo mn --custom customtopo.py --topo sample
別のトポロジを(ここでは例としてcustomtopo.pyファイルのsample)指定して起動する


【Mininetの終了方法】

MininetのCLIでexitと打つか、Ctl+Dを押します

【MininetのCLIコマンド】

Mininetを起動すると、コマンドラインが表示されます。
コマンドラインで実行出来るコマンドを記します
helpで見ると以下に書かれているコマンド以外にもいくつかあります。

help
コマンドの一覧を表示します

nodes
ノードを表示します

net
リンクを表示します

dump
全てのノードの情報を出力します

pingall
全てのネットワーク接続に対してpingを送ります

他にもMininet内のノードを指定して実行するコマンドがあります
以下のように書きます。

ノード名 コマンド

例えばホストh1からh2にpingを飛ばす場合、以下のように書きます

h1 ping h2
h1 ping 10.0.0.2

その他、Linuxと同じ様なコマンドを実行する事が出来ます。

h1 ifconfig -a
h1 ps -a

今回は以上です。

2014年1月26日日曜日

VMwareにゲストOSをインストールしてみる

今回はVMware PlayerにゲストOSをインストールしてみます。

インストールするのは日本語版のUbuntuで、最新バージョンの13.10です。

まずは、Ubuntu Japanese Team: HomepageよりUbuntuのインストールイメージをダウンロードしてきます。

http://www.ubuntulinux.jp/

このページのUbuntuのダウンロードボタンをクリックします。
次のページでは日本語Remixイメージのダウンロードボタンをクリックします。

ダウンロードサイトの画面が表示されたら、適当なサイトからISOイメージをダウンロードします。
今回は64bit版をインストールするので、以下のISOイメージをダウンロードします。

ubuntu-ja-13.10-desktop-amd64.iso(ISOイメージ)

約1Gバイトありました。

では、インストールを始めます。
途中、細かくダイアログが出てきたりしますが、ここでは割愛します。

VMware Playerを起動し、「新規仮想マシンの作成」をクリックします。


















「後でOSをインストール」を選択し、次へをクリックします



















ゲストOSの選択画面では「Linux」を選択し、バージョンは「Ubuntu 64ビット」を選択して次へをクリックします



















仮想マシン名、イメージファイル保存先の場所を設定し次へをクリックします


















ディスク最大サイズはデフォルトの推奨サイズとし、「仮想ディスクを単一ファイルとして保存」を選択して次へをクリックします


















完了をクリックします



















「仮想マシン設定の編集」をクリックします


















画面左の「CD/DVD(SATA)」をクリックし、右側の「ISOイメージファイルを使用する」を選択します
参照ボタンをクリックし、ダウンロードしたUbuntuのISOイメージを選択してOKをクリックします

















仮想マシンの再生をクリックします


















エラー画面が表示されました・・・
インストール先のPCは、Intel VT-xが有効になっていなかったようです
BIOSの設定を変更して Intel Virtualization Technology を有効にしました
設定後、仮想マシンの再生を再実行しました
(BIOSの変更等は自己責任で行ってください;;BIOSの名称は、使用しているPCによって異なるかもしれません。)



Ubuntuのサンプル画面が表示されます

メモ
ゲストOSから本体のWindowsにマウスやキーボードのコントロールを戻すにはCtl+Altを押します

Ubuntuのインストールを開始するには、デスクトップの「Ubuntu 13.10のインストール」アイコンをダブルクリックします

















言語を選ぶ画面では、日本語が選択されている事を確認して続けるをクリックします

















特に問題なさそうなので、続けるをクリックします

















ディスクを削除してUbuntuをインストールが選択されてる事を確認して、インストールをクリックします




 

Ubuntuのインストールが始まります
Tokyoが選ばれている事を確認して、続けるをクリックします

















キーボードは日本語が選ばれている事を確認して、続けるをクリックします

















ログインに使用するユーザ名やパスワード等を入力し、続けるをクリックします

















Ubuntu Oneアカウントの設定画面です
ここではLogin laterをクリックして設定を飛ばしました


















いよいよインストールが始まりました
終わるまで待ちます

















インストールが終了した時の画面がコチラです
今すぐ再起動をクリックします

















これはCDが入りっぱなしの状態だったみたいです
Playerメニューのパワーから、一度ゲストOSの電源切ります

















メイン画面から、作成したゲストOSを選択し、「仮想マシン設定の編集」をクリックします


















画面左の「CD/DVD(SATA)」をクリックし、右側の「物理ドライブを使用する」を選択します
OKボタンを押して、前の画面に戻り「仮想マシンの再生」をクリックします

















ログイン画面が表示されたら、先ほど作ったユーザのパスワード入力してログインします

















デスクトップ画面が表示されます

















無事、インストールできたようです。

今回は以上になります

2014年1月25日土曜日

OpenFlow Mininetをインストールしてみる

今回はMininetのインストールをしてみます。

Mininetを使うには以下の方法があります。
・あらかじめUbuntuにMininetがインストールされたVMイメージを使う
・UbuntuかFedoraにソースを落としてインストールする
・パッケージからインストールする

今回はソースを落としてインストールしてみます。

推奨は最新のUbuntuにインストールするようですが、今回インストールしたUbuntuのバージョンは12.04です。 この記事を書いてる時点のUbuntuの最新バージョンは13.10でした。

インストール先のUbuntuのバージョンを確認してみる。
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 12.04.2 LTS
Release:        12.04
Codename:       precise

まずはMininetのソースコードをダウンロードします。

git clone git://github.com/mininet/mininet

以下のコマンドでMininetをインストールします

$ sudo mininet/util/install.sh

待つこと約20分
最後に以下のような表示がされて、インストールが完了したようです。

Enjoy Mininet!

上記インストールのコマンド(install.sh)の後にオプションを付ける事で、何をインストールするか決めれるようです。
今回は何もつけなかったので、結構時間がかかってしまったのかもしれません。

バージョンを確認してみます。
$ mn --version
2.1.0+

試しに基本的な機能をテストしてみます。

$ sudo mn --test pingall
[sudo] password for sdn:
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1)
*** Configuring hosts
h1 h2
*** Starting controller
*** Starting 1 switches
s1
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (2/2 received)
*** Stopping 1 switches
s1 ..
*** Stopping 2 hosts
h1 h2
*** Stopping 1 controllers
c0
*** Done
completed in 4.004 seconds

ちゃんと動きそうな予感。

以上です。

OpenFlow Mininetとは何だ!?

Tremaや他のフレームワークでコントローラを作っても、動作確認するにはOpenFlow対応スイッチや、それに接続するホストPCなどが必要になります。
以前紹介しましたが、Tremaには簡易な確認環境が用意されています。

他にもMininetという仮想ネットワーク環境を作るソフトがあるようです。

Mininet
http://mininet.org/

今度はこのMininetを試してみようと思います。
とりあえず今回は、Mininetを使っていろいろ試した方のページを探してみました。

OpenFlow の動作確認に便利な Mininet を OpenFlow 1.3 で使う http://momijiame.tumblr.com/post/73412814308/openflow-mininet-openflow-1-3

OpenFlow/mininet
http://labs.beatcraft.com/ja/index.php?OpenFlow%2Fmininet

OpenFlowを気軽に試せるMininet
http://tech-sketch.jp/2012/07/openflowmininet.html

OpenFlow環境をつくってみた(POX,Mininet編) http://nushu123.blogspot.jp/2012/07/openflowmac.html
OpenFlow環境をつくってみた(NOX,Mininet編) http://nushu123.blogspot.jp/2012/07/openflownoxmininet.html

Mininetの使い方について(1)
http://www.cloudcluster.cloudysunny14.org/show_materials?id=ahBzfm9uY2xvdWRjbHVzdGVyciYLEg9NYXRlcmlhbHNUaGVtZXMY0YwBDAsSCE1lbnRpb25zGOkHDA
Mininetの使い方について(2)
http://www.cloudcluster.cloudysunny14.org/show_article?id=ahBzfm9uY2xvdWRjbHVzdGVyciwLEg9NYXRlcmlhbHNUaGVtZXMY0YwBDAsSCE1lbnRpb25zGICAgICAwK8KDA

これらの内容を参考に実際に使ってみたいと思います。

IPパケットについてまとめてみた

今回はIPパケットについてです。

ここではIPv4について記述します。 tremaのsimple_routerでは、ICMPリプライを送るのにIPパケットを作りました。 もう少し理解を深めると言う事で、IPパケットについてまとめてみます。

IPパケットの先頭にはIPヘッダーが付いていて、パケットの宛先や送信元のアドレス、パケットの長さなどの情報が含まれています。
IPヘッダの長さは先頭の20バイトは固定で、続いてオプション情報が可変で0~40バイト、その後ろに送りたいデータが来ます。
IPパケットの中身はこんな感じです。

0481216202428
バージョンヘッダ長サービスタイプ全長
IDフラグ断片位置
TTLプロトコルチェックサム
送信元IPアドレス
宛先IPアドレス
オプション情報
データ
※表見出しの緑色はの数字はビット数になります。

各フィールドの説明は以下になります。

バージョンIPプロトコルのバージョン。IPv4の場合は4
ヘッダ長IPヘッダの32ビット単位の長さを表す。この情報によりデータの開始位置がわかる。通常はIPヘッダの固定部分の長さの5が入る
サービスタイプIPパケットの優先度などを表す。現在のTCP/IPではこのフィールドでの指定はほとんど行われていない。
全長IPパケット全体の長さが入る。
ID分割したパケットを復元するのに使用する。
フラグ3桁のうち、先頭は使用しない。真中は分割の可否を表します。1が分割不可です。末尾が分割されたパケットの終わりを表します。0だと終わりです。
断片位置パケットを分割した際の元の位置を格納します。パケットの分割は8バイト単位で行われるので、8バイト単位の値が格納されます。
TTL パケットの寿命を表します。パケットが経由できるルータの数になります。
プロトコル上位のプロトコルを示す番号が入ります。例えばICMPなら1、TCPなら6、UPDなら17です。
チェックサムIPヘッダの誤り検査に使用します。
送信元IPアドレスパケットの送信元のIPアドレスが入ります。
宛先IPアドレスパケットの宛先IPアドレスが入ります。
オプション情報4バイト単位の可変長フィールドです。通常は使用されない。
データIPパケットで送りたいデータ(ペイロード)が入ります。


以上です。

2014年1月23日木曜日

Tremaを試す ~simple-ruter その10~

今回もrouter-utilsのソースを続きから見ていきます。
router-utilsは今回で最後です。

139  module RouterUtils
140    def create_arp_request_from interface, addr
141      arp = ARPRequest.new( interface.hwaddr, addr, interface.ipaddr )
142      arp.pack
143    end
144  
145    def create_arp_reply_from message, replyaddr
146      arp = ARPReply.new( message.macsa, replyaddr, message.arp_spa, message.arp_tpa )
147      arp.pack
148    end
149  
150    def create_icmpv4_reply entry, interface, message
151      offset = 14 + 20 + 4
152      payload = message.data.unpack( "C*" )[ offset .. message.data.length - 1 ]
153      icmp = ICMPEchoReply.new( payload )
154      ip_packet = IPPacket.new( :id => message.ipv4_id,
155                                :protocol => message.ipv4_protocol,
156                                :ttl => message.ipv4_ttl,
157                                :daddr => message.ipv4_saddr,
158                                :saddr => message.ipv4_daddr,
159                                :payload => icmp )
160      eth_header = EthernetHeader.new( entry.hwaddr, interface.hwaddr, 0x0800 )
161  
162      eth_header.pack + ip_packet.pack
163    end
164  end

139行目
モジュールの定義をしています。

140~143行目
ARPリクエストをするメソッドです。
メソッドの結果はARPリクエストのパケットを返します。

145~148行目
ARPリプライをするメソッドです。
メソッドの結果はARPリプライのパケットを返します。

150~163行目
ICMPの応答を返すメソッドです。
offset変数にはイーサネットヘッダー、IPヘッダー、ICMPヘッダーのバイト長を足した値が入ります。
payload変数にはパケットのペイロード部分を取り出します。
icmp変数には、ICMPEchoReplyクラスがセットされます。

ip_packet変数には、IPPacketクラスがセットされます。
引数にはIPヘッダの項目と、ICMPパケットが渡されています。

eth_header変数には、宛先のmacアドレスと送信元のmacアドレスと、IPv4を意味する0x0800が入ります。

162行目でeth_header変数の値とip_packet変数の値をバイナリにしてくっつけます。

これでrouter-utilsのソースは終わりです。

packメソッドについて補足

router-utilsのソースを読んでいて、最も難解なのがpackメソッドでした。
補足などと言えるほど理解していないかもですが、確認したことをメモしておきます。

例えば"abc123"という文字列をunpack("C*")すると[97, 98, 99, 49, 50, 51]という配列が返ってきます。
配列の数字は文字コードのようです。aの文字コードは97、1の文字コードは49です。

(pack.rb)
p "abc123".unpack("C*")]

$ ruby pack.rb
[97, 98, 99, 49, 50, 51]

次に、unpack("C*")の後にpack("C*").unpack("n*")を追加すると、配列をバイナリにし、その後ビッグエンディアンの16bit 符号なし整数にします。

p "abc123".unpack("C*").pack("C*").unpack("n*")

$ ruby pack.rb
[24930, 25393, 12851]

これはどうなったのかというと、配列の1つ目の24930は97と98をくっつけたものです。

(10進数)→(2進数)
24930→110000101100010

97→1100001
98→1100010

桁を揃えて結合すると同じ値になります

24930→0110000101100010
97,98→0110000101100010

99と49、50と51も同様です。

packのテンプレートの"C"が8bit 符号なし整数なので、丁度配列2つ分です。

続いて、テンプレート文字の"n"は何なのか。
16進数の0xffをpackしてみます。

p [0xff].pack("n*")

$ ruby pack.rb
"\000\377"

0xffの8進数表現になりました。

他の数も試してみます。
p [0x01ff].pack("n*")
p [0x0102ff].pack("n*")

$ ruby pack.rb
"\001\377"
"\002\377"

どうやら8ビットずつを8進数で表示したようです。
0x0102ffは後ろから16ビットだけが変換されたようで、数字が大きいと切られてしまうみたいですね。

router-utilsのソースで見てみます。
例えばICMPEchoReplyクラスの↓この辺など。

124      words = @payload.pack( "C*" ).unpack( "n*" )
125      words.each do | each |
126        @checksum = get_checksum( @checksum, each )
127      end

呼び出し元にさかのぼっていくと元データはmessage.dataです。
message.dataはネットワークに流れるデータなのでバイナリなのでしょう。
unpack("C*")で8bit 符号なし整数の配列にしています。

152      payload = message.data.unpack( "C*" )[ offset .. message.data.length - 1 ]
153      icmp = ICMPEchoReply.new( payload )

その後、(124行目)ICMPEchoReplyクラスでpack("C*")を実行して再びバイナリに変換し、unpack("n*")でビッグエンディアンの16bit 符号なし整数に変換しています。
IPヘッダやICMPヘッダのチェックサム(get_checksumメソッドで計算)は16ビットずつ計算していくので、unpack("n*")で16bitに変換して配列をループで処理しているようです。

以上になります。

2014年1月22日水曜日

Tremaを試す ~simple-ruter その9~

今回はrouter-utilsのソースを前回の続きから見ていきます。

 72  class IPPacket
 73    attr_accessor :id, :protocol, :daddr, :saddr, :payload
 74  
 75    def initialize options
 76      @id = options[ :id ]
 77      @protocol = options[ :protocol ]
 78      @daddr = options[ :daddr ]
 79      @saddr = options[ :saddr ]
 80      @payload = options[ :payload ]
 81      @tot_len = 20 + payload.length
 82    end
 83  
 84    def pack
 85      csum = get_checksum( 0, 0x4500 )
 86      header = [ 0x45, 0x00 ] # Version, IHL, ToS
 87  
 88      csum = get_checksum( csum, @tot_len )
 89      header += [ @tot_len >> 8, @tot_len & 0xff ] # len
 90  
 91      csum = get_checksum( csum, @id )
 92      header += [ @id >> 8, @id & 0xff ] # ID
 93  
 94      csum = get_checksum( csum, 0x4000 )
 95      header += [ 0x40, 0x00 ] # Flags, Frag offset
 96  
 97      csum = get_checksum( csum, 0x40 * 0x100 + @protocol )
 98      header += [ 0x40, @protocol ] # ttl, protocol
 99  
100      csum = get_checksum( csum, @saddr.to_i >> 16 )
101      csum = get_checksum( csum, @saddr.to_i & 0xffff )
102      csum = get_checksum( csum, @daddr.to_i >> 16 )
103      csum = get_checksum( csum, @daddr.to_i & 0xffff )
104      header += [ csum >> 8, csum & 0xff ] # checksum
105      header += @saddr.to_a + @daddr.to_a
106  
107      header.pack( "C*" ) + @payload.pack
108    end
109  end
110  
111  class ICMPPacket
112    attr_reader :payload, :length
113  
114    def initialize type, code, payload
115      @type = type
116      @code = code
117      @payload = payload
118      @length = 4 + payload.length
119    end
120  
121    def pack
122      @checksum = get_checksum( 0, @type * 0x100 + @code )
123  
124      words = @payload.pack( "C*" ).unpack( "n*" )
125      words.each do | each |
126        @checksum = get_checksum( @checksum, each )
127      end
128  
129      [ @type, @code, @checksum ].pack( "C2n" ) + @payload.pack( "C*" )
130    end
131  end
132  
133  class ICMPEchoReply < ICMPPacket
134    def initialize payload
135      super( 0x00, 0x00, payload )
136    end
137  end
138  


72~82行目
IPパケットを作るクラスです。
73行目はアクセサの宣言をしています。

75行目のinitializeで引数を変数にセットしています。
@idには分割したIPパケットを復元する時に使用される識別子が入ります。
@protocolにはICMPやTCPといったをトランスポート層のプロトコルを識別する番号が入ります。
@daddrには宛先のIPアドレスが入ります。
@saddrには送信元のIPアドレスが入ります。
@payloadにはペイロード(転送したいデータ)が入ります。
@tot_lenにはIPヘッダーのバイト長の20と、ペイロードの長さを足した値が入ります。

84~109行目
IPパケットを作るメソッドです。
csum変数にはIPパケットのチェックサムが入ります。
header変数にはIPヘッダのフォーマットに合わせてデータを追加していきます。

86行目はバージョンとヘッダ長、サービス種別をheader変数に追加しています。
IPv4の場合、バージョンには固定で4が入ります。
ヘッダ長にはIPv4ヘッダの固定長部分の長さである20バイトを4バイトで割った数の5が入ります。
サービス種別はこのプログラムでは0x00が固定でセットされています。

89行目はデータ全長をheader変数に追加しています。
ここでは先頭から8け桁取り出すために8ビット右シフトし、末尾から8ビット取り出すために0xffで論理積をしています。
なぜこんなことをしているのか疑問でしたが、どうやらpackメソッドを使うのに8ビットずつの配列にする必要があるためだと思います。

91行目は識別子をheader変数に追加しています。
95行目はフラグと断片位置をheader変数に追加しています。
このプログラムではIPパケットを分割禁止にしています。
98行目はttlとプロトコルをheader変数に追加しています。
このプログラムではttlは64がセットされています。

100行目から104行目は、宛先IPアドレスと送信元IPアドレスからチェックサムの計算を行っています。
IPヘッダのフォーマットでは、チェックサムはプロトコルの次のフィールドなので、header変数にチェックサムの値を追加する前にチェックサムより後ろのフィールドの値でチェックサムの計算をしています。
104行目はチェックサムをheader変数に追加しています。
105行目は宛先IPアドスと送信元IPアドレスをheader変数に追加しています。

107行目でheader変数をバイナリに変換し、@payload変数をpackメソッドで変換して追加します。

111~119行目
ICMPパケットを作るクラスです。
112行目はアクセサの宣言をしています。

114行目のinitializeで引数を変数にセットしています。
@typeには機能コードが入ります。
@codeには詳細な機能コードが入ります。
@payloadにはペイロード(転送したいデータ)が入ります。
@lengthにはICMPヘッダーのバイト長の4と、ペイロードの長さを足した値が入ります。

121~131行目
ICMPパケットを作るメソッドです。
@checksum変数にはチェックサムの値が入ります。

122行目の@checksum変数はget_checksumメソッドで@type変数と@code変数からチェックサムを求めています。
カッコ内の0x100は@type変数の値を256倍して16bitの先頭8bitに@type変数の値がくるようにします。
そこに@code変数の値を足し、こちらは末尾8bitが@code変数の値がくるようにします。

124行目は@payload変数の値をバイナリにし、unpackで16bitごとの配列にします。
その次のループでチェックサムを計算します。

129行目でICMPヘッダと@payload変数をバイナリにします。

133~137行目
ICMPリプライのパケットを作るクラスです。
ICMPPacketクラスを継承しています。

superでスーパークラスであるICMPPacketクラスのinitializeメソッドを呼び出します。
1つ目の引数はICMPのタイプでエコー応答の0、2つ目の引数はコードでエコー応答は固定で0が入ります。

今回はここまで。
router-utilsはあと少しで終わりです。

2014年1月21日火曜日

VMwareで仮想環境を作ってみる

今までVirtualBoxを使っていましたが、試しにVMwareを使ってみようと思います。
使うのはVMware Player 6です。

http://www.vmware.com/jp/products/player/

個人利用は無償だそうです。
とりあえずダウンロード。

インストールはウィザードに従ってすんなり終了しました。

今度、ゲストOSを作ってみます。

Tremaを試す ~simple-ruter その8~

今回ばrouter-utilsのソースを前回の続きから全体の半分ぐらいまで見ていきます。

以下のソースはrouter-utils.rbからの抜粋です

 33  class ARPPacket
 34    attr_accessor :type, :tha, :sha, :tpa, :spa
 35  
 36    def initialize type, tha, sha, tpa, spa
 37      @type = type
 38      @tha = tha
 39      @sha = sha
 40      @tpa = tpa
 41      @spa = spa
 42    end
 43  
 44    def pack
 45      eth_header = EthernetHeader.new( @tha, @sha, 0x0806 )
 46  
 47      # arp
 48      arp = [ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, @type ]
 49      arp += @sha.to_a + @spa.to_a + @tha.to_a + @tpa.to_a
 50  
 51      while arp.length < 46 do
 52        arp += [ 0x00 ]
 53      end
 54  
 55      eth_header.pack + arp.pack( "C*" )
 56    end
 57  end
 58  
 59  class ARPRequest < ARPPacket
 60    def initialize sha, tpa, spa
 61      tha = [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]
 62      super( 1, tha, sha, tpa, spa )
 63    end
 64  end
 65  
 66  class ARPReply < ARPPacket
 67    def initialize tha, sha, tpa, spa
 68      super( 2, tha, sha, tpa, spa )
 69    end
 70  end
 71  


33~43行目
ARPパケットを作るクラスです。
34行目はアクセサの宣言をしています。

36行目のinitializeで引数を変数にセットしています。
@typeにはARPリクエスト、ARPリプライといったARPパケットのタイプがセットされます。
@thaには宛先のmacアドレスが入ります。
@shaには送信元のmacアドレスが入ります。
@tpaには宛先のIPアドレスが入ります。
@spaには送信元のIPアドレスが入ります。

44~56行目
packメソッドではARPパケットのフォーマットに合わせてデータを並べていきます。
まずはeth_header変数にEthernetHeaderオブジェクトをセットしてイーサネットヘッダーを用意します。

arp変数には、ARPパケットフォーマットにしたがって、制御情報やプロトコル、ARPパケットのタイプを配列にセットします。
次いでarp変数に送信元macアドレス、送信元IPアドレス、宛先macアドレス、宛先IPアドレスをセットします。

51行目のループは、イーサネットフレームのデータ部分の長さは最低でも46バイトなので、arp変数の長さが46バイトになるまで0x00を追加していきます。
最後にeth_header変数をpackメソッドでバイナリにしたデータと、arp変数をpack変数でバイナリにしたデータをくっつけます。

59~64行目
ARPリクエストのパケットを作るクラスです。
APRPacketクラスを継承しています。

initializeメソッドで、tha変数にmacアドレスをセットしています。
ARPリクエストなので、macアドレスには「FF:FF:FF:FF:FF:FF」が入ります。

superでスーパークラスであるARPPacketクラスのinitializeメソッドを呼び出します。
一つ目の引数はARPパケットのタイプなので、ARPリクエストは1を指定します。

66~70行目
ARPリプライのパケットを作るクラスです。
ARPPacketクラスを継承しています。

superでスーパークラスであるARPPacketクラスのinitializeメソッドを呼び出します。
一つ目の引数はARPパケットのタイプなので、ARPリプライは2を指定します。


今回はここまでです。

Tremaを試す ~simple-ruter その7~

今回はrouter-utilsのソースを見ていきます。
前回見たrouter-utils.rbから抜粋しました

  1  require 'ipaddr'
  2  
  3  def get_checksum csum, val
  4    sum = ( ~csum & 0xffff ) + val
  5    while sum > 0xffff
  6      sum = ( sum & 0xffff ) + ( sum >> 16 )
  7    end
  8    ~sum & 0xffff
  9  end
 10  
 11  class IPAddr
 12    def to_a
 13      self.to_s.split( "." ).collect do | each |
 14        each.to_i
 15      end
 16    end
 17  end
 18  
 19  class EthernetHeader
 20    attr_accessor :macda, :macsa, :eth_type
 21  
 22    def initialize macda, macsa, eth_type
 23      @macda = macda
 24      @macsa = macsa
 25      @eth_type = eth_type
 26    end
 27  
 28    def pack
 29      ( @macda.to_a + @macsa.to_a + [ eth_type ] ).pack( "C12n" )
 30    end
 31  end
 32  

1行目
rubyの標準ライブラリのipaddrファイルを読み込み、IPAddrクラスを使えるようにします。

3~9行目
IPv4パケットのチェックサムを計算するメソッドです。
4行目は、引数のcsum変数の値を1の補数にし、0xffffをビット論理積で演算した結果に引数のvalの値を足してsum変数にセットしています。

5行目は、sum変数の値が0xffffを超えている間はループを繰り返します。
ループの中では、sum変数の値をビット論理積で16ビットにした値と、sum変数を右に16ビットシフトした値を足しています。
16ビット右シフトする事で、16ビットからあふれた値をチェックサムに足しています。

8行目でsum変数の値を1の補数にしています。

11~17行目
標準ライブラリのIPAddrクラスに定義を追加しています。
標準ライブラリのIPAddrクラスに定義を追加しています。
ここではto_aメソッドを追加しています。
このメソッドでは、IPAddrオブジェクトの値を文字列に変換し、ドットで分割して、10進数に変換した値を配列にして返します。

19~31行目
このメソッドではイーサネットヘッダーを構成します。
まずアクセサの宣言をして外部からアクセス出来るようにします。

initializeでは、オブジェクトを作る時に渡された引数を変数にセットします。
@macda変数には宛先のmacアドレスが入ります。
@macsa変数には送信元のmacアドレスが入ります。
@eth_typeにはパケットのプロトコルのタイプが入ります。例えばIPv4やARPなどです。

28行目以降で、packメソッドを定義しています。
@macda変数と@macsa変数をeth_type変数が含まれている配列に追加し、packメソッドでバイナリにしています。
Cは8bitの符号なし整数、nはネットワークバイトオーダーです。

短いですが、今日はここまでにします。

2014年1月19日日曜日

Tremaを試す ~simple-ruter その6~

今回はからrouter-utilsを見ていきいます。
このプログラムはルータに必要な機能を使えるようにします。

今回はこのプログラムに定義されているクラスとメソッドについて簡単に説明します。

(router-utils.rb)
  1  require 'ipaddr'
  2  
  3  def get_checksum csum, val
  4    sum = ( ~csum & 0xffff ) + val
  5    while sum > 0xffff
  6      sum = ( sum & 0xffff ) + ( sum >> 16 )
  7    end
  8    ~sum & 0xffff
  9  end
 10  
 11  class IPAddr
 12    def to_a
 13      self.to_s.split( "." ).collect do | each |
 14        each.to_i
 15      end
 16    end
 17  end
 18  
 19  class EthernetHeader
 20    attr_accessor :macda, :macsa, :eth_type
 21  
 22    def initialize macda, macsa, eth_type
 23      @macda = macda
 24      @macsa = macsa
 25      @eth_type = eth_type
 26    end
 27  
 28    def pack
 29      ( @macda.to_a + @macsa.to_a + [ eth_type ] ).pack( "C12n" )
 30    end
 31  end
 32  
 33  class ARPPacket
 34    attr_accessor :type, :tha, :sha, :tpa, :spa
 35  
 36    def initialize type, tha, sha, tpa, spa
 37      @type = type
 38      @tha = tha
 39      @sha = sha
 40      @tpa = tpa
 41      @spa = spa
 42    end
 43  
 44    def pack
 45      eth_header = EthernetHeader.new( @tha, @sha, 0x0806 )
 46  
 47      # arp
 48      arp = [ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, @type ]
 49      arp += @sha.to_a + @spa.to_a + @tha.to_a + @tpa.to_a
 50  
 51      while arp.length < 46 do
 52        arp += [ 0x00 ]
 53      end
 54  
 55      eth_header.pack + arp.pack( "C*" )
 56    end
 57  end
 58  
 59  class ARPRequest < ARPPacket
 60    def initialize sha, tpa, spa
 61      tha = [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]
 62      super( 1, tha, sha, tpa, spa )
 63    end
 64  end
 65  
 66  class ARPReply < ARPPacket
 67    def initialize tha, sha, tpa, spa
 68      super( 2, tha, sha, tpa, spa )
 69    end
 70  end
 71  
 72  class IPPacket
 73    attr_accessor :id, :protocol, :daddr, :saddr, :payload
 74  
 75    def initialize options
 76      @id = options[ :id ]
 77      @protocol = options[ :protocol ]
 78      @daddr = options[ :daddr ]
 79      @saddr = options[ :saddr ]
 80      @payload = options[ :payload ]
 81      @tot_len = 20 + payload.length
 82    end
 83  
 84    def pack
 85      csum = get_checksum( 0, 0x4500 )
 86      header = [ 0x45, 0x00 ] # Version, IHL, ToS
 87  
 88      csum = get_checksum( csum, @tot_len )
 89      header += [ @tot_len >> 8, @tot_len & 0xff ] # len
 90  
 91      csum = get_checksum( csum, @id )
 92      header += [ @id >> 8, @id & 0xff ] # ID
 93  
 94      csum = get_checksum( csum, 0x4000 )
 95      header += [ 0x40, 0x00 ] # Flags, Frag offset
 96  
 97      csum = get_checksum( csum, 0x40 * 0x100 + @protocol )
 98      header += [ 0x40, @protocol ] # ttl, protocol
 99  
100      csum = get_checksum( csum, @saddr.to_i >> 16 )
101      csum = get_checksum( csum, @saddr.to_i & 0xffff )
102      csum = get_checksum( csum, @daddr.to_i >> 16 )
103      csum = get_checksum( csum, @daddr.to_i & 0xffff )
104      header += [ csum >> 8, csum & 0xff ] # checksum
105      header += @saddr.to_a + @daddr.to_a
106  
107      header.pack( "C*" ) + @payload.pack
108    end
109  end
110  
111  class ICMPPacket
112    attr_reader :payload, :length
113  
114    def initialize type, code, payload
115      @type = type
116      @code = code
117      @payload = payload
118      @length = 4 + payload.length
119    end
120  
121    def pack
122      @checksum = get_checksum( 0, @type * 0x100 + @code )
123  
124      words = @payload.pack( "C*" ).unpack( "n*" )
125      words.each do | each |
126        @checksum = get_checksum( @checksum, each )
127      end
128  
129      [ @type, @code, @checksum ].pack( "C2n" ) + @payload.pack( "C*" )
130    end
131  end
132  
133  class ICMPEchoReply < ICMPPacket
134    def initialize payload
135      super( 0x00, 0x00, payload )
136    end
137  end
138  
139  module RouterUtils
140    def create_arp_request_from interface, addr
141      arp = ARPRequest.new( interface.hwaddr, addr, interface.ipaddr )
142      arp.pack
143    end
144  
145    def create_arp_reply_from message, replyaddr
146      arp = ARPReply.new( message.macsa, replyaddr, message.arp_spa, message.arp_tpa )
147      arp.pack
148    end
149  
150    def create_icmpv4_reply entry, interface, message
151      offset = 14 + 20 + 4
152      payload = message.data.unpack( "C*" )[ offset .. message.data.length - 1 ]
153      icmp = ICMPEchoReply.new( payload )
154      ip_packet = IPPacket.new( :id => message.ipv4_id,
155                                :protocol => message.ipv4_protocol,
156                                :ttl => message.ipv4_ttl,
157                                :daddr => message.ipv4_saddr,
158                                :saddr => message.ipv4_daddr,
159                                :payload => icmp )
160      eth_header = EthernetHeader.new( entry.hwaddr, interface.hwaddr, 0x0800 )
161  
162      eth_header.pack + ip_packet.pack
163    end
164  end


get_checksumメソッド
IPv4パケットのチェックサムを計算する時に使用するメソッドです。

IPAddrクラス
1行目のrequireでipaddrを読み込む事で、標準ライブラリIPAddrクラス使えるようになっていますが、そのIPAddrクラスに定義を追加しています。

EthernetHeaderクラス
イーサネットヘッダーを構成するためのクラスです。

ARPPacketクラス
ARPパケットを構成するためのクラスです。

ARPRequestクラス
ARPリクエストのパケットを作るクラスです。
ARPPacketクラスを継承しています。

ARPReplyクラス
ARPリプライのパケットを作るクラスです。
ARPPacketクラスを継承しています。

IPPacketクラス
IPパケットを作るクラスです
ここではICMPのリプライパケットを送るのに使われています。

ICMPPacketクラス
ICMPパケットを構成するためのクラスです。

ICMPEchoReplyクラス
ICMPのリプライパケットを作るクラスです。
ICMPPacketクラスを継承しています。

RouterUtilsモジュール
create_arp_request_fromメソッドとcreate_arp_reply_fromメソッドとcreate_icmpv4_replyメソッドを定義しています。


今回は大まかな説明だけになります。
個人的にはsimple-router全体でこのソースが一番難しかったです。

次回以降、何度かに分けてこのソースを読んでいきます。

rubyのpackメソッドとは何だ!?

以前rubyのpackメソッドがわからないという記事を書きましたが、なんとなくわかった気がします。

packメソッドは「配列の内容をtemplateで指定された文字列にしたがってバイナリとしてパックした文字列を返す」という説明がどうにも理解できませんでした。
今でも怪しいですけど。

まあ、要するに文字や数字をバイナリに変換するメソッドと思っていいのでしょう。
templateは変換対象のデータが文字列なのか、16進数なのか等を示していると思います。

unpackはその逆で、バイナリデータを指定の文字や数字に変換します。
以下のプログラムでどう表示されるか試してみました。

(test_pack.rb)
p [0x41,0x42,0xE3,0x81,0x82].pack("C*")
print([0x41,0x61,0xE3,0x81,0x82].pack("C*"),"\n")
puts [0x41,0x61,0xE3,0x81,0x82].pack("C*")

p [0x41,0x61,0xE3,0x81,0x82].pack("C*").unpack("B*")
p ["Aaあ"].pack("A*").unpack("B*")
p ["0100000101100001111000111000000110000010"].pack("B*").unpack("B*")

puts ["0100000101100001111000111000000110000010"].pack("B*")


初めの3行はp、print、putsでどう表示されるかを確認します。
次の3行はpackメソッドで様々な形式のデータをバイナリに変換し、unpackメソッドでバイト表現にしています。

最後はバイト表現のデータをputsメソッドで表示しています。

実行すると、以下のように表示れました。
$ ruby test_pack.rb
"AB\343\201\202"
Aaあ
Aaあ
["0100000101100001111000111000000110000010"]
["0100000101100001111000111000000110000010"]
["0100000101100001111000111000000110000010"]
Aaあ


初めの3行は表示の確認です。
pだと「あ」が8進数で表示されています。
printとputsは文字で表示されています。

そもそも、なぜ文字で表示されるか?という疑問がありましたが、どうやら「p」や「print」「puts」メソッドが人が見やすいように変換しているようです。
ただし、「p」と「print」「puts」は変換の仕方が違うようで、見え方が違っています。

次にさまざまな形式のデータをバイナリに変換し、そのあとバイト表現にしています。
これは16進数、文字列、2進数と表現は違いますが実はすべて同じデータでした。
なので、2バイト表現した値はすべて同じになります。

最後のputsは2バイトで表現されたデータを表示しただけです。
putsメソッドで変換されて「Aaあ」と表示されました。

こんな具合に、いろいろなデータをバイナリに変換するためのメソッドだと理解しました。

間違っていないといいんですけど。

2014年1月18日土曜日

Tremaを試す ~simple-ruter その5~

今回はrouting-tableを見ていきます。
このソースは名前の通りルーティングテーブルとして動作します。

(routing-table.rb)
 1  require "ipaddr"
 2  
 3  class RoutingTable
 4    ADDR_LEN = 32
 5  
 6    def initialize route = []
 7      @db = Array.new( ADDR_LEN + 1 ) { Hash.new }
 8      route.each do | each |
 9        add( each )
10      end
11    end
12  
13    def add options
14      dest = IPAddr.new( options[ :destination ] )
15      masklen = options[ :masklen ]
16      prefix = dest.mask( masklen )
17      @db[ masklen ][ prefix.to_i ] = IPAddr.new( options[ :nexthop ] )
18    end
19  
20    def delete options
21      dest = IPAddr.new( options[ :destination ] )
22      masklen = options[ :masklen ]
23      prefix = dest.mask( masklen )
24      @db[ masklen ].delete( prefix.to_i )
25    end
26  
27    def lookup dest
28      ( 0..ADDR_LEN ).reverse_each do | masklen |
29        prefix = dest.mask( masklen )
30        entry = @db[ masklen ][ prefix.to_i ]
31        return entry if entry
32      end
33      nil
34    end
35  end

1行目
rubyの標準ライブラリのipaddrファイルを読み込み、IPAddrクラスを使えるようにします。

4行目
定数でプレフィックス長の最大値をセットしています。

6~11行目
initializeメソッドでルーティングテーブルに初期値をセットします。
RoutingTableオブジェクトが作成される時に、引数が渡されていなかったら空の配列で初期化されます。

@dbは、33個の配列を作り、空のハッシュを作成します。
引数のroute変数の値をループして、addメソッドで処理します。

13~18行目
addメソッドは引数のハッシュを@db変数に追加します。
引数にはルーティングの情報が入っています。
dest変数には、ルーティングの宛先IPアドレスをIPAddrクラスを作成してセットします。
masklen変数にはルーティングのプレフィックス長をセットします。
prefix変数には、dest変数にセットしたIPアドレスからmaskメソッドでネットワーク部のアドレスを取得してセットします。
@db変数の配列のmasklen変数の値の要素に、宛先IPアドレスのネットワーク部をハッシュキーにし、引数のoptions変数からnexthopの値を取得してセットします。

20~25行目
deleteメソッドは@adbから引数のハッシュに該当する要素を削除します。
addメソッド同様に、引数にはルーティングの情報が入っています。
dest変数には、ルーティングの宛先IPアドレスからIPAddrクラスを作成してセットします。
masklen変数にはルーティングのプレフィックス長をセットします。
prefix変数には、dest変数にセットしたIPアドレスからmaskメソッドでネットワーク部のアドレスを取得してセットします。
@db変数の配列のmasklen変数の値の要素から、宛先IPアドレスのネットワーク部のハッシュキーと一致するハッシュ要素を削除します。

27~34行目
lookupメソッドは、引数のIPアドレスに合致するルーティングエントリからネクストホップを返します。
reverse_eachでADDR_LEN変数の値から0に減らしながらループを回します。
数字の大きい方から比較することで、ルーティングのロンゲストマッチをしています。

prefix変数には、引数のIPアドレスからmaskメソッドでネットワークアドレスを取得しセットします。
entry変数には、@db変数からprefix変数をハッシュキーにして値を取得しセットします。
31行目は、entry変数に値が取得できていればentryの値であるネクストホップを返します。
31行目のifの結果、returnでメソッドから抜けない場合、メソッドは33行目のnilを返します。

今回は以上になります。