2012年3月23日金曜日

小野秀貴: Open vSwitch によるOpenFlow の利用

◆OpenFlow/Open vSwitchとは

OpenFlowは、1台のOpenFlowコントローラで複数のOpenFlowスイッチを制御する
仕組みです。OpenFlowスイッチは転送機能を提供します。OpenFlowコントロー
ラは経路制御をまとめて行います。OpenFlowスイッチは必要に応じて経路情報
をOpenFlowコントローラに問い合わせる形となります。OpenFlowコントローラ
とOpenFlowスイッチ間はOpenFlowプロトコルで通信が行われます。

Open vSwitchはオープンソースの仮想ソフトウェアスイッチで、XenServer,
KVM, VirtualBoxなどの仮想化プラットフォームでも使用されています。
Open vSwitchは仮想化プラットフォームと組み合わせなくても普通のLinux上で
動作可能です。Linux上で動作させる場合はユーザ空間でのパケット転送処理の
他にカーネルモジュールを利用して高速にパケット転送処理を行うことも可能
です。
またOpen vSwitchは設定によりOpenFlowに対応したOpenFlowスイッチとしての
動作も可能となっています。




◆動向/必要性

OpenFlow 1.0仕様は2009年12月、OpenFlow 1.1仕様は2011年2月にそれぞれリリー
スされました。2011年12月にIPv6のサポートなどが追加されたOpenFlow 1.2仕
様がONF(Open Networking Foundation)で承認されました。1.2はまだ出たばか
りなので現状では1.0/1.1が主流となっています。
OpenFlowは技術的には比較的新しく、またセキュリティ上の懸念なども議論さ
れていたりなどまだ実用段階には至っていません。一方、集中制御できること
から大規模データセンターなどでの利用が期待されています。

このようにOpenFlowは大規模データセンターなどをおもなターゲットとして検
討されているようですが、L2〜L4の情報に基いて細かい制御が可能ということ
で比較的小規模のネットワーク環境で効果的に使える可能性も考えられます。

Open vSwitchではバージョン1.4.0(2012年1月リリース)でOpenFlow 1.0
に加え、OpenFlow 1.1/1.2の一部の機能(IPv6など)に対応しています。



◆Open vSwitch導入

OpenBlockS 600DにOpen vSwitchを導入してみます。

まずはOpenBlockS 600Dでセルフ開発環境を整えます。
今回は、ファームウェア、および開発環境として以下を用いました。
 ftp://ftp.plathome.co.jp/pub/OBS600/debian/files/squeeze/2.6.29-4/uImage.initrd.squeeze
 ftp://ftp.plathome.co.jp/pub/OBS600/debian/files/squeeze/obs600d_squeeze_develop_edition_20110726.tgz
パッケージはaptitude upgradeで2012年2月21日時点での最新版にしました。
 # aptitude update
 # aptitude safe-upgrade
またopenvswitchコンパイルのための準備としてlibssl-dev, pkg-configパッケー
ジを追加しました。
 # aptitude install libssl-dev pkg-config
openvswitchでは、転送処理をカーネル(モジュール)で行う方法とユーザランド
で行う方法の2通りがありコンパイル時に選択します。今回は準備が多少面倒で
すが性能が出るであろう前者のカーネルモジュールを選択することにします。

カーネルモジュールを作成するためにモジュール生成のための環境が必要とな
るので、まずはその準備をします。

開発環境でカーネルのソースはすでに入っていますが、最新のファームと同じ
環境にするために、最新ファーム用のカーネルソースを取得します。
 # cd /usr/src
 # wget ftp://ftp.plathome.co.jp/pub/OBS600/debian/linux/linux-2.6.29-20111128-00.tgz
 # mv linux-2.6.29 linux-2.6.29.old
 # tar xvf linux-2.6.29-20111128-00.tgz
