Ryu SDN Frameworkを活用した簡易ルータ機能の作成(4) 〜REST-IF編〜
前回までの簡易ルータは、物理/論理構成を完全に固定してPC端末間での通信を実現しました。OpenFlowプログラミングの概要がだいぶ理解できてきたので、今回からは、もう少し実用性を意識して簡易ルータの作成を進めていきたいと思います。
◆Ryu SDN FrameworkによるREST-IF対応
通常のルータ機器の設定方法としては、まずルータの電源を投入して、シリアルコンソールケーブルで本体と接続して、ルータコンフィグをコマンドラインから作成するような手順になると思います。OpenFlowベースの簡易ルータでも、ある程度、論理構成は、外部から自由に変更できるようにするべきなので、SDNフレームワークとして本命視されているREST-IFによる論理構成の設定機能を実現したいと思います。
もともと、Ryu SDN Frameworkでは、REST-IFを含めて、WSGIベースのWEBフレームワークに対応しているそうです。
RyuブックREST-API章には、REST-IF対応のサンプルコードが掲載されておりますので、参考にさせて頂きました。
RyuによるOpenFlowプログラミング
◆Ryuアプリ「簡易ルータ(コード名;OpenflowRouter)」の実装
実際の機能構成イメージは、概ね、こんな感じです。
前回まで作成した簡易ルータ「SimpleForward」の実装コードは、「SimpleRouter」として、概ね再利用しています。
実装コードは、こちらになります。
Ryuアプリ「簡易ルータ(コード名;OpenflowRouter)」
個人メモ
今回の実装コードを動作させるためには、ofp_handlerのロードが必要となる。ofp_handlerを単独でロードする方法が わからなかったので、コンテキスト「DPSet」を組み込んで対応した。
◆実際に動かしてみた
Openflowルータを動作させるために、論理構成(インタフェース情報)の設定が必要となります。
今回の動作環境は、RESTクライアントとOpenFlowコントローラは、同一サーバ上で動作させました。
今回、REST-IFを介して、RESTクライアントから、論理構成の設定を行いました。
OpenFlowコントローラ動作
OpenFlowコントローラ起動画面上に、Webサーバ履歴として、RESTクライアントのアクセスを確認できます。
$ ryu-manager openflowRouter.py loading app openflowRouter.py loading app ryu.controller.ofp_handler instantiating app None of DPSet creating context dpset creating context wsgi instantiating app openflowRouter.py of OpenflowRouter instantiating app ryu.controller.ofp_handler of OFPHandler (3473) wsgi starting up on http://0.0.0.0:8080/ (3473) accepted ('127.0.0.1', 36174) 127.0.0.1 - - [25/Jan/2014 14:59:30] "POST /openflow/0000000000000001/interface HTTP/1.1" 200 279 0.003215 (3473) accepted ('127.0.0.1', 36175) 127.0.0.1 - - [25/Jan/2014 14:59:36] "POST /openflow/0000000000000001/interface HTTP/1.1" 200 279 0.001029 (3473) accepted ('127.0.0.1', 36176) 127.0.0.1 - - [25/Jan/2014 15:00:09] "GET /openflow/0000000000000001/interface/1 HTTP/1.1" 200 279 0.000429 (3473) accepted ('127.0.0.1', 36177) 127.0.0.1 - - [25/Jan/2014 15:00:22] "GET /openflow/0000000000000001/interface/2 HTTP/1.1" 200 279 0.000311
RESTクライアント動作
(1)ポート1側のインタフェース情報の設定に関わるWEBアクセス内容は、こんな感じです。
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:01", "ipaddress": "192.168.0.10", "port": "1", "opposite_ipaddress": "192.168.0.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool { "id": "0000000000000001", "interface": { "ipaddress": "192.168.0.10", "macaddress": "00:00:00:00:00:01", "opposite_ipaddress": "192.168.0.1", "port": "1" } }
(2)ポート2側のインタフェース情報の設定に関わるWEBアクセス内容は、こんな感じです。
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:02", "ipaddress": "192.168.1.10", "port": "2", "opposite_ipaddress": "192.168.1.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool { "id": "0000000000000001", "interface": { "ipaddress": "192.168.1.10", "macaddress": "00:00:00:00:00:02", "opposite_ipaddress": "192.168.1.1", "port": "2" } }
(3)ポート1側のインタフェース情報の参照に関わるWEBアクセス内容は、こんな感じです。
$ curl -s http://localhost:8080/openflow/0000000000000001/interface/1 | python -mjson.tool { "id": "0000000000000001", "interface": { "ipaddress": "192.168.0.10", "macaddress": "00:00:00:00:00:01", "opposite_ipaddress": "192.168.0.1", "port": "1" } }
(4)ポート2側のインタフェース情報の参照に関わるWEBアクセス内容は、こんな感じです。
$ curl -s http://localhost:8080/openflow/0000000000000001/interface/2 | python -mjson.tool { "id": "0000000000000001", "interface": { "ipaddress": "192.168.1.10", "macaddress": "00:00:00:00:00:02", "opposite_ipaddress": "192.168.1.1", "port": "2" } }
OpenvSwitch動作
正しくFlowエントリが登録できていることも確認できました。
tsubo@OpenFlowSwitch:~$ sudo ovs-ofctl dump-flows br0 --protocols=OpenFlow13 OFPST_FLOW reply (OF1.3) (xid=0x2): cookie=0x0, duration=9.025s, table=0, n_packets=9, n_bytes=882, priority=255,ip,in_port=2,dl_src=52:54:00:0b:d0:48,dl_dst=00:00:00:00:00:02,nw_dst=192.168.0.1 actions=set_field:00:00:00:00:00:01->eth_src,set_field:52:54:00:75:4e:57->eth_dst,output:1 cookie=0x0, duration=9.062s, table=0, n_packets=9, n_bytes=882, priority=255,ip,in_port=1,dl_src=52:54:00:75:4e:57,dl_dst=00:00:00:00:00:01,nw_dst=192.168.1.1 actions=set_field:00:00:00:00:00:02->eth_src,set_field:52:54:00:0b:d0:48->eth_dst,output:2 cookie=0x0, duration=29.097s, table=0, n_packets=27, n_bytes=1638, priority=0 actions=CONTROLLER:65535
PC端末側の動作
OpenFlowコントローラを起動する前は、PC端末からのpingが失敗しました。
OpenFlowコントローラを起動してから、しばらくすると、PC端末からのpingが成功するようになりました。
From 192.168.0.1 icmp_seq=156 Destination Host Unreachable From 192.168.0.1 icmp_seq=157 Destination Host Unreachable From 192.168.0.1 icmp_seq=158 Destination Host Unreachable From 192.168.0.1 icmp_seq=159 Destination Host Unreachable From 192.168.0.1 icmp_seq=160 Destination Host Unreachable 64 bytes from 192.168.1.1: icmp_req=170 ttl=64 time=0.719 ms 64 bytes from 192.168.1.1: icmp_req=171 ttl=64 time=0.486 ms 64 bytes from 192.168.1.1: icmp_req=172 ttl=64 time=0.421 ms 64 bytes from 192.168.1.1: icmp_req=173 ttl=64 time=0.450 ms 64 bytes from 192.168.1.1: icmp_req=174 ttl=64 time=0.541 ms 64 bytes from 192.168.1.1: icmp_req=175 ttl=64 time=0.457 ms 64 bytes from 192.168.1.1: icmp_req=176 ttl=64 time=0.461 ms 64 bytes from 192.168.1.1: icmp_req=177 ttl=64 time=0.387 ms 64 bytes from 192.168.1.1: icmp_req=178 ttl=64 time=0.653 ms 64 bytes from 192.168.1.1: icmp_req=179 ttl=64 time=1.15 ms 64 bytes from 192.168.1.1: icmp_req=180 ttl=64 time=0.733 ms 64 bytes from 192.168.1.1: icmp_req=181 ttl=64 time=0.653 ms 64 bytes from 192.168.1.1: icmp_req=182 ttl=64 time=0.986 ms 64 bytes from 192.168.1.1: icmp_req=183 ttl=64 time=0.436 ms 64 bytes from 192.168.1.1: icmp_req=184 ttl=64 time=0.794 ms 64 bytes from 192.168.1.1: icmp_req=185 ttl=64 time=0.428 ms 64 bytes from 192.168.1.1: icmp_req=186 ttl=64 time=0.846 ms ^C --- 192.168.1.1 ping statistics --- 186 packets transmitted, 50 received, +87 errors, 73% packet loss, time 185036ms rtt min/avg/max/mdev = 0.286/0.622/1.312/0.225 ms, pipe 4 tsubo@Host1:~$
◆終わりに
今回、Ryu SDN Frameworkを活用して、WEBアプリケーション的なREST-IFプログラミングを実施してみました。
Ryuアプリ拡張を通じて、WEBアプリケーション開発が体験できるRyu SDN Frameworkの凄さを実感することができました。
次回からは、監視系の機能を少しずつ育てていきたいと考えております。