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

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

Ryu SDN Frameworkを活用した簡易ルータ機能の作成(1) 〜ARP Request/Reply編〜

最近、IT分野へのクラウドコンピューティング技術の浸透が顕在化している状況ですが、ネットワーク分野においてもSDN/OpenFlowの新技術が定着してきていると感じます。ただ、現時点では、OpenFlow技術の活用事例は、市販のOpenFlow製品が中心であり、オープンソースの活用事例は、あまり聞こえてきませんね。(もちろん、研究テーマとしてのオープンソース活用事例は、だいぶ増えていると思いますけど ... )

もともと、OpenFlowの特徴として、「クラウドコンピューティングに関わるNWリソース間のやりとりを、フレキシブル(=プログラマブル)に制御できる技術」として期待されておりました。でも、実際には、従来ネットワーク機器の刷新を目的としたOpenFlow技術適用は、費用対効果の面から現実的ではありません。OpenFlow活用を考える上で、まず、既存ネットワーク機器と「どう相互接続するか!」という技術課題をクリアする上で、OpenFlowで通信プロトコルを制御することが必要不可欠となるわけです。

そこで、オープンソースなOpenFlowコントローラを活用した通信プロトコルのプログラミングが、どの程度、大変なのかを体験してみたいと思います。

◆チャレンジテーマ「オープンソースを活用した簡易ルータ機能を作成してみる」

通信プロトコル基本動作をOpenFlowプログラミングで制御するテーマ素材として、簡易なIPルータ機能にチャレンジしたいと思います。さらに、監視機能などステップByステップで機能補強していきたいと思います。
実現したい通信シーケンスの挙動は、こんな感じです。
f:id:ttsubo:20140111002916j:plain

◆簡易ルータ動作環境

OpenFlowプロトコルとしては、OpenFlow1.3を使ってみました。なお、予算的な制約から、動作環境は、KVMによる仮想VM上で構成しました。

OpenFlowコントローラ

Ryu SDN Framework「osrg/ryu · GitHub」を使いました。
最近では、Ryu-book「RyuによるOpenFlowプログラミング」が公開されたそうです。

OpenFlowスイッチ

当面は、OpenFlowスイッチとしては、オープンソースで一番メジャーなOpenvSwitchを使っていきたいと思います。
なお、OpenFlowルータとしてポート情報に付与されたアドレス情報は、OpenFlowコントローラ側で管理しております。

【HOST1側ポート情報】

 - ポート番号:1
 - MACアドレス:00:00:00:00:00:01
 - IPアドレス:192.168.0.10

【HOST2側ポート情報】

 - ポート番号:2
 - MACアドレス:00:00:00:00:00:02
 - IPアドレス:192.168.1.10

PCのアドレス情報

こちらは、普通のUbuntu搭載のPCです。
HOST1側のIPアドレスMACアドレスは、次のとおりです。

root@Host1:/etc/network# ifconfig
eth0      Link encap:イーサネット  ハードウェアアドレス 52:54:00:75:4e:57  
          inetアドレス:192.168.0.1  ブロードキャスト:192.168.0.255  マスク:255.255.255.0
          inet6アドレス: fe80::5054:ff:fe75:4e57/64 範囲:リンク
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:1573 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:4674 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1000 
          RXバイト:130575 (130.5 KB)  TXバイト:338873 (338.8 KB)

lo        Link encap:ローカルループバック  
          inetアドレス:127.0.0.1  マスク:255.0.0.0
          inet6アドレス: ::1/128 範囲:ホスト
          UP LOOPBACK RUNNING  MTU:65536  メトリック:1
          RXパケット:2762 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:2762 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:0 
          RXバイト:285312 (285.3 KB)  TXバイト:285312 (285.3 KB)

HOST2側のIPアドレスMACアドレスは、次のとおりです。

tsubo@Host2:~$ ifconfig
eth0      Link encap:イーサネット  ハードウェアアドレス 52:54:00:0b:d0:48  
          inetアドレス:192.168.1.1  ブロードキャスト:192.168.1.255  マスク:255.255.255.0
          inet6アドレス: fe80::5054:ff:fe0b:d048/64 範囲:リンク
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:3329 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:1765 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1000 
          RXバイト:211962 (211.9 KB)  TXバイト:136939 (136.9 KB)