モジュール生成時にはautoconf.h等が必要になるためその準備をします。今回
はモジュールシンボル(Module.symvers)も生成したかったのでmake modulesま
で行いました。make vmlinux modulesは数時間を要します。確認はしていませ
んがmake prepareまで行えばopenvswitchはコンパイル可能かもしれません。
 # cd /usr/src/linux
 # wget -O /usr/src/linux/.config ftp://ftp.plathome.co.jp/pub/OBS600/debian/files/lenny/LATEST/dot.config
 # cd /usr/src/linux/include
 # rm asm
 # ln -s /usr/src/linux/arch/powerpc/include/asm .
 # make oldconfig
 # make prepare
 # make vmlinux modules
さて、これで準備は整ったのでようやくopenvswitchソフトウェアのコンパイル
にうつります。まずは2012年2月21日時点での最新版(1.4.0)のソースを取得し
展開します。
 # wget http://openvswitch.org/releases/openvswitch-1.4.0.tar.gz
 # tar zxvf openvswitch-1.4.0.tar.gz
powerpcではオリジナルのままだと一ヶ所だけ関数未定義でコンパイルを通らな
い箇所があるため以下の修正を加えました。
--- datapath/tunnel.c.orig    2012-01-31 16:08:18.000000000 +0900
+++ datapath/tunnel.c        2012-02-22 17:53:23.000000000 +0900
@@ -38,6 +38,7 @@
 #include <net/ip.h>
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 #include <net/ipv6.h>
+#include <net/ip6_checksum.h>
 #endif
 #include <net/route.h>
 #include <net/xfrm.h>
次にopenvswitchのmakeを行う。
 # cd openvswitch-1.4.0
 # ./configure --with-linux=/lib/modules/`uname -r`/build
 # make
makeが問題なく通ったらmake installを行います。デフォルトでは/usr/local
以下にインストールされます。さらに作成したモジュールをinsmodします。
 # make install
 # insmod datapath/linux/openvswitch_mod.ko
特にエラーメッセージ等が出なければ準備完了となります。




◆構成と設定ファイル初期化

openvswitchの構成は以下の図のようになります。






各種設定は設定用のデータベースで管理されます。データベースへのアクセス
はデータベースアクセス用デーモン(ovsdb-server) を通してアクセスされます。
その他のツールはovsdb-serverと通信して動作を行います。今回はunix domain
socketを用いる設定にしました。
ovs-vswitchdはスイッチのデータパスの設定等を行うメインのデーモンです。
ovs-vsctlはスイッチ関連の各種設定を行うコマンドです。

まずは、初期化を行います。
設定ファイル用のディレクトリを作成し、データベースを新たに作成します。
データベースはovsdb-toolコマンドを用いて生成します。
 # mkdir -p /usr/local/etc/openvswitch
 # ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema
 Feb 22 09:50:54|00001|lockfile|INFO|/usr/local/etc/openvswitch/.conf.db.~lock~: lock file does not exist, creating
次にデータベースを操作するためのサーバを起動します。
データベースサーバへはunix domain socket(db.sock)を通してアクセスします。
 # ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \
                     --remote=db:Open_vSwitch,manager_options \
                     --private-key=db:SSL,private_key \
                     --certificate=db:SSL,certificate \
                     --bootstrap-ca-cert=db:SSL,ca_cert \
                     --pidfile --detach
ovs-vsctlコマンドでデータベースの初期化を行います。
 # ovs-vsctl --no-wait init
open vswitchのメインサーバ ovs-vswitchdを起動します。
 # ovs-vswitchd --pidfile --detach
 Feb 22 09:54:27|00001|reconnect|INFO|unix:/usr/local/var/run/openvswitch/db.sock: connecting...
 Feb 22 09:54:27|00002|reconnect|INFO|unix:/usr/local/var/run/openvswitch/db.sock: connected



◆Open vSwitch基本動作確認

最も単純なeth0, eth1 をブリッジさせる動作を確認します。

まずはブリッジデバイスを作成します。
 # ovs-vsctl add-br br0
 device br0 entered promiscuous mode

 # ifconfig br0
 br0       Link encap:Ethernet  HWaddr fe:b2:9d:a2:84:45 
           BROADCAST MULTICAST  MTU:1500  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)
