SDN開発エンジニアを目指した活動ブログ

〜SDNなオープンソース製品を実際に使って試してみる〜

Ryu SDN Frameworkを活用した簡易ルータ機能の作成(5) 〜トラフィックモニタリング編〜

前回までの簡易ルータでは、REST-API経由で論理構成を設定できる機能を実現しました。ただ、このままでは、簡易ルータが正しく動作しているかを確認する手段がありません。不測な事象が発生した場合に簡易ルータ側が原因なのか、他に原因があるのかを切り分けられる障害解析の機能も実現したいところです。そこで、今回から監視機能の実現を目指したいと思います。
一般には、監視機能といえば、トラフィック監視(モニタリング)と疎通診断(所謂、pingなど)がよく知られていると思います。今回は、トラフィックモニタリング機能に着手してみます。

◆モニタリング機能

OpenFlowスイッチを通過するIP通信トラフィックの監視は、OpenFlow機能を活用して実現します。

(1) ポート監視

  OpenFlow Switch Specication の「Port Statistics」では、ポート監視を目的とするOpenFlowメッセージが規定されています。
  OpenFlowコントローラは、定期的にPort Statisticsを収集することによりポートを通過するトラフィックを監視します。

Port Statistics
struct ofp_port_stats {
    uint32_t port_no;
    uint8_t pad[4]; /* Align to 64-bits. */
    uint64_t rx_packets; /* Number of received packets. */
    uint64_t tx_packets; /* Number of transmitted packets. */
    uint64_t rx_bytes; /* Number of received bytes. */
    uint64_t tx_bytes; /* Number of transmitted bytes. */
    uint64_t rx_dropped; /* Number of packets dropped by RX. */
    uint64_t tx_dropped; /* Number of packets dropped by TX. */
    uint64_t rx_errors; /* Number of receive errors. This is a super-set
                           of more specific receive errors and should be
                           greater than or equal to the sum of all
                           rx_*_err values. */
    uint64_t tx_errors; /* Number of transmit errors. This is a super-set
                           of more specific transmit errors and should be
                           greater than or equal to the sum of all
                           tx_*_err values (none currently defined.) */
    uint64_t rx_frame_err; /* Number of frame alignment errors. */
    uint64_t rx_over_err; /* Number of packets with RX overrun. */
    uint64_t rx_crc_err; /* Number of CRC errors. */
    uint64_t collisions; /* Number of collisions. */
    uint32_t duration_sec; /* Time port has been alive in seconds. */
    uint32_t duration_nsec; /* Time port has been alive in nanoseconds beyond
                              duration_sec. */
};
OFP_ASSERT(sizeof(struct ofp_port_stats) == 112);

(2) Flowエントリ監視

  OpenFlow Switch Specication の「Flow Statistics」では、フロー監視を目的とするOpenFlowメッセージが規定されています。
  OpenFlowコントローラは、定期的にFlow Statisticsを収集することによりFlowエントリを通過するトラフィックを監視します。

Flow Statistics
struct ofp_flow_stats {
    uint16_t length; /* Length of this entry. */
    uint8_t table_id; /* ID of table flow came from. */
    uint8_t pad;
    uint32_t duration_sec; /* Time flow has been alive in seconds. */
    uint32_t duration_nsec; /* Time flow has been alive in nanoseconds beyond
                               duration_sec. */
    uint16_t priority; /* Priority of the entry. */
    uint16_t idle_timeout; /* Number of seconds idle before expiration. */
    uint16_t hard_timeout; /* Number of seconds before expiration. */
    uint16_t flags; /* One of OFPFF_*. */
    uint8_t pad2[4]; /* Align to 64-bits. */
    uint64_t cookie; /* Opaque controller-issued identifier. */
    uint64_t packet_count; /* Number of packets in flow. */
    uint64_t byte_count; /* Number of bytes in flow. */
struct ofp_match match; /* Description of fields. Variable size. */
//struct ofp_instruction instructions[0]; /* Instruction set. */
};
OFP_ASSERT(sizeof(struct ofp_flow_stats) == 56);

◆簡易ルータへのモニタリング機能の組み込み

実際の機能構成イメージは、概ね、こんな感じです。

f:id:ttsubo:20140201175701j:plain
実装コードは、こちらになります。
モニタリング機能(SimpleMonitor)の実装コード
前回のRESTインタフェース(openflowRouter)の実装コード拡張

◆実際に動かしてみた

OpenFlowコントローラが定期的に収集した統計情報をREST-APIを介して参照できるようにしました。

RESTクライアント動作

OpenFlowコントローラが収集した監視統計情報をRESTクライアントから確認してみました。

(1) ポート監視

RESTインタフェースでパラメータを指定し、トラフィック情報の参照結果をわかりやすく確認できるよう、RESTクライアント側もスクリプト化しました。
simpleRouter/rest-client/get_port_stats.sh at master · ttsubo/simpleRouter · GitHub

$ ./get_port_stats.sh 
/openflow/0000000000000001/stats/port
-----------------------------------------------------------
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json; charset=UTF-8
header: Content-Length: 420
header: Date: Sat, 01 Feb 2014 07:14:36 GMT
+++++++++++++++++++++++++++++++
2014/02/01 16:14:36 : PortStats
+++++++++++++++++++++++++++++++
portNo   rxPackets rxBytes  rxErrors txPackets txBytes  txErrors
-------- --------- -------- -------- --------- -------- --------
       1       124    10306        0       105     8968        0
       2       125    10220        0       103     8884        0
