OpenFlow にてNW機能構築
公開日:
最終更新日:2014/07/25
|
By kumagai19o |
OpenFlow, ryu, SDN
by Hiroki Ide 2013/7/18
仮想化全盛の今日において、足枷となっていたネットワークをプログラマブルに制御できるという事で
「SDN」というキーワードが注目を浴びています。
その「SDN」を具体化する1つの技術要素である OpenFlow の動作検証を行いましたので
簡単にご紹介させて頂きます。
動作の確認は、以下の必要最低限の環境で行いました。
OS:Ubuntu 13.04
スイッチ:Open vSwitch 1.10.0
コントローラー:Ryu 2.1
1.基本動作
OpenFlow スイッチは単体でも動作可能ですが、OpenFlow コントローラーと接続する事で
コントローラー側からの一元管理が可能となります。
コントローラーとの接続はデフォルトでTCP port 6633 で行い
この際にスイッチ、コントローラー間でサポートしているOpenFlow のバージョンや
スイッチのcapability情報などをやり取りします。
OpenFlow のバージョンによっては新たな概念が追加されたり、デフォルトの挙動が
変更になったりしていますが、スイッチとしての基本的な動作は、概ね以下の通りとなります。
まず、スイッチへの 1 パケット着信 が発生し、パケットのヘッダー情報の解析を行います。
スイッチはパケットの扱いをフローテーブルというテーブルで判断する事になりますので
2 フローテーブル参照 し、様々な条件が記述されたフローエントリの中から
解析したヘッダー情報を基に、マッチするものを見つけ、その条件と対になる
3 アクション実行 をします。
フローの条件に指定できる項目は、OpenFlow のバージョンが進むにつれ
多くなってきており、バージョン 1.3 では、40項目となっております。
一方、フローテーブルのエントリにマッチするものがなかった場合は
Packet-In というメッセージをコントローラーに送り、判断を求めます。
コントローラーは、スイッチが該当パケットを処理する為に必要な新たなルールを
2.5 フローエントリ追加 という形で行い、次回からの同一パケットはスイッチ単体で
処理できるようにします。
ちなみに、フローエントリ内での優先されるマッチングルールは、以下の通りとなります。
2.スイッチ機能の確認
最低限のハブとしての機能は2つのフローエントリで実現出来ます。
ひとまず、スイッチをコントローラーとは接続せず、スイッチ単体で動作確認を行います。
以下のコマンドを実行する事でブリッジを構成し、最低限のフローを登録します。
# ovs-vsctl add-br [ブリッジ名]
# ovs-vsctl set bridge [ブリッジ名] protocols=OpenFlow10,OpenFlow12,OpenFlow13
# ovs-vsctl add-port [ブリッジ名] [Server A側ポート]
# ovs-vsctl add-port [ブリッジ名] [Server B側ポート]
root@ubuntu:~# ovs-vsctl add-br br0 root@ubuntu:~# ovs-vsctl set bridge br0 protocols=OpenFlow10,OpenFlow12,OpenFlow13 root@ubuntu:~# ovs-vsctl add-port br0 eth2 root@ubuntu:~# ovs-vsctl add-port br0 eth3
# ovs-ofctl add-flow [ブリッジ名] in_port=[Server A側ポート],actions=output:[Server B側ポート]
# ovs-ofctl add-flow [ブリッジ名] in_port=[Server B側ポート],actions=output:[Server A側ポート]
root@ubuntu:~# ovs-ofctl add-flow br0 in_port=1,actions=output:2 root@ubuntu:~# ovs-ofctl add-flow br0 in_port=2,actions=output:1
上記のようにServer A側ポートに着信したパケットは、Server B側ポートに出力
逆にServer B側ポートに着信したパケットは、Server A側ポートに出力 というフローを登録する事で
Server A、B間で通信が可能となります。
[root@server-a ~]# ping -c 3 192.168.201.101 PING 192.168.201.101 (192.168.201.101) 56(84) bytes of data. 64 bytes from 192.168.201.101: icmp_seq=1 ttl=64 time=0.540 ms 64 bytes from 192.168.201.101: icmp_seq=2 ttl=64 time=0.338 ms 64 bytes from 192.168.201.101: icmp_seq=3 ttl=64 time=0.375 ms --- 192.168.201.101 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 0.338/0.417/0.540/0.090 ms
※ 192.168.201.101 は、Server BのIPアドレス
フローテーブルの状態を確認するコマンドは以下になります。
# ovs-ofctl dump-flows [ブリッジ名]
root@ubuntu:~# ovs-ofctl dump-flows br0 NXST_FLOW reply (xid=0x4): cookie=0x0, duration=311.346s, table=0, n_packets=13, n_bytes=1198, idle_age=31, in_port=1 actions=output:2 cookie=0x0, duration=303.177s, table=0, n_packets=45, n_bytes=4723, idle_age=31, in_port=2 actions=output:1 cookie=0x0, duration=455.866s, table=0, n_packets=6, n_bytes=252, idle_age=123, priority=0 actions=NORMAL
※ 最後の3行目のエントリは、デフォルトのエントリでOpenFlow スイッチでなく
通常のスイッチとして動作させるもの(actions=NORMAL)となります
上記の例では、1つの入力ポートと1つの出力ポートを紐付けていますが
ポートは同時に複数ポートを指定する事も可能です。
任意のポートにトラフィックを流せる という事でまず、思いつく機能は
「ポートミラーリング」や「パッチパネル」の機能です。
ここでは、ポートミラーリングの機能を確認したいと思います。
以下のコマンドを実行する事で、先ほどのブリッジに対する設定は一旦削除し
新たにポートミラーリングの設定を行います。
# ovs-ofctl del-flows [ブリッジ名] in_port=[Server A側ポート]
# ovs-ofctl del-flows [ブリッジ名] in_port=[Server B側ポート]
# ovs-vsctl add-port [ブリッジ名] [PC側ポート]
# ovs-ofctl add-flow ブリッジ名 in_port=[PC側ポート],actions=output:[Server A側ポート],
output:[Server B側ポート]
root@ubuntu:~# ovs-ofctl del-flows br0 in_port=1 root@ubuntu:~# ovs-ofctl del-flows br0 in_port=2 root@ubuntu:~# ovs-vsctl add-port br0 eth1 root@ubuntu:~# ovs-ofctl add-flow br0 in_port=3,actions=output:1,output:2
※ PCからのパケットをServer A、Server B へ、ともに送信する
実際にPCからping を実行し、2台のサーバー側でパケットキャプチャーをしたところ
ちゃんと瓜二つのパケットが2つのポートから出力されている結果となっております。
>ping 192.168.201.101 192.168.201.101 に ping を送信しています 32 バイトのデータ: 192.168.201.101 からの応答: バイト数 =32 時間 =1ms TTL=64
[root@server-a ~]# tcpdump -t -i em4 -c 1 icmp and host 192.168.201.215 IP 192.168.201.215 > 192.168.201.101: ICMP echo request, id 1, seq 410, length 40 1 packet captured 2 packets received by filter 0 packets dropped by kernel
[root@server-b ~]# tcpdump -t -i em4 -c 1 icmp and host 192.168.201.215 IP 192.168.201.215 > 192.168.201.101: ICMP echo request, id 1, seq 410, length 40 1 packet captured 2 packets received by filter 0 packets dropped by kernel
※ 192.168.201.215 は、PCのIPアドレス
ただ、あるポートからのトラフィックをあるポートに送るというだけでは
スイッチの機能は満たせません。
OpenFlow コントローラーであるRyu にはあらかじめアプリケーションが用意されており
スイッチ機能はsimple_switch.py というプログラムで確認する事ができます。
以下のコマンドを実行する事でコントローラーとスイッチを接続し、アプリケーションとして
simple_switch.py を起動します。
# ovs-vsctl set-controller [ブリッジ名] [tcp:コントローラーIPアドレス:6633]
# ryu-manager [simple_switch.py のPath]
root@ubuntu:~# ovs-vsctl set-controller br0 tcp:10.30.10.105:6633 root@ubuntu:/usr/local/ryu/ryu/app# ryu-manager simple_switch.py
以下のコマンドを実行して、Controller のところに「is_connected: true」が表示されれば
コントローラーと接続した事になります。
また、スイッチのフローテーブルはコントローラーと接続される事で初期化されます。
# ovs-vsctl show
# ovs-ofctl dump-flows [ブリッジ名]
root@ubuntu:~# ovs-vsctl show ba89f196-dab2-4c84-90ac-b3e44e186877 Bridge "br0" Controller "tcp:10.30.10.105:6633" is_connected: true Port "eth3" Interface "eth3" Port "eth2" Interface "eth2" Port "eth1" Interface "eth1" Port "br0" Interface "br0" type: internal ovs_version: "1.10.0" root@ubuntu:~# ovs-ofctl dump-flows br0 NXST_FLOW reply (xid=0x4):
simple_switch.py では、Macアドレスの学習機能を備えており、パケットが着信した際
着信ポートを送信元Macアドレス、スイッチID で紐付けて情報を保持します。
初期のスイッチはフローテーブルに何もエントリが無いので、パケットの処理を
コントローラーに問い合わせにいきます。
コントローラー側は、問い合わせの際に発生するPacket-In メッセージのイベントハンドラを
定義しており、着信パケットの宛先Macアドレスが既知のものであれば
学習済みである接続先ポートへ出力、未知のアドレスであれば、フラッディングするように
ルールを作成し、スイッチのフローエントリを追加します。
実際にServer AからServer Bへ通信をして、フローテーブルを確認します。
# ping 192.168.201.101
# ovs-ofctl dump-flows [ブリッジ名]
[root@server-a ~]# ping 192.168.201.101 -c 2 PING 192.168.201.101 (192.168.201.101) 56(84) bytes of data. 64 bytes from 192.168.201.101: icmp_seq=1 ttl=64 time=3.1 ms 64 bytes from 192.168.201.101: icmp_seq=2 ttl=64 time=0.363 ms --- 192.168.201.101 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 0.363/41.768/83.174/41.406 ms
root@ubuntu:~# ovs-ofctl dump-flows br0 NXST_FLOW reply (xid=0x4): cookie=0x0, duration=22.144s, table=0, n_packets=3, n_bytes=256, idle_age=17, in_port=2,dl_dst=44:1e:a1:4e:05:02 actions=output:1 cookie=0x0, duration=22.102s, table=0, n_packets=2, n_bytes=158, idle_age=17, in_port=1,dl_dst=44:1e:a1:46:3d:3a actions=output:2
先ほどとは違い、単純なポートとポートの紐付けではなく、条件にMacアドレスが指定されています。
simple_switch.py を利用する事でMacアドレスを学習し、スイッチに多数のポートが存在しても
目的のポートに出力できるというスイッチの基本機能が確認できました。
3.FW機能の確認
次にFW機能の確認をします。こちらもRyu のアプリケーションが用意されており
rest_firewall.py というプログラムで確認できます。
まず、rest_firewall.py を指定してコントローラーを起動します。
# ryu-manager [rest_firewall.py のPath]
root@ubuntu:/usr/local/ryu/ryu/app# ryu-manager rest_firewall.py
次に、デフォルトではFW機能が無効となっているので、以下のコマンドで有効にします。
# curl -X PUT http://[コントローラーのIPアドレス:8080]/firewall/module/enable/[スイッチID]
root@ubuntu:~# curl -X PUT http://10.30.10.105:8080/firewall/module/enable /00003cd92bfa12fc
※ rest_firewall.py は、WSGIアプリケーションとして動作しています
現時点では、FWのルールは何も無いので、通信は通りません。
[root@server-a ~]# ping 192.168.201.101 -c 2 PING 192.168.201.101 (192.168.201.101) 56(84) bytes of data. --- 192.168.201.101 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 999ms
FWのルール追加は以下のコマンドとなります。
# curl -X POST -d ‘{“項目”:”値”}’ http://[コントローラーのIPアドレス:8080]/firewall/rules/[スイッチID]
FW機能確認として、ICMPの許可をしてみます。
root@ubuntu:~# curl -X POST -d '{"nw_src":"192.168.201.0/24", "nw_proto": "ICMP"}' http://10.30.10.105:8080/firewall/rules/00003cd92bfa12fc
[root@server-a ~]# ping 192.168.201.101 -c 2 PING 192.168.201.101 (192.168.201.101) 56(84) bytes of data. 64 bytes from 192.168.201.101: icmp_seq=1 ttl=64 time=1.08 ms 64 bytes from 192.168.201.101: icmp_seq=2 ttl=64 time=0.367 ms --- 192.168.201.101 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 0.367/0.725/1.083/0.358 ms
次にHTTPの許可をしてみます。
[root@server-a ~]# curl -I http://192.168.201.101 curl: (7) couldn't connect to host
root@ubuntu:~# curl -X POST -d '{"nw_dst":"192.168.201.101", "nw_proto": "TCP", "tp_dst":"80"}' http://10.30.10.105:8080/firewall/rules/00003cd92bfa12fc root@ubuntu:~# curl -X POST -d '{"nw_src":"192.168.201.101", "nw_proto": "TCP", "tp_src":"80"}' http://10.30.10.105:8080/firewall/rules/00003cd92bfa12fc
※ Webサーバー宛の通信とWebサーバーからの戻り通信の2つのルールを設定
[root@server-a ~]# curl -I http://192.168.201.101 HTTP/1.1 200 OK Server: nginx/1.2.9 Date: Wed, 17 Jul 2013 08:22:08 GMT Content-Type: text/html Content-Length: 3700 Last-Modified: Mon, 13 May 2013 20:59:18 GMT Connection: keep-alive Accept-Ranges: bytes
最後にFTPの許可をしてみます。
[root@server-a ~]# ftp -A 192.168.201.101 ftp: connect: Connection timed out ftp>
root@ubuntu:~# curl -X POST -d '{"nw_dst":"192.168.201.101", "nw_proto": "TCP", "tp_dst":"21"}' http://10.30.10.105:8080/firewall/rules/00003cd92bfa12fc root@ubuntu:~# curl -X POST -d '{"nw_src":"192.168.201.101", "nw_proto": "TCP", "tp_src":"21"}' http://10.30.10.105:8080/firewall/rules/00003cd92bfa12fc
※ 通信制御用ポート(port 21)のルールを設定
root@ubuntu:~# curl -X POST -d '{"nw_dst":"192.168.201.101", "nw_proto": "TCP", "tp_dst":"20"}' http://10.30.10.105:8080/firewall/rules/00003cd92bfa12fc root@ubuntu:~# curl -X POST -d '{"nw_src":"192.168.201.101", "nw_proto": "TCP", "tp_src":"20"}' http://10.30.10.105:8080/firewall/rules/00003cd92bfa12fc
※ データ転送用ポート(port 20)のルールを設定
まずは、アクティブモードで確認します。
[root@server-a ~]# ftp -A 192.168.201.101 Connected to 192.168.201.101 (192.168.201.101). 220 (vsFTPd 3.0.2) Name (192.168.201.101:root): test 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> ftp> ftp> ftp> ls 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. -rw-r--r-- 1 0 0 0 Jul 17 08:25 file1 -rw-r--r-- 1 0 0 0 Jul 17 08:26 file2 -rw-r--r-- 1 0 0 0 Jul 17 08:26 file3 -rw-r--r-- 1 0 0 0 Jul 17 08:26 file4 -rw-r--r-- 1 0 0 0 Jul 17 08:26 file5 226 Directory send OK. ftp>
次に、パッシブモードで確認します。
[root@server-a ~]# ftp 192.168.201.101 Connected to 192.168.201.101 (192.168.201.101). 220 (vsFTPd 3.0.2) Name (192.168.201.101:root): test 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> ftp> ftp> ftp> ls 227 Entering Passive Mode (192,168,201,101,93,43). ftp: connect: Connection timed out ftp>
パッシブモードは、ログインは成功するものの、データの転送は出来ません。
当然ですが、パッシブモードのデータ転送用ポートは動的に決定されるので
あらかじめ、登録しておくというような事はできません。
苦肉の策としては、FTP通信の間は、通信を行うホストとホストのwell-knownポート以外を
全て解放しておく(idle_timeout を設定しておく事で一定時間が経過すると
そのフローエントリは削除される)
というものがありますが、良い解決方法とは言えません
(もちろん、フローテーブルでの対応でなく、コントローラー側でPASVコマンドの
返り値を基にポート番号を算出する事は可能です)。
他にも、OpenFlow の苦手な領域としては、FWアプライアンスが提供するような
TCPフラグをチェックして攻撃(例えば、Xmasスキャンなど)を検知する
インテリジェントな機能が挙げられます。
OpenFlow のバージョン1.3 では、フローに指定できる条件(マッチフィールド)の数が
40に増えたものの、それでもTCPフラグまで見る事はできません。
4.LB機能の確認
LBと聞いてイメージされるのは、Webサーバーなどへのトラフィックの振り分け というものが
あるかと思いますが結論から申しますと、このような使い方をフローテーブルでの
処理のみで行うのは難しいと思います。
特に振り分け方法がラウンドロビンだと先ほどのFW機能であったように
TCPフラグを無視した振り分けとなり、TCPセッションの確立などでエラーとなります。
また、ラウンドロビンという振り分け方法を実現させる事自体も
フローテーブルのみでは難しいです。
それはフローテーブルによって決定される処理は1つのみで、同一通信を複数のルールに
順番にマッチさせる事が出来ない為です。
なんとか実現させるには、常にコントローラーに処理の判断を委ねるというプログラムでの対応か
一定時間毎にコントローラーからルールを書き換えてやれば実現はできますが
現実的ではありません。
解決策として、OpenFlow バージョン1.1から追加された新しい概念で
グループテーブルというものがあります。
これは、複数ポートをグルーピングし、1つの同じ処理を行えるものとなり
いくつか設定できる挙動(グループタイプ)の中でselect というものを使用すれば
グルーピングしたポートを順番に使用するというラウンドロビンの動きが実現できます。
ただ、Open vSwitch では、グループテーブルに対応していない様で、今回の環境では
動作の確認を取る事が出来ませんでした。
手軽に確認できるところでは、Open vSwitch と同じく仮想スイッチである
ofsoftswitch13(OpenFlow 1.3 Software Switch)があり、こちらでは
グループテーブルの動作を確認できます。
ラウンドロビンの実現が難しい一方、通信の宛先は同じでもリソース状況によって
通信経路を変更する といった振り分けは得意かと思います。
ここでは、スイッチのフローテーブルに登録済みのある1つのエントリに対する
トラフィック流量によって、通信経路を変更するという動作を確認したいと思います。
トラフィック流量を調べる為にFlow Removed というメッセージを利用します。
Flow Removed は、登録したフローエントリが削除されたタイミングで発生します。
Flow Removed メッセージは、それまでに処理したトラフィック量を
カウンターとして保持している為、トラフィックをモニタリングする事が出来ます。
以下がその処理を行うコードの例となります。
def flow_removed_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
ofp_parser = dp.ofproto_parser
in_port = ofp.OFPP_ANY
for f in msg.match.fields:
if isinstance(f,ofp_parser.MTInPort):
in_port = f.value
break
if in_port == 1 and msg.byte_count/msg.duration_sec * 8 > 50000000:
出力ポート変更処理(出力ポートを変えて、フローエントリ追加)
else:
出力ポートはそのまま(今までと同じフローエントリを追加)
※ eth2 に着信したトラフィックをeth3、eth1 にバランシングする(50Mbps を超えた場合)
実際にトラフィック流量を調整して、試してみると、40Mbps では経路の切り替えは発生せず
[root@server-a ~]# iperf -u -c 192.168.201.101 -b 40M -t 30
root@ubuntu:~# tcpdump -i eth1 port 5001 ^C 0 packets captured 0 packets received by filter 0 packets dropped by kernel
60Mbps では経路の切り替えが発生しました。
[root@server-a ~]# iperf -u -c 192.168.201.101 -b 60M -t 30
root@ubuntu:~# tcpdump -i eth1 port 5001 19:28:25.346857 IP 192.168.201.106.38289 > 192.168.201.101.5001: UDP, length 1470 19:28:25.347062 IP 192.168.201.106.38289 > 192.168.201.101.5001: UDP, length 1470 19:28:25.347223 IP 192.168.201.106.38289 > 192.168.201.101.5001: UDP, length 1470 19:28:25.347465 IP 192.168.201.106.38289 > 192.168.201.101.5001: UDP, length 1470 19:28:25.347613 IP 192.168.201.106.38289 > 192.168.201.101.5001: UDP, length 1470 ^C 15430 packets captured 56114 packets received by filter 40684 packets dropped by kernel
フローエントリは登録する際に、10秒で削除されるように設定しています。
情報が集約されるコントローラー側で判断して、動的に変更する といったこのような使い方は
OpenFlow ならではの使い方だと思います。
よく耳にする「トレンドは集中と分散を繰り返している」というのとは
少しOpenFlow の集中は違うと思います。
演算主体としての集中と分散ではなく、管理面での集中という事だと思います。
ちなみに、10秒毎にフローエントリを消すというやり方に抵抗がありましたので
実際にフローエントリ削除・追加をするタイミング(10秒毎)での通信影響を確認してみました。
[root@server-a ~]# fping -C 100 -B1 -b1400 -t1 -i10 -p1000 192.168.201.101 192.168.201.101 : [0], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [1], 1428 bytes, 0.42 ms (0.42 avg, 0% loss) 192.168.201.101 : [2], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [3], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [4], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [5], 1428 bytes, 0.41 ms (0.42 avg, 0% loss) 192.168.201.101 : [6], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [7], 1428 bytes, 0.49 ms (0.43 avg, 0% loss) 192.168.201.101 : [8], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [9], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [10], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [11], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [12], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [13], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [14], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [15], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [16], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [17], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [18], 1428 bytes, 0.50 ms (0.43 avg, 0% loss) 192.168.201.101 : [19], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [20], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [21], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [22], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [23], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [24], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [25], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [26], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [27], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [28], 1428 bytes, 0.40 ms (0.43 avg, 0% loss) 192.168.201.101 : [29], 1428 bytes, 0.49 ms (0.43 avg, 0% loss) 192.168.201.101 : [30], 1428 bytes, 0.47 ms (0.43 avg, 0% loss) 192.168.201.101 : [31], 1428 bytes, 0.40 ms (0.43 avg, 0% loss) 192.168.201.101 : [32], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [33], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [34], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [35], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [36], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [37], 1428 bytes, 0.40 ms (0.43 avg, 0% loss) 192.168.201.101 : [38], 1428 bytes, 0.41 ms (0.42 avg, 0% loss) 192.168.201.101 : [39], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [40], 1428 bytes, 0.49 ms (0.43 avg, 0% loss) 192.168.201.101 : [41], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [42], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [43], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [44], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [45], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [46], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [47], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [48], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [49], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [50], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [51], 1428 bytes, 0.48 ms (0.43 avg, 0% loss) 192.168.201.101 : [52], 1428 bytes, 0.44 ms (0.43 avg, 0% loss) 192.168.201.101 : [53], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [54], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [55], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [56], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [57], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [58], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [59], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [60], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [61], 1428 bytes, 0.39 ms (0.42 avg, 0% loss) 192.168.201.101 : [62], 1428 bytes, 0.48 ms (0.43 avg, 0% loss) 192.168.201.101 : [63], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [64], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [65], 1428 bytes, 0.48 ms (0.43 avg, 0% loss) 192.168.201.101 : [66], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [67], 1428 bytes, 0.36 ms (0.42 avg, 0% loss) 192.168.201.101 : [68], 1428 bytes, 0.42 ms (0.42 avg, 0% loss) 192.168.201.101 : [69], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [70], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [71], 1428 bytes, 0.41 ms (0.42 avg, 0% loss) 192.168.201.101 : [72], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [73], 1428 bytes, 0.49 ms (0.43 avg, 0% loss) 192.168.201.101 : [74], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [75], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [76], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [77], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [78], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [79], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [80], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [81], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [82], 1428 bytes, 0.41 ms (0.42 avg, 0% loss) 192.168.201.101 : [83], 1428 bytes, 0.43 ms (0.42 avg, 0% loss) 192.168.201.101 : [84], 1428 bytes, 0.53 ms (0.43 avg, 0% loss) 192.168.201.101 : [85], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [86], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [87], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [88], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [89], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [90], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [91], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [92], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [93], 1428 bytes, 0.41 ms (0.43 avg, 0% loss) 192.168.201.101 : [94], 1428 bytes, 0.40 ms (0.42 avg, 0% loss) 192.168.201.101 : [95], 1428 bytes, 0.49 ms (0.43 avg, 0% loss) 192.168.201.101 : [96], 1428 bytes, 0.42 ms (0.43 avg, 0% loss) 192.168.201.101 : [97], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [98], 1428 bytes, 0.43 ms (0.43 avg, 0% loss) 192.168.201.101 : [99], 1428 bytes, 0.39 ms (0.43 avg, 0% loss)
確かに10秒毎に遅延が増加しますが、0.1ms未満の増加である事やパケットロスは
無い事が分かります(インターバルやタイムアウトを厳しい値にしても同様でした)。
蛇足ですが、スイッチがコントローラーと接続して、アプリケーションを実行しても
スイッチ単体の時と比べて、遅延の差は見られませんでした。
もちろん、常時コントローラーに問い合わせにいってはいませんし、アプリケーションにも
依存すると思います。
一方、サーバー側でパケットキャプチャーをしている間は明らかに遅延が増加しています。
5.まとめ
最低限の環境で、スイッチ・FW・LB機能を確認する事ができました。
また、TCPのステートの管理などは行えないので(フローテーブル上では)、使いどころに
注意が必要な事も確認できました。
その他、OpenFlow の動作確認を行っていて注意しなければならないと感じたのは
OpenFlow のバージョンによって挙動が変わる事や、スイッチ側の実装依存がある
(特にプロトコルとして規定されていてもそれがOptional だと実装されていないケースがある)
などがありました。
あと、コントローラー側のプログラムを組む際は、OpenFlow のバージョン毎の違いを
考慮する必要があり、処理の分岐が大変になります。
とはいえ、単にトラフィックの流れを変えるだけでなく、パケットを書き換えて
別のパケットにしたり、周囲の機器との連携で情報を集約し、統計情報を基に
コントロールを行えたりといった柔軟性は、使いどころを見つければ
非常に強力なツールになるのではないかと思いました。
関連記事
-
-
RDOを使用したOpenStack+MidoNet環境のインストール
ビットアイル総合研究所 田波です。 今回は以前紹介したRDOを使用して、OpenStack+M
-
-
OpenFlow スイッチとしてのOpen vSwitch の性能
by Hiroki Ide 2013/8/26Open vSwitch のカーネルモジュールがLin