lo        Link encap:ローカルループバック  
          inetアドレス:127.0.0.1  マスク:255.0.0.0
          inet6アドレス: ::1/128 範囲:ホスト
          UP LOOPBACK RUNNING  MTU:65536  メトリック:1
          RXパケット:661 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:661 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:0 
          RXバイト:58264 (58.2 KB)  TXバイト:58264 (58.2 KB)

◆実装コード

双方のPC端末間では、各々が属しているサブネットワークが異なるため、自側のPCが対向側PCと相互通信を始めるにあたり、まずは、自側PCに直接繋がったIPルータのMACアドレスを把握する必要があります。そこで、これらのARP Request/Replyの通信シーケンス制御をOpenFlowコントローラ上で制御する仕組みをプログラミングしました。こちらが実際のRyuアプリになります。
simpleRouter/ryu-app/blog/article_01/simpleArp.py at master · ttsubo/simpleRouter · GitHub

今回、作成したARP Request/Replyの通信シーケンスは、こんな感じです。
f:id:ttsubo:20140111002924j:plain


◆実際に動かしてみた

OpenFlowコントローラ上でのRyuアプリを動作させた上で、HOST1からHOST2にICMP通信を行いました。

tsubo@Host1:~$ ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
From 192.168.0.1 icmp_seq=1 Destination Host Unreachable
From 192.168.0.1 icmp_seq=2 Destination Host Unreachable
From 192.168.0.1 icmp_seq=3 Destination Host Unreachable
From 192.168.0.1 icmp_seq=4 Destination Host Unreachable
From 192.168.0.1 icmp_seq=5 Destination Host Unreachable
From 192.168.0.1 icmp_seq=6 Destination Host Unreachable
From 192.168.0.1 icmp_seq=7 Destination Host Unreachable
From 192.168.0.1 icmp_seq=8 Destination Host Unreachable
From 192.168.0.1 icmp_seq=9 Destination Host Unreachable
^C
--- 192.168.1.1 ping statistics ---
11 packets transmitted, 0 received, +9 errors, 100% packet loss, time 9999ms

OpenFlowコントローラ上でのRyuアプリの実行結果を確認してみると、ARP Request/Replyの通信シーケンスが行われておりました。ただ、HOST1からのARP Request受信以降に、HOST2からもARP Request受信している点が気になります。

$ ryu-manager simpleArp.py 
loading app simpleArp.py
loading app ryu.controller.ofp_handler
instantiating app simpleArp.py of SimpleArp
instantiating app ryu.controller.ofp_handler of OFPHandler
receive ARP request 52:54:00:75:4e:57 => ff:ff:ff:ff:ff:ff (port1)
send ARP reply 00:00:00:00:00:01 => 52:54:00:75:4e:57 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive ARP request 52:54:00:0b:d0:48 => ff:ff:ff:ff:ff:ff (port2)
send ARP reply 00:00:00:00:00:02 => 52:54:00:0b:d0:48 (port2)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:0b:d0:48 => 00:00:00:00:00:02 (port2)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)
receive IP 52:54:00:75:4e:57 => 00:00:00:00:00:01 (port1)

実際、OpenFlowコントローラ上でのパケット送受信をwiresharkで確認してみました。
とりあえず、ARP Request/Replyの通信シーケンスをOpenFlowプログラミングで制御できることが確認できました。
f:id:ttsubo:20140111061719j:plain

ひととおり、ARP Request/Replyの通信シーケンスに関わるRyuアプリが正しく動作することが確認できました。

◆Ryuアプリのユニットテスト

ユニットテストとしてRyu SDN Framework内部で疑似的にARP Requestパケットを生成して、RyuアプリでのPacket-in動作を確認してみました。
simpleRouter/ryu-app/blog/article_01/test_SimpleArp.py at master · ttsubo/simpleRouter · GitHub

$ python test_SimpleArp.py 
.DEBUG:SimpleArp:receive ARP request 52:54:00:75:4e:57 => ff:ff:ff:ff:ff:ff (port1)
DEBUG:SimpleArp:send ARP reply 00:00:00:00:00:01 => 52:54:00:75:4e:57 (port1)
.
----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK

◆おわりに

実際、Ryu SDN Frameworkを活用して、ARP Request/Replyの通信シーケンスのOpenFlowプログラミングを実施してみました。
Ryu SDN Framework上では、豊富なPacket-libraryが存在するので、Ryuアプリ側で通信パケットを生成するプログラミングは、そんなに手間を掛けずに実装できることが確認できました。次回は、未着手部分(ICMP転送など)にチャレンジしたいと思います。