次に、eth0, eth1 をこのブリッジのポートして追加します。
 # ovs-vsctl add-port br0 eth0
 device eth0 entered promiscuous mode
 # ovs-vsctl add-port br0 eth1
 device eth1 entered promiscuous mode
br0をupするとブリッジ動作を行うようになります。
 # ifconfig br0 up
ovs-vsctlコマンドでブリッジの情報を確認できます。
 # ovs-vsctl show
 a54365a7-c6a5-43b0-b920-bf56e53f37f5
    Bridge "br0"
        Port "eth1"
            Interface "eth1"
        Port "br0"
            Interface "br0"
                type: internal
        Port "eth0"
            Interface "eth0"
なお、注意点としてopenvswitchを導入したマシンでsshなどのIP通信を行うに
は、eth0, eth1ではなくbr0にIPアドレスをふる必要があります。
試しにDHCPでアドレスをふってみます。
 # dhclient br0
 # ifconfig br0
 br0       Link encap:Ethernet  HWaddr 00:0a:85:04:15:5f 
           inet addr:192.168.100.211  Bcast:192.168.100.255  Mask:255.255.255.0
           inet6 addr: fe80::20a:85ff:fe04:155f/64 Scope:Link
           UP BROADCAST RUNNING ALLMULTI MULTICAST  MTU:1500  Metric:1
           RX packets:833632 errors:0 dropped:0 overruns:0 frame:0
           TX packets:52700 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:0
           RX bytes:90350673 (86.1 MiB)  TX bytes:18998763 (18.1 MiB)
動作確認のため3台のOpenBlockS 600D(OBS600D)を用いて以下のネットワークを構成しました。
obs600-3は上記でopenvswitchを導入済のマシンです。





















openvswitchのブリッジが動作をしているかをobs600-1からobs600-2へのpingで
確認します。
 obs600-1# ping 192.168.100.219
 PING 192.168.100.219 (192.168.100.219) 56(84) bytes of data.
 64 bytes from 192.168.100.219: icmp_req=1 ttl=64 time=116 ms
 64 bytes from 192.168.100.219: icmp_req=2 ttl=64 time=0.366 ms
 64 bytes from 192.168.100.219: icmp_req=3 ttl=64 time=0.307 ms
 64 bytes from 192.168.100.219: icmp_req=4 ttl=64 time=0.368 ms
openvswitchでは一方向のデータパスのテーブルをもとにスイッチングを行って
います。データパスの情報を確認するにはovs-dpctlを用います。
 # ovs-dpctl show
 system@br0:
    lookups: hit:2284446 missed:151252 lost:86
    flows: 6
    port 0: br0 (internal)
    port 1: eth0
    port 2: eth1