fffffffe         6      468        0        44     2044        0
(2) Flowエントリ監視

RESTインタフェースでパラメータを指定し、トラフィック情報の参照結果をわかりやすく確認できるよう、RESTクライアント側もスクリプト化しました。
simpleRouter/rest-client/get_flow_stats.sh at master · ttsubo/simpleRouter · GitHub

$ ./get_flow_stats.sh 
/openflow/0000000000000001/stats/flow
-----------------------------------------------------------
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json; charset=UTF-8
header: Content-Length: 334
header: Date: Sat, 01 Feb 2014 07:14:59 GMT
+++++++++++++++++++++++++++++++
2014/02/01 16:14:59 : FlowStats
+++++++++++++++++++++++++++++++
inPort   ethSrc             ethDst             ipv4Dst         packets  bytes
-------- ------------------ ------------------ --------------- -------- --------
       1  52:54:00:75:4e:57  00:00:00:00:00:01     192.168.1.1       98     9604
       2  52:54:00:0b:d0:48  00:00:00:00:00:02     192.168.0.1       98     9604

OpenFlowコントローラ動作

統計情報の参照に関わるRESTインタフェースについては、OpenFlowコントローラ起動画面上で確認できるようになっています。

$ ryu-manager openflowRouter.py
loading app openflowRouter.py
loading app ryu.controller.ofp_handler
loading app ryu.controller.ofp_handler
creating context wsgi
instantiating app None of SimpleMonitor
creating context monitor
instantiating app openflowRouter.py of OpenflowRouter
instantiating app ryu.controller.ofp_handler of OFPHandler
(2029) wsgi starting up on http://0.0.0.0:8080/
(2029) accepted ('127.0.0.1', 40343)
127.0.0.1 - - [01/Feb/2014 16:12:34] "POST /openflow/0000000000000001/interface HTTP/1.1" 200 279 0.002894
(2029) accepted ('127.0.0.1', 40344)
127.0.0.1 - - [01/Feb/2014 16:12:44] "POST /openflow/0000000000000001/interface HTTP/1.1" 200 279 0.001497
(2029) accepted ('127.0.0.1', 40345)
127.0.0.1 - - [01/Feb/2014 16:12:46] "GET /openflow/0000000000000001/interface/1 HTTP/1.1" 200 279 0.000464
(2029) accepted ('127.0.0.1', 40346)
127.0.0.1 - - [01/Feb/2014 16:12:48] "GET /openflow/0000000000000001/interface/2 HTTP/1.1" 200 279 0.000439
(2029) accepted ('127.0.0.1', 40347)
+++++++++++++++++++++++++++++++
2014/02/01 16:13:00 : PortStats
+++++++++++++++++++++++++++++++
portNo   rxPackets rxBytes  rxErrors txPackets txBytes  txErrors
-------- --------- -------- -------- --------- -------- --------
       1        27     1232        0        26     1226        0
       2        30     1358        0        22     1058        0
fffffffe         6      468        0        44     2044        0
127.0.0.1 - - [01/Feb/2014 16:13:00] "GET /openflow/0000000000000001/stats/port HTTP/1.1" 200 538 0.000908
(2029) accepted ('127.0.0.1', 40348)
+++++++++++++++++++++++++++++++
2014/02/01 16:13:08 : FlowStats
+++++++++++++++++++++++++++++++
inPort   ethSrc             ethDst             ipv4Dst         packets  bytes
-------- ------------------ ------------------ --------------- -------- --------
       1  52:54:00:75:4e:57  00:00:00:00:00:01     192.168.1.1        0        0
       2  52:54:00:0b:d0:48  00:00:00:00:00:02     192.168.0.1        0        0
127.0.0.1 - - [01/Feb/2014 16:13:08] "GET /openflow/0000000000000001/stats/flow HTTP/1.1" 200 450 0.001715
(2029) accepted ('127.0.0.1', 40349)
+++++++++++++++++++++++++++++++
2014/02/01 16:14:36 : PortStats
+++++++++++++++++++++++++++++++
portNo   rxPackets rxBytes  rxErrors txPackets txBytes  txErrors
-------- --------- -------- -------- --------- -------- --------
       1       124    10306        0       105     8968        0
       2       125    10220        0       103     8884        0
fffffffe         6      468        0        44     2044        0
127.0.0.1 - - [01/Feb/2014 16:14:36] "GET /openflow/0000000000000001/stats/port HTTP/1.1" 200 544 0.000812
(2029) accepted ('127.0.0.1', 40350)
+++++++++++++++++++++++++++++++
2014/02/01 16:14:59 : FlowStats
+++++++++++++++++++++++++++++++
inPort   ethSrc             ethDst             ipv4Dst         packets  bytes
-------- ------------------ ------------------ --------------- -------- --------
       1  52:54:00:75:4e:57  00:00:00:00:00:01     192.168.1.1       98     9604
       2  52:54:00:0b:d0:48  00:00:00:00:00:02     192.168.0.1       98     9604
127.0.0.1 - - [01/Feb/2014 16:14:59] "GET /openflow/0000000000000001/stats/flow HTTP/1.1" 200 458 0.000904

◆終わりに

今回も、Ryu SDN Frameworkを活用して、REST-IFプログラミングを実施してみました。
Ryuコントローラ内部で保持している情報を、REST/JSON対応する方法が、だいぶ理解できてきました。
こちらのブログ記事がとても参考になりました。
http://blog.beanz-net.jp/happy_programming/2008/11/python-5.html

次回は、監視機能のもう一方の疎通診断に着手したいと思います。