br0のデータパスを確認してみます。
 # ovs-dpctl dump-flows br0 |grep 192.168.100.123
 in_port(2),eth(src=00:0a:85:04:93:99,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=192.168.100.123,tip=192.168.100.219,op=1,sha=00:0a:85:04:93:99,tha=00:00:00:00:00:00), packets:0, bytes:0, used:never, actions:0,1
 in_port(1),eth(src=00:0a:85:04:15:5e,dst=00:0a:85:04:93:99),eth_type(0x0800),ipv4(src=192.168.100.219,dst=192.168.100.123,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0), packets:4, bytes:392, used:0.145s, actions:2
 in_port(1),eth(src=00:0a:85:04:15:5e,dst=00:0a:85:04:93:99),eth_type(0x0806),arp(sip=192.168.100.219,tip=192.168.100.123,op=2,sha=00:0a:85:04:15:5e,tha=00:0a:85:04:93:99), packets:0, bytes:0, used:never, actions:2
 in_port(2),eth(src=00:0a:85:04:93:99,dst=00:0a:85:04:15:5e),eth_type(0x0800),ipv4(src=192.168.100.123,dst=192.168.100.219,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:4, bytes:392, used:0.145s, actions:1
eth1側からの入力はin_port(2)に対応し、arpおよびICMP echo request
(type=8)のデータパスが確認できます。actions:1は出力ポートが1(=eth0)
となっています。arpはactions:0,1となっていますが、ブロードキャスト
の場合は自分自身用にport 0(=br0) へも出力していることが確認できます。

なお、このデータパスは最大256個となっています。使用されなくなったら数秒
で消えてしまうようです。





◆Open vSwitch性能測定

OpenBlockS 600Dでopenvswitchをカーネルモードで利用した場合の性能を測定してみます。
今回は機材の関係上、obs600-1 <--> obs600-2 間のTCP転送性能を測定します。
測定にはnuttcpを用いました。
まずobs600-2でnuttcpをサーバモードで起動します。
 obs600-2# nuttcp -S
そして、obs600-1ではクライアントモードで起動し、10秒間測定します。
 obs600-1# nuttcp -i1 -T10 192.168.111.219
比較のため、まずはopenvswitchなしの場合で、obs600-1, obs600-2 間を測定
します。ネットワーク図は以下のとおりです。
なお、obs600-1, obs600-2のeth0をmtu 1500にした場合と mtu 9000の場合と2
パターンで測定しました。
なお、今回はカーネルパラメータなどのチューニングは行っていません。










         
結果
mtu 1500
  224.1250 MB /  10.02 sec =  187.6814 Mbps 41 %TX 99 %RX 0 retrans 0.44 msRTT

mtu 9000
  322.0000 MB /  10.02 sec =  269.6913 Mbps 48 %TX 99 %RX 0 retrans 0.46 msRTT
次にopenvswitchを間に挟んで同様の測定を行いました。
ネットワーク図は以下になります。mtu 1500, mtu 9000の2パターンで測定を行
いましたが、この際openvswitchのmtu(br0,eth0,eth1)も同一にしました。

 
結果
mtu 1500
  209.5625 MB /  10.03 sec =  175.2363 Mbps 40 %TX 98 %RX 0 retrans 1.56 msRTT

mtu 9000
  324.0000 MB /  10.01 sec =  271.3858 Mbps 43 %TX 99 %RX 0 retrans 1.53 msRTT
測定結果を比較すると明白に違いはみられません。
今回の測定では末端のOpenBlockS 600Dの性能がボトルネックとなってしまい、上限の正確な
値は確認できていませんが、すくなくとも、
 mtu 1500では 170 Mbps
 mtu 9000では 270 Mbps
程度の性能は出ることが確認できました。



◆OpenFlow風にOpen vSwitchをコントロール

Open vSwitchではovs-vsctl set-controllerコマンドによりOpenFlowコントロー
ラに接続してコントーラからフロー設定できるようになります。
今回はその前段階としてOpenFlowコントローラは使用せずに、ovs-ofctlコマン
ドを用いることで直接Open vSwitch上のフロー情報を書き換えて動作を確認し
ます。

今回の実験は、マルチホーム環境でopenvswitchの配下にあるクライアントから
の上流へのアクセス時に、特定のTCPポート(今回はSMTP=25)の通信だけ異なる
router を経由するように変更します。
このとき、routerやclientの設定は一切変更せずにopenvswitchの操作だけで上
記制御を行います。

今回使用したネットワーク構成は以下のようになります。






















obs600-1ではデフォルトルートは192.168.100.1(router-1)となっていて、
通常の外部への通信はISP 1側を通して行います。
 obs600-1# ip route
 192.168.100.0/24 dev eth1  proto kernel  scope link  src 192.168.100.123
 default via 192.168.100.1 dev eth1
初期状態でのopenvswitchのフローを確認します。
 # ovs-ofctl dump-flows br0
 NXST_FLOW reply (xid=0x4):
  cookie=0x0, duration=40.911s, table=0, n_packets=404, n_bytes=70012, priority=0 actions=NORMAL

actions=NORMALとなっているひとつのエントリが存在します。任意のパケット
はこのエントリにマッチして通常のブリッジ動作を行う。

次に新たなエントリを追加します。
宛先MACアドレスがrouter-1でTCP宛先ポートが25の場合のみ、宛先MACアドレス
を強制的にrouter-2に向かうように変更します。
これを行うにはovs-ofctl add-flowでフローを追加します。
 # ovs-ofctl add-flow br0 'priority=100,in_port=2,dl_dst=00:00:00:00:00:01,tcp,tp_dst=25, actions=mod_dl_dst:00:00:00:00:00:02,output:1'
priority=100を指定することで、条件にマッチする場合このエントリが優先さ
れます。in_port=2(eth1)から入力したパケットはmod_dl_dstにより宛先MACア
ドレスを変更してoutput:1でPort 1(eth0)に出力されます。

再びovs-ofctl dump-flowsでフローを確認します。
 # ovs-ofctl dump-flows br0
 NXST_FLOW reply (xid=0x4):
  cookie=0x0, duration=1171.997s, table=0, n_packets=0, n_bytes=0, priority=100,tcp,in_port=2,dl_dst=00:00:00:00:00:01,tp_dst=25 actions=mod_dl_dst:00:00:00:00:00:02,output:1
  cookie=0x0, duration=1304.627s, table=0, n_packets=2753, n_bytes=347468, priority=0 actions=NORMAL

openvswitch配下のクライアント(obs600-1)で実際に外部SMTPサーバに接続をしてみます。
 obs600-1# telnet smtp.example.org 25
 Connected to smtp.example.org.
 Escape character is '^]'.
 220 smtp.example.org. ESMTP Postfix
このとき外部サーバでアクセスログを確認すると、ISP-2経由でアクセスされて
いることが確認できます。
WWWサーバ(Port 80)へも同様に接続してみます。
 obs600-1# telnet www.example.org 80
 Connected to www.example.org.
 Escape character is '^]'.
外部サーバで同様にアクセスログを確認すると、ISP-1経由のアクセスであるこ
とが確認できます。

これにより当初の目的が達成できました。

このときのOpen vSwitch上でのデータパスも確認してみます。
 # ovs-dpctl dump-flows br0
  - 省略 -
 in_port(2),eth(src=00:0a:85:04:93:99,dst=00:00:00:00:00:01),eth_type(0x0800),ipv4(src=192.168.111.123,dst=175.41.248.246,proto=6,tos=0x10,ttl=64,frag=no),tcp(src=45737,dst=25), packets:3, bytes:206, used:0.645s, actions:set(eth(src=00:0a:85:04:93:99,dst=00:00:00:00:00:02)),1
  - 省略 -

 # ovs-dpctl dump-flows br0
  - 省略 -
 in_port(2),eth(src=00:0a:85:04:93:99,dst=00:00:00:00:00:01),eth_type(0x0800),ipv4(src=192.168.111.123,dst=175.41.248.246,proto=6,tos=0x10,ttl=64,frag=no),tcp(src=35688,dst=80), packets:0, bytes:0, used:never, actions:1
  - 省略 -

dst=80の場合はactions:1に対して、dst=25の場合はMACアドレスが変更
されていることが確認できます。



◆まとめ

今回はOpenFlowに対応した仮想スイッチOpen vSwitchをOpenBlockS 600D上に導入し実際
の動作確認を行いました。転送処理はカーネルモードで行うようにビルドを行
いました。

Open vSwitchをブリッジとして動作するように設定しOpen vSwitch の各種デー
モンやコマンドを使い動作確認を行いました。

OpenBlockS 600D上でのOpen vSwitchの転送性能を測定したところ、最低でも
 mtu 1500では 170 Mbps
 mtu 9000では 270 Mbps
程度はでそうなことが確認できました。

Open vSwitch上でフローを設定することで、特定のフローについての
動作を変更できることを確認しました。実際にはTCP宛先ポート25(=smtp)
のパケットを異なるルータに転送するという例を実現しました。

以上で今回目的としていたことは一通り確認できました。

0 件のコメント:

コメントを投稿