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

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

家庭用BuffaloルータのOpenFlow化へのチャレンジ 〜OpenvSwitch構築手順メモ編〜

前回、家庭用Buffaloルータ”BHR-4GRV"をOpenFlow化して、OpenFlow基本動作を確認しました。
家庭用BuffaloルータのOpenFlow化へのチャレンジ 〜OpenFlow1.3動作確認編〜 - SDN開発エンジニアを目指した活動ブログ
SDN/OpenFlowの実験環境で、OpenFlowスイッチ台数を増やすことを想定して、OpenvSwitch構築手順をメモっておきます。

◆構築手順の流れ

(1) Buffaloルータ”BHR-4GRV"のOpenWRT化
(2) OpenWRTのネットワーク設定
(3) OpenvSwitchパッケージのインストール

◆BHR-4GRVのOpenWRT化

本構築手順は、MacBookMac OS X)での作業を想定しております。
注) ここでの構築手順は、個人の構築メモとして掲載しております。
 (Buffaloルータ”BHR-4GRV"が文鎮化してしまうなどの不測な事態が発生しても、あくまでも、自己責任でお願いします。)

1. OpenWRファームウェアの入手

BHR-4GRV専用のOpenWRTファームウェアはありませんが、WZR-HP-G450Hで代用可能です。
Table of Hardware - OpenWrt Wiki

以下のファームウェアをダウンロードし、MacBookのローカルディスクに置いておきます。
openwrt-ar71xx-generic-wzr-hp-g450h-squashfs-tftp.bin

2. debugモードでのログイン

BHR-4GRVの初期状態では、192.168.12.1が設定されているようです。
まずは、WEBブラウザの管理コンソールから管理者パスワード(8文字以内)を設定しておきます。
そして、以下のURLからdebugモードでログインします。

http://192.168.12.1/cgi-bin/cgi?req=frm&frm=py-db/55debug.html
ID:bufpy
Password: otdpopy + 管理者パスワード

成功するとdebugメニュー画面が表示されるので、telnetd を有効にします。
以降、telnetでのアクセスが可能となります。

3. uboot変数の確認と変更

bootloader 「u-boot」用の変数(パラメータ)を確認します。
ipaddr: 192.168.11.1
uboot_ethaddr: 02:AA:BB:CC:DD:22

BHR-4GRVのデフォルト管理IPは192.168.12.1ですが、uboot変数値は192.168.11.1になっている点を留意しておきましょう。

# ubootenv list

tftpでのファームウェアインストールをできるようにするために accept_open_rt_fmt を設定します。

# ubootenv set accept_open_rt_fmt 1

末尾に変数が登録されたことを確認します。

# ubootenv list

4. MacBookのアドレス設定

IPアドレスを以下に設定します。
IPアドレス:192.168.11.2
サブネットマスク:255.255.255.0

以下のコマンドで、MacBook上のarpテーブルにMACアドレスをスタティックで登録しておきます。

$ sudo arp -s 192.168.11.1 02:AA:BB:CC:DD:22

5. TFTPでのOpenWRTファームウェアのインストール

まずは、TFTP動作環境を設定しておきます。

$ tftp
tftp> connect 192.168.11.1
tftp> verbose
tftp> binary
tftp> trace
tftp> rexmt 1
tftp> timeout 60 

つぎに、BHR-4GRVの電源ONして、数秒後に、OpenWRTファームウェアの流し込みを開始します。

tftp> put openwrt-ar71xx-generic-wzr-hp-g450h-squashfs-tftp.bin

以上で、OpenWRT化は完了です。
こちらのURLも参考になると思います。
Buffalo WHR-HP-G300N - OpenWrt Wiki

◆OpenWRTのネットワーク設定

BHR-4GRVのOpenWRT化が完了したら、つぎに、OpenvSwitch動作環境に関わるネットワーク設定を行います。
なお、BHR-4GRVの外観上のRJ45ポートが、Etherポートに対応しているわけではないようです。
すなわち、BHR-4GRV内部のEtherSwitchでeth0ポートを共有する仕組みとなっているみたいです。
よって、今回は、下図のようなVLAN構成となるようにコンフィグ設定を行います。
OpenFlowコントローラとのSecureチャネル接続は、WANポート(青色のポート)を使用することにします。
f:id:ttsubo:20140406165055j:plain

1. OpenWRTへのログイン

BHR-4GRVのLAN側ポートとMacBookをLANケーブル接続して、rootユーザで、OpenWRTにログインしてみます。
(青色のWAN側ポートではありません。)

$ ssh root@192.168.1.1
root@192.168.1.1's password: 


BusyBox v1.19.4 (2014-03-30 18:50:39 JST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 BARRIER BREAKER (Bleeding Edge, r40300)
 -----------------------------------------------------
  * 1/2 oz Galliano         Pour all ingredients into
  * 4 oz cold Coffee        an irish coffee mug filled
  * 1 1/2 oz Dark Rum       with crushed ice. Stir.
  * 2 tsp. Creme de Cacao
 -----------------------------------------------------

2. SSH通過の設定

外部から、WANポートに対してSSHログインが可能なように、firewall設定を行います。

root@OpenWrt:~# vi /etc/config/firewall
-----------------------
config zone
	option name		lan
	list   network		'lan'
	option input		ACCEPT
	option output		ACCEPT
	option forward		ACCEPT

config zone
	option name		wan
	list   network		'wan'
	option input		ACCEPT
	option output		ACCEPT
	option forward		ACCEPT

config forwarding
	option src		lan
	option dest		wan

# Allow SSH
config rule
	option name		Allow-ssh
	option src		wan
	option proto		tcp
	option dest_port	22
	option target		ACCEPT

コンフィグ設定を行ったら、firewallルール有効化のために再起動します。

root@OpenWrt:~# /etc/init.d/firewall restart

3. アドレス設定

WAN側ポートには、以下のIPアドレスを設定します。
IPアドレス:192.168.0.1
サブネットマスク:255.255.255.0

root@OpenWrt:~# vi /etc/config/network
-----------------------
config interface 'loopback'
	option ifname 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'
	
config switch
	option name 'switch0'
	option reset '1'
	option enable_vlan '1'
	
	
config switch_vlan
	option device 'switch0'
	option vlan '1'
	option ports '0t 2'
	
config interface 'lan1'
	option ifname 'eth0.1'
	option proto 'static'

config switch_vlan
	option device 'switch0'
	option vlan '2'
	option ports '0t 3'
	
config interface 'lan2'
	option ifname 'eth0.2'
	option proto 'static'
	
config switch_vlan
	option device 'switch0'
	option vlan '3'
	option ports '0t 4'
	
config interface 'lan3'
	option ifname 'eth0.3'
	option proto 'static'
	
config switch_vlan
	option device 'switch0'
	option vlan '4'
	option ports '0t 5'
	
config interface 'lan4'
	option ifname 'eth0.4'
	option proto 'static'
	
config switch_vlan
	option device 'switch0'
	option vlan '5'
	option ports '0t 1'
	
config interface 'wan1'
	option ifname 'eth0.5'
	option proto 'static'
	option ipaddr '192.168.0.1'
	option netmask '255.255.255.0'

コンフィグ設定を行ったら、ネットワーク有効化のために再起動します。

root@OpenWrt:~# /etc/init.d/network restart

BHR-4GRVのWAN側ポートとMacBookをLANケーブル接続して、OpenWRTに再ログインします。
NIC設定の確認すると、こんな感じで出力されます。

root@OpenWrt:~# ifconfig
eth0      Link encap:Ethernet  HWaddr 96:3C:D2:D7:9E:BB  
          inet6 addr: fe80::943c:d2ff:fed7:9ebb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:42 errors:0 dropped:0 overruns:0 frame:0
          TX packets:54 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:6061 (5.9 KiB)  TX bytes:7534 (7.3 KiB)
          Interrupt:4 

eth0.1    Link encap:Ethernet  HWaddr 96:3C:D2:D7:9E:BB  
          inet6 addr: fe80::943c:d2ff:fed7:9ebb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:408 (408.0 B)

eth0.2    Link encap:Ethernet  HWaddr 96:3C:D2:D7:9E:BB  
          inet6 addr: fe80::943c:d2ff:fed7:9ebb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:408 (408.0 B)

eth0.3    Link encap:Ethernet  HWaddr 96:3C:D2:D7:9E:BB  
          inet6 addr: fe80::943c:d2ff:fed7:9ebb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:478 (478.0 B)

eth0.4    Link encap:Ethernet  HWaddr 96:3C:D2:D7:9E:BB  
          inet6 addr: fe80::943c:d2ff:fed7:9ebb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:408 (408.0 B)

eth0.5    Link encap:Ethernet  HWaddr 96:3C:D2:D7:9E:BB  
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
          inet6 addr: fe80::943c:d2ff:fed7:9ebb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:42 errors:0 dropped:0 overruns:0 frame:0
          TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:5305 (5.1 KiB)  TX bytes:5184 (5.0 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:432 errors:0 dropped:0 overruns:0 frame:0
          TX packets:432 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:29376 (28.6 KiB)  TX bytes:29376 (28.6 KiB)

◆OpenvSwitchインストール

OpenWRTのネットワーク設定が終わったら、OpenvSwitchパッケージをインストールします。

1. OpenvSwitchパッケージの入手

まずは、MacBook上に、OpenvSwitchパッケージをダウンロードしておきます。
Releases · ttsubo/openvswitch · GitHub

そして、OpenWRT上に、OpenvSwitchパッケージをアップロードします。

scp kmod-crypto-crc32c_3.10.34-1_ar71xx.ipk root@192.168.0.1:/root
scp kmod-crypto-hash_3.10.34-1_ar71xx.ipk root@192.168.0.1:/root
scp kmod-gre_3.10.34-1_ar71xx.ipk root@192.168.0.1:/root
scp kmod-iptunnel_3.10.34-1_ar71xx.ipk root@192.168.0.1:/root
scp kmod-lib-crc32c_3.10.34-1_ar71xx.ipk root@192.168.0.1:/root
scp kmod-llc_3.10.34-1_ar71xx.ipk root@192.168.0.1:/root
scp kmod-openvswitch_3.10.34.2.1.0-1_ar71xx.ipk root@192.168.0.1:/root
scp kmod-stp_3.10.34-1_ar71xx.ipk root@192.168.0.1:/root
scp openvswitch-common_2.1.0-1_ar71xx.ipk root@192.168.0.1:/root
scp openvswitch-switch_2.1.0-1_ar71xx.ipk root@192.168.0.1:/root
scp libopenssl_1.0.1f-1_ar71xx.ipk root@192.168.0.1:/root
scp libpcap_1.5.3-1_ar71xx.ipk root@192.168.0.1:/root
scp librt_0.9.33.2-1_ar71xx.ipk root@192.168.0.1:/root
scp libpthread_0.9.33.2-1_ar71xx.ipk root@192.168.0.1:/root
scp zlib_1.2.8-1_ar71xx.ipk root@192.168.0.1:/root

そして、OpenWRT上で、パッケージインストールを行います。

$ ssh root@192.168.0.1
root@192.168.0.1's password: 


BusyBox v1.19.4 (2014-03-30 18:50:39 JST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 BARRIER BREAKER (Bleeding Edge, r40300)
 -----------------------------------------------------
  * 1/2 oz Galliano         Pour all ingredients into
  * 4 oz cold Coffee        an irish coffee mug filled
  * 1 1/2 oz Dark Rum       with crushed ice. Stir.
  * 2 tsp. Creme de Cacao
 -----------------------------------------------------


root@OpenWrt:~# ls -l
-rw-r--r--    1 root     root          1704 Mar 30 15:13 kmod-crypto-crc32c_3.10.34-1_ar71xx.ipk
-rw-r--r--    1 root     root          6620 Mar 30 15:13 kmod-crypto-hash_3.10.34-1_ar71xx.ipk
-rw-r--r--    1 root     root          8155 Mar 30 15:13 kmod-gre_3.10.34-1_ar71xx.ipk
-rw-r--r--    1 root     root          8220 Mar 30 15:14 kmod-iptunnel_3.10.34-1_ar71xx.ipk
-rw-r--r--    1 root     root          1591 Mar 30 15:14 kmod-lib-crc32c_3.10.34-1_ar71xx.ipk
-rw-r--r--    1 root     root           684 Mar 30 15:14 kmod-llc_3.10.34-1_ar71xx.ipk
-rw-r--r--    1 root     root         39049 Mar 30 15:14 kmod-openvswitch_3.10.34.2.1.0-1_ar71xx.ipk
-rw-r--r--    1 root     root           695 Mar 30 15:14 kmod-stp_3.10.34-1_ar71xx.ipk
-rw-r--r--    1 root     root        674063 Mar 30 15:15 libopenssl_1.0.1f-1_ar71xx.ipk
-rw-r--r--    1 root     root         88627 Mar 30 15:16 libpcap_1.5.3-1_ar71xx.ipk
-rw-r--r--    1 root     root         31833 Mar 30 15:16 libpthread_0.9.33.2-1_ar71xx.ipk
-rw-r--r--    1 root     root          5592 Mar 30 15:16 librt_0.9.33.2-1_ar71xx.ipk
-rw-r--r--    1 root     root        523230 Mar 30 15:15 openvswitch-common_2.1.0-1_ar71xx.ipk
-rw-r--r--    1 root     root       1421554 Mar 30 15:15 openvswitch-switch_2.1.0-1_ar71xx.ipk
-rw-r--r--    1 root     root         40544 Mar 30 15:16 zlib_1.2.8-1_ar71xx.ipk


root@OpenWrt:~# opkg install kmod-llc_3.10.34-1_ar71xx.ipk
Installing kmod-llc (3.10.34-1) to root...
Configuring kmod-llc.

root@OpenWrt:~# opkg install kmod-stp_3.10.34-1_ar71xx.ipk
Installing kmod-stp (3.10.34-1) to root...
Configuring kmod-stp.

root@OpenWrt:~# opkg install kmod-iptunnel_3.10.34-1_ar71xx.ipk
Installing kmod-iptunnel (3.10.34-1) to root...
Configuring kmod-iptunnel.

root@OpenWrt:~# opkg install kmod-gre_3.10.34-1_ar71xx.ipk
Installing kmod-gre (3.10.34-1) to root...
Configuring kmod-gre.

root@OpenWrt:~# opkg install kmod-crypto-hash_3.10.34-1_ar71xx.ipk
Installing kmod-crypto-hash (3.10.34-1) to root...
Configuring kmod-crypto-hash.

root@OpenWrt:~# opkg install kmod-crypto-crc32c_3.10.34-1_ar71xx.ipk
Installing kmod-crypto-crc32c (3.10.34-1) to root...
Configuring kmod-crypto-crc32c.

root@OpenWrt:~# opkg install kmod-lib-crc32c_3.10.34-1_ar71xx.ipk
Installing kmod-lib-crc32c (3.10.34-1) to root...
Configuring kmod-lib-crc32c.

root@OpenWrt:~# modprobe libcrc32c

root@OpenWrt:~# opkg install kmod-openvswitch_3.10.34.2.1.0-1_ar71xx.ipk
Installing kmod-openvswitch (3.10.34+2.1.0-1) to root...
Configuring kmod-openvswitch.

root@OpenWrt:~# lsmod|grep open
gre                     1874  2 openvswitch
libcrc32c                599  1 openvswitch
openvswitch            60332  0

root@OpenWrt:~# opkg install zlib_1.2.8-1_ar71xx.ipk
Installing zlib (1.2.8-1) to root...
Configuring zlib.

root@OpenWrt:~# opkg install libopenssl_1.0.1f-1_ar71xx.ipk
Installing libopenssl (1.0.1f-1) to root...
Configuring libopenssl.

root@OpenWrt:~# opkg install libpcap_1.5.3-1_ar71xx.ipk
Installing libpcap (1.5.3-1) to root...
Configuring libpcap.

root@OpenWrt:~# opkg install libpthread_0.9.33.2-1_ar71xx.ipk 
Installing libpthread (0.9.33.2-1) to root...
Configuring libpthread.

root@OpenWrt:~# opkg install librt_0.9.33.2-1_ar71xx.ipk
Installing librt (0.9.33.2-1) to root...
Configuring librt.

root@OpenWrt:~# opkg install openvswitch-common_2.1.0-1_ar71xx.ipk
Installing openvswitch-common (2.1.0-1) to root...
Configuring openvswitch-common.

root@OpenWrt:~# opkg install openvswitch-switch_2.1.0-1_ar71xx.ipk
Installing openvswitch-switch (2.1.0-1) to root...
Configuring openvswitch-switch.

root@OpenWrt:~# /etc/init.d/openvswitch start
2014-03-30T15:26:01Z|00001|reconnect|INFO|unix:/var/run/db.sock: connecting...
2014-03-30T15:26:01Z|00002|reconnect|INFO|unix:/var/run/db.sock: connected

以上で、OpenvSwitchインストールは完了です。
いちおう、OpenvSwitchのバージョンを確認しておきます。

root@OpenWrt:~# ovs-vsctl -V
ovs-vsctl (Open vSwitch) 2.1.0
Compiled Mar 30 2014 17:50:11

2. OpenvSwitch設定

ここからは、一般的なOpenvSwitch設定作業ですね。

root@OpenWrt:~# ovs-vsctl add-br br0
root@OpenWrt:~# ovs-vsctl add-port br0 eth0.1
root@OpenWrt:~# ovs-vsctl add-port br0 eth0.2
root@OpenWrt:~# ovs-vsctl set-controller br0 tcp:192.168.0.100:6633
root@OpenWrt:~# ovs-vsctl set bridge br0 other-config:datapath-id=0000000000000001
root@OpenWrt:~# ovs-vsctl set bridge br0 protocols=OpenFlow13

設定結果を確認しておきます。

root@OpenWrt:~# ovs-vsctl show
6d27491f-e242-4a02-acf3-cd0c28d16de2
    Bridge "br0"
        Controller "tcp:192.168.0.100:6633"
        Port "eth0.2"
            Interface "eth0.2"
        Port "eth0.1"
            Interface "eth0.1"
        Port "br0"
            Interface "br0"
                type: internal

root@OpenWrt:~# ovs-ofctl dump-ports-desc br0 --protocols=OpenFlow13
OFPST_PORT_DESC reply (OF1.3) (xid=0x2):
 1(eth0.1): addr:96:3c:d2:d7:9e:bb
     config:     0
     state:      0
     current:    1GB-FD AUTO_NEG
     advertised: 1GB-FD
     supported:  1GB-FD
     speed: 1000 Mbps now, 1000 Mbps max
 2(eth0.2): addr:96:3c:d2:d7:9e:bb
     config:     0
     state:      0
     current:    1GB-FD AUTO_NEG
     advertised: 1GB-FD
     supported:  1GB-FD
     speed: 1000 Mbps now, 1000 Mbps max
 LOCAL(br0): addr:fa:e4:ce:22:a1:9b
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max

以上で、OpenWRT上でのOpenvSwitch環境が構築できました。

◆留意事項

OpenWRT上でのネットワーク設定では、各ポートをeth0上で共有する形態になっています。
従って、各ポートに割り当てられたMACアドレスがみんな同じ値になってしまっております。
今回のSDN/OpenFlow実験環境で使用する際には、MACアドレス制御もOpenFlowで管理が可能となるので、特に気にする必要がないと思います。しかし、オーバレイNWネットワークとして、本装置を活用する場合には、ネットワークトポロジ上でのMACテーブル管理で、ループ等の弊害が発生するかもしれません。

◆終わりに

前回を通じて、"OpenWRT+OpenvSwitch"でOpenFlow1.3スイッチ環境を構築してみました。
構築手順も、OpenWRTファーム構築さえ慣れてしまえば、OpenFlowスイッチ台数の拡張時にも、それほど苦労なく対応できると思います。
さらに、OpenFlowスイッチが6,000円程度で入手可能というのは、いちばんの魅力かもしれません。

家庭用BuffaloルータのOpenFlow化へのチャレンジ 〜OpenFlow1.3動作確認編〜

これまでも、Linuxボックス"DNA940"を活用してSDN/OpenFlow環境を構築してきました。ただし、汎用性の乏しいLinuxボックス構成だったので、SDN/OpenFlow環境としてOpenFlowスイッチ台数を増やすことが困難でした。今回は、もっと簡易にOpenFlowスイッチ台数を増やすことができる環境構築を目指します。

◆OpenWRT版OpenvSwitch構築

昨年あたりから、OpenWRT版のOpenvSwitchがGitHUBに公開されているようです。ただし、OpenvSwitchバージョンが"1.9.0"と古いままになっているようです。
そこで、Buffaloルータ"BHR-4GRV"のOpenWRT化とOpenvSwitch 2.1.0版パッケージを整備しました。
Releases · ttsubo/openvswitch · GitHub

こちらが、実際に、OpenFlow化した家庭用Buffaloルータ”BHR-4GRV"です。OpenvSwitchの特徴としては、ユーザランドではなく、カーネルモジュールとして、datapathが動作する点ですね。
f:id:ttsubo:20140405171104j:plain

ちなみに、家庭用Buffaloルータ"WHR-G301N"でも、チャレンジしてみましたが、OpenvSwitch保存先のルータ本体ディスク容量不足がネックとなり、インストールできませんでした。

◆自宅ネットワークへのOpenFlow導入

基本的には、以前のブログ記事と同等の構成になります。
OpenFlow簡易ルータの実践活用(3) 〜LinuxボックスでOpenFlowスイッチ構築編〜 - SDN開発エンジニアを目指した活動ブログ

f:id:ttsubo:20140405171354j:plain

◆実際、使ってみて ...

Buffaloルータ"BHR-4GRV"で構築したOpenFlowスイッチを介して実際にインターネットにアクセスしてみました。
いまのところは、安定して動作しているようです。一般的なインターネットの使用感について、とくに、ストレスが感じることなく、大変満足できるものです。ustreamの閲覧も、すこぶる順調でした。

f:id:ttsubo:20140405171737j:plain

あと、参考までに、スピード計測の結果は、こんな感じでした。
f:id:ttsubo:20140405171854j:plain

◆OpenvSwitch上でのフローエントリ出力

ちなみに、OpenFlowのフローエントリのダンプは、こんな感じです。

root@OpenWrt:~# ovs-ofctl dump-flows br0 --protocols=OpenFlow13
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x0, duration=827.722s, table=0, n_packets=567, n_bytes=45795, priority=255,ip,in_port=2,dl_src=7c:c3:a1:87:8f:65,dl_dst=00:00:00:00:00:02,nw_dst=192.168.100.1 actions=set_field:00:00:00:00:00:01->eth_src,set_field:10:66:82:93:c4:f0->eth_dst,output:1,dec_ttl
 cookie=0x0, duration=827.722s, table=0, n_packets=234295, n_bytes=300428408, priority=255,ip,in_port=1,dl_src=10:66:82:93:c4:f0,dl_dst=00:00:00:00:00:01,nw_dst=192.168.101.1 actions=set_field:00:00:00:00:00:02->eth_src,set_field:7c:c3:a1:87:8f:65->eth_dst,output:2,dec_ttl
 cookie=0x0, duration=814.607s, table=0, n_packets=139100, n_bytes=12649245, priority=1,ip actions=set_field:00:00:00:00:00:01->eth_src,set_field:10:66:82:93:c4:f0->eth_dst,output:1,dec_ttl
 cookie=0x0, duration=844.926s, table=0, n_packets=853, n_bytes=133044, priority=0 actions=CONTROLLER:65535
 cookie=0x0, duration=837.807s, table=0, n_packets=12, n_bytes=924, priority=16,ip,nw_dst=192.168.100.100 actions=CONTROLLER:65535
 cookie=0x0, duration=827.794s, table=0, n_packets=92, n_bytes=11862, priority=16,ip,nw_dst=192.168.101.100 actions=CONTROLLER:65535

◆終わりに

SDN/OpenFlowを中心としたネットワーク仮想化技術は、様々な最新技術によって構成されるものです。これらを習得するためには、実際に試してみるのが一番手っ取り早いです。ただ、これまでは、家計への負担にならない程度の出費でSDN/OpenFlow環境を構築することは困難でした。今回の"OpenWRT+OpenvSwitch"の組み合わせで、手軽にリアルな環境を入手できることが判明できました。次回は、OpenFlowスイッチ台数の拡張を見据えて、"OpenWRT+OpenvSwitch"の構築手順をメモしておきたいと思います。

ネットワーク仮想化技術の実践活用(2) 〜OpenvSwitch管理プロトコル(OVSDB)編〜

ネットワーク仮想化環境の特徴は、VxLAN等のオーバレイ技術を活用して多拠点間をトンネルで接続するモデルだと思います。
ただ、拠点数(n)に対して、拠点間をフルメッシュn*(n − 1)本のトンネルを構築する必要があります。
前回のブログ記事では、2拠点をVxLANトンネルで構築する程度のため、OpenvSwitchのコマンドラインで構築しましたが、拠点数が多くなると、やっぱり、集中管理的に拠点間トンネル設定を行いたくなりますよね。ということで、今回は、OpenvSwitch管理プロトコル「OVSDB」に着目したいと思います。

◆OVSDBとは ?

OVSDBとは、OpenvSwitchのデータモデルを管理する手法です。
RDBMSにおけるSQL的な役割で、DDL(Data Definition Language:データ定義言語)の側面と、DML(Data Manipulation Language:データ操作言語)の側面を併せ持っているものです。
ざっと、OpenvSwitchのテーブル構成は、以下のようになってます。
Open_vSwitch --> Open vSwitch configuration.
Bridge --> Bridge configuration.
Port --> Port configuration.
Interface --> One physical network device in a Port. Flow_Table OpenFlow table configuration
QoS --> Quality of Service configuration Queue QoS output queue.
Mirror --> Port mirroring.
Controller --> OpenFlow controller configuration. Manager OVSDB management connection. NetFlow NetFlow configuration.
SSL --> SSL configuration.
sFlow --> sFlow configuration.
IPFIX --> IPFIX configuration. Flow_Sample_Collector_Set
Flow_Sample_Collector_Set --> configuration.

また、OpenvSwitchデータベースのスキーマ定義などの詳細は、以下のリンクが参考になります。
http://openvswitch.org/ovs-vswitchd.conf.db.5.pdf

Open_vSwitchテーブル構造

OpenvSwitchデータベースを構成する多数のテーブルのうち、「Open_vSwitch」テーブル構造を、確認してみます。

tsubo@OFS1:~$ sudo ovs-vsctl list Open_vSwitch
_uuid               : 82524775-43a3-4838-90ae-61e2cbd10820
bridges             : [55d71da8-cd33-4117-b7a3-de8a5b4222a3]
cur_cfg             : 12
db_version          : "7.3.0"
external_ids        : {system-id="a7812d37-5389-4ae6-b003-42a66a6e05fe"}
manager_options     : [0cc00f03-5c47-404a-9a31-66e5105f48d2]
next_cfg            : 12
other_config        : {}
ovs_version         : "2.0.1"
ssl                 : []
statistics          : {}
system_type         : Ubuntu
system_version      : "12.04-precise"

ovs-vsctlコマンドと、いろいろと引数を指定してあげれば、様々なテーブル情報を参照できるようです。

◆外部からOpenvSwitchデータベースにアクセスするには ?

1. OpenvSwitch管理プロトコル

VMware社により、IETFのInformational RFC化されているようですが、OpenvSwitch専用だと思います。
他の類似技術として、OpenFlowスイッチ管理プロトコル「OF-Config」があります。

OVSDB管理手法の特徴としては、JSON-RPCをベースとしたデータモデリングを前提としている点です。
データ検索クエリのデータフォーマットとしては、"method", "params", "id"という構造となるようです。

RFC 7047 :The Open vSwitch Database Management Protocol

4.1.5. Monitor

   The "monitor" request enables a client to replicate tables or subsets
   of tables within an OVSDB database by requesting notifications of
   changes to those tables and by receiving the complete initial state
   of a table or a subset of a table.  The request object has the
   following members:

   o  "method": "monitor"

   o  "params": [<db-name>, <json-value>, <monitor-requests>]

   o  "id": <nonnull-json-value>

   The <json-value> parameter is used to match subsequent update
   notifications (see below) to this request.  The <monitor-requests>
   object maps the name of the table to be monitored to an array of
   <monitor-request> objects.

   Each <monitor-request> is an object with the following members:

       "columns": [<column>*]            optional
       "select": <monitor-select>        optional

   The columns, if present, define the columns within the table to be
   monitored.

<snip>

2. 外部機器からデータ操作するための事前準備

外部機器から、OpenvSwitchデータベースにアクセスするために、事前に、以下のコマンドを実施しておきます。

$ sudo ovs-vsctl set-manager ptcp:6632

ポート番号は、今回は、とりあえず、"6632"としました。

3. 実際に「Open_vSwitchテーブル」を参照してみる

それでは、外部装置から、以下のPythonプログラムで「Open_vSwitchテーブル」を参照してみます。

#-*- coding: utf-8 -*-

import socket
import json

OVSDB_IP = '192.168.0.1'
OVSDB_PORT = 6632

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((OVSDB_IP, OVSDB_PORT))

monitor_query = \
{"method":"monitor",
"params":["Open_vSwitch","null",{"Open_vSwitch":{"columns":["bridges","cur_cfg","db_version","external_ids","manager_options","next_cfg","other_config","ovs_version","ssl","statistics","system_type","system_version"]}}],
"id":0}

print "----------------------------------"
print "json rpc request"
print "----------------------------------"
print json.dumps(monitor_query, sort_keys=False, indent=1)
s.send(json.dumps(monitor_query))

print "----------------------------------"
print "json rpc reply"
print "----------------------------------"
response = s.recv(8192)
result = json.loads(response)
print json.dumps(result, sort_keys=False, indent=1)

Pythonプログラムの実行結果は、こんな感じです。
さきほど、"sudo ovs-vsctl list Open_vSwitch"の実行結果と対比してみると、OVSDBの挙動がイメージしやすいかもしれません。

$ python ovsdb_show.py 
----------------------------------
json rpc request
----------------------------------
{
 "params": [
  "Open_vSwitch", 
  "null", 
  {
   "Open_vSwitch": {
    "columns": [
     "bridges", 
     "cur_cfg", 
     "db_version", 
     "external_ids", 
     "manager_options", 
     "next_cfg", 
     "other_config", 
     "ovs_version", 
     "ssl", 
     "statistics", 
     "system_type", 
     "system_version"
    ]
   }
  }
 ], 
 "method": "monitor", 
 "id": 0
}
----------------------------------
json rpc reply
----------------------------------
{
 "error": null, 
 "id": 0, 
 "result": {
  "Open_vSwitch": {
   "82524775-43a3-4838-90ae-61e2cbd10820": {
    "new": {
     "bridges": [
      "uuid", 
      "55d71da8-cd33-4117-b7a3-de8a5b4222a3"
     ], 
     "statistics": [
      "map", 
      []
     ], 
     "db_version": "7.3.0", 
     "next_cfg": 12, 
     "ovs_version": "2.0.1", 
     "other_config": [
      "map", 
      []
     ], 
     "ssl": [
      "set", 
      []
     ], 
     "system_type": "Ubuntu", 
     "external_ids": [
      "map", 
      [
       [
        "system-id", 
        "a7812d37-5389-4ae6-b003-42a66a6e05fe"
       ]
      ]
     ], 
     "system_version": "12.04-precise", 
     "cur_cfg": 12, 
     "manager_options": [
      "uuid", 
      "0cc00f03-5c47-404a-9a31-66e5105f48d2"
     ]
    }
   }
  }
 }
}

◆集中管理的にVxLANトンネルを設定してみる

OpenvSwitch管理プロトコル概要が理解できたところで、それでは、もう少し実用的なOVSDB活用にチャレンジしてみます。

1. 検証構成

基本的な検証構成は、前回のブログ記事と同様です。
ただし、今回は、OpenFlowコントローラを使用せず、OVSDBコントローラとして、Ryuコントローラを活用しました。

f:id:ttsubo:20140323213802j:plain

2. VxLANトンネル設定プログラム

OVSDBを制御するPythonプログラムは、以下になります。OVSDBコントローラのNorthBoundインタフェースとして、REST-APIを採用しております。

import json

from webob import Response
from ryu.base import app_manager
from ryu.app.wsgi import ControllerBase, WSGIApplication, route
from ryu.lib.dpid import DPID_PATTERN
from ryu.lib.ovs import bridge

OVSDB_ADDR1 = 'tcp:192.168.0.1:6632'
OVSDB_ADDR2 = 'tcp:192.168.0.2:6632'

class SetOvsdb(app_manager.RyuApp):

    _CONTEXTS = {
        'wsgi': WSGIApplication
    }

    def __init__(self, *args, **kwargs):
        super(SetOvsdb, self).__init__(*args, **kwargs)
        wsgi = kwargs['wsgi']
        wsgi.register(OvsdbController, {'SetOvsdb' : self})


    def setTunnel(self, id, name, type, local_ip, remote_ip):
        if id == 1:
            ovs_bridge = bridge.OVSBridge(id, OVSDB_ADDR1)
        elif id == 2:
            ovs_bridge = bridge.OVSBridge(id, OVSDB_ADDR2)
        else:
            return 1

        ovs_bridge.init()
        ovs_bridge.add_tunnel_port(name, type, local_ip, remote_ip)
        return 0



class OvsdbController(ControllerBase):
    def __init__(self, req, link, data, **config):
        super(OvsdbController, self).__init__(req, link, data, **config)
        self.ovsdb_spp = data['SetOvsdb']

    @route('router', '/ovsdb/{dpid}/tunnel', methods=['POST'], requirements={'dpid': DPID_PATTERN})
    def set_tunnel_port(self, req, dpid, **kwargs):

        tunnel_param = eval(req.body)
        result = self.setTunnel(int(dpid, 16), tunnel_param)

        message = json.dumps(result)
        return Response(status=200,
                        content_type = 'application/json',
                        body = message)


    def setTunnel(self, id, tunnel_param):
        simpleOvsdb = self.ovsdb_spp
        name = tunnel_param['tunnel']['name']
        type = tunnel_param['tunnel']['type']
        local_ip = tunnel_param['tunnel']['local_ip']
        remote_ip = tunnel_param['tunnel']['remote_ip']

        simpleOvsdb.setTunnel(id, name, type, local_ip, remote_ip)

        return {
            'id': '%016d' % id,
            'tunnel': {
                'name': '%s' % name,
                'type': '%s' % type,
                'local_ip': '%s' % local_ip,
                'remote_ip': '%s' % remote_ip
            }
        }

3. OVSDBコントローラ上でのプログラム動作イメージ

実際に、プログラムを動作させてみました。REST-API経由で、VxLANトンネル設定パラメータを受信した様子がわかると思います。

$ ryu-manager setOvsdb.py
loading app setOvsdb.py
creating context wsgi
instantiating app setOvsdb.py of SetOvsdb
(4017) wsgi starting up on http://0.0.0.0:8080/
(4017) accepted ('127.0.0.1', 37197)
127.0.0.1 - - [23/Mar/2014 17:35:17] "POST /ovsdb/0000000000000001/tunnel HTTP/1.1" 200 250 0.285298
(4017) accepted ('127.0.0.1', 37201)
127.0.0.1 - - [23/Mar/2014 17:35:21] "POST /ovsdb/0000000000000002/tunnel HTTP/1.1" 200 250 0.287827

4. OFS1へのVxLANトンネル設定

実際に、OVSDBコントローラの上位より、REST-APIを経由してOFS1用のVxLANトンネル設定パラメータを指定しました。

$ curl -s -X POST -d '{"tunnel": {"name": "vxlan1", "type": "vxlan", "local_ip": "172.16.0.1", "remote_ip": "172.16.0.2"}}' http://localhost:8080/ovsdb/0000000000000001/tunnel | python -mjson.tool
{
    "id": "0000000000000001", 
    "tunnel": {
        "local_ip": "172.16.0.1", 
        "name": "vxlan1", 
        "remote_ip": "172.16.0.2", 
        "type": "vxlan"
    }
}

結果として、OFS1上で、想定どおりにVxLANトンネルが構築できました。

tsubo@OFS1:~$ sudo ovs-vsctl show
82524775-43a3-4838-90ae-61e2cbd10820
    Manager "ptcp:6632"
    Bridge "br0"
        Controller "tcp:192.168.0.100:6633"
        Port "eth1"
            Interface "eth1"
        Port "br0"
            Interface "br0"
                type: internal
        Port "vxlan1"
            Interface "vxlan1"
                type: vxlan
                options: {local_ip="172.16.0.1", remote_ip="172.16.0.2"}
    ovs_version: "2.0.1"

5. OFS2へのVxLANトンネル設定

同様に、OVSDBコントローラの上位より、REST-APIを経由してOFS2用のVxLANトンネル設定パラメータを指定しました。

$ curl -s -X POST -d '{"tunnel": {"name": "vxlan2", "type": "vxlan", "local_ip": "172.16.0.2", "remote_ip": "172.16.0.1"}}' http://localhost:8080/ovsdb/0000000000000002/tunnel | python -mjson.tool
{
    "id": "0000000000000002", 
    "tunnel": {
        "local_ip": "172.16.0.2", 
        "name": "vxlan2", 
        "remote_ip": "172.16.0.1", 
        "type": "vxlan"
    }
}

結果として、OFS2上で、想定どおりにVxLANトンネルが構築できました。

tsubo@OFS2:~$ sudo ovs-vsctl show
845f5da2-fb63-4273-b32a-c4cf77b0b943
    Manager "ptcp:6632"
    Bridge "br0"
        Controller "tcp:192.168.0.100:6633"
        Port "br0"
            Interface "br0"
                type: internal
        Port "eth2"
            Interface "eth2"
        Port "vxlan2"
            Interface "vxlan2"
                type: vxlan
                options: {local_ip="172.16.0.2", remote_ip="172.16.0.1"}
    ovs_version: "2.0.1"

6. VxLANトンネル上での通信確認

VxLANトンネル構築が完了したので、ちゃんと動作できるかの確認として、MacBook Airからインターネットに接続して、Ustream映像を閲覧してみました。ustream映像も問題なく再生できておりました。あと、余談ですが、ustream映像の「BABYMETAL」は、要注目ですよ。
f:id:ttsubo:20140323215130j:plain

7. 留意事項

VxLANトンネルの登録・削除を繰り返すと、OFポート番号が、インクリメントしてしまうようです。
OpenFlowでVxLANトンネルを制御する際には、考慮が必要となりますね。

tsubo@OFS1:~$ sudo ovs-ofctl dump-ports-desc br0 --protocols=OpenFlow13
OFPST_PORT_DESC reply (OF1.3) (xid=0x2):
 1(eth1): addr:00:10:f3:1d:3d:1d
     config:     0
     state:      0
     current:    1GB-FD COPPER AUTO_NEG
     advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD 1GB-FD COPPER AUTO_NEG
     supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD 1GB-FD COPPER AUTO_NEG
     speed: 1000 Mbps now, 1000 Mbps max
 5(vxlan1): addr:de:be:49:23:35:a6
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(br0): addr:00:10:f3:1d:3d:1d
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max

◆終わりに

以前から、VxLANトンネル等のネットワーク仮想化の構成管理って、OpenvSwitchコマンド主体だと煩雑になる懸念がありました。OVSDBプロトコル自体の活用シーンは、OpenvSwitch専用ツールが前提となります。ただし、今後も、SDN技術領域におけるOpenvSwitchの役割りは大きなウエイトを占めると予想されますので、もっとちゃんと使いこなせるように調査探求していきたいです。

ネットワーク仮想化技術の実践活用(1) 〜LinuxボックスでVxLAN構築編〜

前回まで、OpenFlow簡易ルータの実践活用として、いろいろと実装技術を試してきました。今回からは、少し路線を変更して、ネットワーク仮想化技術に着目したいと思います。
ネットワーク仮想化技術といえば、SDN業界では、VxLANやNVGREなどの新技術が注目されておりますね。ただ、ちょっと前までは、ベンダのプロプライエタリ製品でなければ実践活用が難しい側面がありました。
最近では、OpenvSwitchでVxLANが使用できるようになったみたいなので、さっそく、試してみたいと思います。

◆ネットワーク仮想化環境

通常だと、ネットワーク仮想化環境を試してみる場合には、お手軽にサーバ仮想化環境で、ネットワーク仮想化ソフトウェアを構築してみる方法が一般的だと思いますが、折角なので、もっと、実践的にLinuxボックスでネットワーク仮想化環境を構築したいと思います。

1. ハードウェア構成

DNA940のLinuxボックスに、OpenvSwitchを搭載する形態としました。よって、前回のDNA940を引き続き使用します。
DNA 940 - ネットワーク&コミュニケーション関連 - NEXCOM

ただし、ネットワーク仮想化を実現するためには、オーバレイNWを終端するエッジ機能を有するLinuxボックスが最低2台必要になりますので、もう一台も事前にセットアップしておきました。
f:id:ttsubo:20140315150626j:plain

2. 自宅ネットワークへの導入形態

VxLANトンネルを導入して自宅ネットワークのL2ドメインを拡張する形態としました。
Linuxボックスの装置間は、所謂、IPネットワークを介して相互接続する構成が一般的のようです。ただ、今回は、シンプルに直結しました。さらに、Linuxボックス上での実際のパケット転送は、OpenFlowによるフロー制御ルールは、事前に定義する形態としました。
f:id:ttsubo:20140315151103j:plain

◆OpenvSwitchでのVxLAN設定方法

1. OpenvSwitch(2.0.1)のインストール

OpenvSwitchのインストール手順は、前回のブログ記事と同一のため、ここでは記述を割愛します。
OpenFlow簡易ルータの実践活用(3) 〜LinuxボックスでOpenFlowスイッチ構築編〜 - SDN開発エンジニアを目指した活動ブログ

2. その他、Linuxボックスでの環境設定

その他の設定作業は、概ね、こんな感じです。
ここでは、OFS1についてのみ記載しますが、同様の作業をOFS2についても行います。

(1) IPフォワードを有効にする

$ sudo vi /etc/sysctl.conf 
net.ipv4.ip_forward=1

$ sudo sysctl -p
net.ipv4.ip_forward = 1

(2) Linuxネットワークを設定する

$ sudo vi /etc/network/interface
----------
auto eth0
iface eth0 inet static
address 192.168.0.1
netmask 255.255.255.0

auto eth1
iface eth1 inet manual
up ifconfig $IFACE 0.0.0.0 up
up ip link set $IFACE promisc on
down ip link set $IFACE promisc off
down ifconfig $IFACE down

auto eth2
iface eth2 inet static
address 172.16.0.1
netmask 255.255.255.0
----------

(3) OpenvSwitchのVxLAN用の仮想ポートを作成する

$ sudo ovs-vsctl add-port br0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=172.16.0.2
$ sudo ovs-vsctl show
82524775-43a3-4838-90ae-61e2cbd10820
    Bridge "br0"
        Controller "tcp:192.168.0.100:6633"
        Port "eth1"
            Interface "eth1"
        Port "br0"
            Interface "br0"
                type: internal
        Port "vxlan1"
            Interface "vxlan1"
                type: vxlan
                options: {remote_ip="172.16.0.2"}
    ovs_version: "2.0.1"

3. OpenFlowによるフローエントリ設定

LinuxボックスでのVxLAN設定作業が完了したら、OpenFlowによるフロー制御ルールを設定します。
ここでは、必要最低限のサンプルなので、実用性は度外視しております。

import logging

from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3

LOG = logging.getLogger('SimpleForward')

class SimpleForward(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    def __init__(self, *args, **kwargs):
        super(SimpleForward, self).__init__(*args, **kwargs)

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        datapath.id = msg.datapath_id
        ofproto_parser = datapath.ofproto_parser

        set_config = ofproto_parser.OFPSetConfig(
            datapath,
            datapath.ofproto.OFPC_FRAG_NORMAL,
            datapath.ofproto.OFPCML_MAX
        )
        datapath.send_msg(set_config)

        self.send_flow(datapath)
        return 0


    def send_flow(self, datapath):
        self.add_flow(datapath, 1, 2)
        self.add_flow(datapath, 2, 1)


    def add_flow(self, datapath, inPort, outPort):
        match = datapath.ofproto_parser.OFPMatch(
                in_port=inPort )
        actions =[datapath.ofproto_parser.OFPActionOutput(outPort, 0)]
        inst = [datapath.ofproto_parser.OFPInstructionActions(
                datapath.ofproto.OFPIT_APPLY_ACTIONS, actions)]
        mod = datapath.ofproto_parser.OFPFlowMod(
                cookie=0,
                cookie_mask=0,
                table_id=0,
                command=datapath.ofproto.OFPFC_ADD,
                datapath=datapath,
                idle_timeout=0,
                hard_timeout=0,
                priority=0xff,
                buffer_id=0xffffffff,
                out_port=datapath.ofproto.OFPP_ANY,
                out_group=datapath.ofproto.OFPG_ANY,
                match=match,
                instructions=inst)
        datapath.send_msg(mod)

4. その他、OpenvSwitch上での各種確認

OpenFlowコントローラから設定したフローエントリは、こんな感じで確認できます

$ sudo ovs-ofctl dump-flows br0 --protocols=OpenFlow13
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x0, duration=32.161s, table=0, n_packets=566, n_bytes=181688, priority=255,in_port=1 actions=output:2
 cookie=0x0, duration=32.161s, table=0, n_packets=590, n_bytes=62642, priority=255,in_port=2 actions=output:1

OpenFlowポートでの実際のトラフィックカウンタも、こんな感じで確認することが可能です。

$ sudo ovs-ofctl dump-ports br0 --protocols=OpenFlow13
OFPST_PORT reply (OF1.3) (xid=0x2): 3 ports
  port  1: rx pkts=27727, bytes=73419238, drop=0, errs=0, frame=0, over=0, crc=0
           tx pkts=18985, bytes=1927125, drop=0, errs=0, coll=0
           duration=2236.049s
  port  2: rx pkts=17785, bytes=1809954, drop=0, errs=0, frame=0, over=0, crc=0
           tx pkts=25827, bytes=72731314, drop=0, errs=0, coll=0
           duration=1060.543s
  port LOCAL: rx pkts=26, bytes=2724, drop=0, errs=0, frame=0, over=0, crc=0
           tx pkts=3357, bytes=1168560, drop=0, errs=0, coll=0
           duration=2236.104s

OpenFlowポートとVxLAN仮想ポートの対応付けも、こんな感じで確認することが可能です。

$ sudo ovs-ofctl dump-ports-desc br0 --protocols=OpenFlow13
OFPST_PORT_DESC reply (OF1.3) (xid=0x2):
 1(eth1): addr:00:10:f3:1d:3d:1d
     config:     0
     state:      0
     current:    1GB-FD COPPER AUTO_NEG
     advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD 1GB-FD COPPER AUTO_NEG
     supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD 1GB-FD COPPER AUTO_NEG
     speed: 1000 Mbps now, 1000 Mbps max
 2(vxlan1): addr:ea:01:9a:e2:fa:67
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(br0): addr:00:10:f3:1d:3d:1d
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max

以上で、VxLANの動作環境の準備が整いました。

◆実際、使ってみて ...

ある程度、Webレスポンス性の性能劣化を想定していたのですが、予想外にも、普段のインターネット利用での操作感と、まったく遜色ありませんでした。通常の検索ポータルでのキーワード検索や、YouTubeなども、ストレスを感じることなく利用することができました。本日のプロ野球オープン戦の実況中継ustream配信も、鮮明な映像だったと思います。

f:id:ttsubo:20140315161609j:plain

いちおう、参考までに、回線速度も計測しておきましたが、結果良好でしたね。
f:id:ttsubo:20140315162508j:plain

◆終わりに

今回は、ネットワーク仮想化の実践活用として基本的なVxLAN環境構築しました。本来のネットワーク仮想化では、MTU調整などをしっかり設計しておかないとフラグメンテーションの多発によるトラフィック性能劣化が発生するはずなのですが、MTUもデフォルト値のままにも関わらず、データプレーンのパフォーマンス劣化を体感することもなく、良好な結果だったと思います。最近のOpenvSwitchでは、オーバレイなカプセル処理によるパケット転送もカーネルモジュールで動作するようになったため、処理能力は昔と比べても、大幅に改善しているようです。

今後は、実践活用における運用面として、環境構築オートメーション化などの対応について、もっと深堀しておきたいところです。

OpenFlow簡易ルータの実践活用(3) 〜LinuxボックスでOpenFlowスイッチ構築編〜

最近、SDN業界では、ホワイトボックス版Linuxベースのオープンなネットワーク機器をデプロイする動きが活発ですよね。
ネットワークにダウンサイジングの波 - [1]スイッチの「オープン化」と「スケールアウト」が進む:ITpro
ネットワークにダウンサイジングの波 - [3]ホワイトボックスに賭ける、ACCESSとPica8の挑戦:ITpro

そこで、これまでの技術ブログ活動の集大成として、ホワイトボックス版OpenFlowスイッチによるOpenFlow簡易ルータを自宅ネットワークに導入してみるチャレンジに取り組んでみたいと思います。

◆OpenFlow簡易ルータのハードウェア構成

今後、OpenFlowスイッチの量産化を意識して、OpenFlowルータの物理構成としての要求条件について、優先順位の高いものから選定ポイントを挙げてみます。

(1)複数の物理NICが搭載していること(何は、さておきといった感じです)
(2)DebianLinuxが動作すること(オープン版スイッチは、Debian系が有望とのことなので...)
(3)なるべく、安価であること(小遣いから工面するわけですから)
(4)見た目がルータ機器っぽいこと(見栄えって案外と重要ですよね)
(5)基本構成として、なるべく汎用性が高いこと(動作実績などを重視したいところなんですけど...)

◆ハードウェアの製品選定

これが、予想通り(?)に難航しました。
世の中、多NICポート搭載の小型Linuxボックスって、なかなか見つからない...
個人的な財力があれば、「OpenBlocks AX3」あたりを選定したいところなんですが...

そんな折に、¥12,800 (税込)で4ポートGigabitEthernet搭載のLinuxボックスを見つけました。
株式会社ネクスコム・ジャパン - 産業用ファンレスコンピュータ, Panel PC, 産業用無線LAN, PCベースFA制御, マシンオートメーション, 車載用テレマティクスPC, デジタルサイネージ, ネットワーク&コミュニケーション関連, IP Camera

(1)〜(4)の条件は、満たしておりますね。
(5)は、こちらのブログ記事でも記載されてますように、HDD用の電源ケーブルVGAケーブルが汎用製品ではないという課題がありそうですが、即買いしてOpenFlow簡易ルータの導入に着手しました。
DNA940にFreeBSD10.0-RELEASEをインストールする: AliceSystem開発日記

◆OpenFlow簡易ルータの外観

実際に構築したLinuxボックスは、こんな感じです。
f:id:ttsubo:20140309154004j:plain

ちなみに、汎用品が見当たらないケーブル類は、@wakadannacomさんの助け舟により幸運にもゲットすることができました。
f:id:ttsubo:20140309153948j:plain

  • 16pin→DIN15pin変換VGAケーブル
  • 電源変換ケーブル 4ピン(メス)->SATA15ピン(メス)

Linuxインストールの留意点

DebianLinuxとして、Ubuntu Server版をインストールしました。
ここでの落とし穴は、DNA940搭載CPUは、”Intel® Celeron® M 600MHz”ということなので、PAE非搭載CPUだということですね。
こちらの技術ブログに記載されているように、このままでは、Ubuntu 12.04 LTSをインストールすることができません。
PAE非搭載CPUで使えるLinux » のろまのひでっち ウェブサイト
そこで、敢えて、11.10をインストールした上で、12.04にupgradeしました。
upgrade from 11.10 to 12.04 - No upgrade option available in update manager - Ask Ubuntu

◆自宅ネットワークへの導入形態

Linuxボックスの導入形態は、こちらの構成になります。
f:id:ttsubo:20140309155007j:plain

1. Ryuコントローラの環境構築

まずは、Ryuコントローラ構築からはじめます。

$ sudo apt-get -y install python-pip python-dev libxml2-dev libxslt1-dev python-lxml
$ sudo pip install ryu

2. OpenvSwitch(2.0.1)の環境構築

最近、OpenvSwitch(2.0.1)がリリースされたみたいです。
以下に構築メモを掲載しておきます。

$ uname -a
Linux OFS 3.2.0-60-generic #91-Ubuntu SMP Wed Feb 19 03:55:18 UTC 2014 i686 i686 i386 GNU/Linux
tsubo@OFS:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=12.04
DISTRIB_CODENAME=precise
DISTRIB_DESCRIPTION="Ubuntu 12.04.4 LTS"

$ wget http://openvswitch.org/releases/openvswitch-2.0.1.tar.gz
$ tar zxvf openvswitch-2.0.1.tar.gz
$ rm openvswitch-2.0.1.tar.gz
$ cd openvswitch-2.0.1
$ sudo apt-get install build-essential fakeroot
$ dpkg-checkbuilddeps
dpkg-checkbuilddeps: Unmet build dependencies: debhelper (>= 8) autoconf (>= 2.64) automake (>= 1.10) | automake1.10 libssl-dev python-all (>= 2.6.6-3~) python-qt4 python-twisted-conch
$ sudo apt-get install debhelper autoconf automake libssl-dev python-all python-qt4 python-twisted-conch
$ dpkg-checkbuilddeps
$ sudo fakeroot debian/rules binary
$ cd ..
$ sudo dpkg -i openvswitch-common_2.0.1-1_i386.deb openvswitch-switch_2.0.1-1_i386.deb
Selecting previously unselected package openvswitch-common.
(Reading database ... 62168 files and directories currently installed.)
Unpacking openvswitch-common (from openvswitch-common_2.0.1-1_i386.deb) ...
Selecting previously unselected package openvswitch-switch.
Unpacking openvswitch-switch (from openvswitch-switch_2.0.1-1_i386.deb) ...
Setting up openvswitch-common (2.0.1-1) ...
Processing triggers for man-db ...
Setting up openvswitch-switch (2.0.1-1) ...
FATAL: Module openvswitch not found.
 * Inserting openvswitch module
 * /etc/openvswitch/conf.db does not exist
 * Creating empty database /etc/openvswitch/conf.db
 * Starting ovsdb-server
 * Configuring Open vSwitch system IDs
FATAL: Module openvswitch not found.
 * Inserting openvswitch module
 * Enabling remote OVSDB managers
Processing triggers for ureadahead ...

$ cd openvswitch-2.0.1
$ sudo apt-get install libtool autopoint
$ ./boot.sh
$ ./configure --with-linux=/lib/modules/`uname -r`/build
$ make
$ ls -la ./datapath/linux/openvswitch.ko
-rw-rw-r-- 1 tsubo tsubo 4107386 Mar  9 10:39 ./datapath/linux/openvswitch.ko

$ modinfo ./datapath/linux/openvswitch.ko
filename:       ./datapath/linux/openvswitch.ko
version:        2.0.1
license:        GPL
description:    Open vSwitch switching datapath
srcversion:     EEA0E974ABDD9576BE7716E
depends:        libcrc32c,gre
vermagic:       3.2.0-60-generic SMP mod_unload modversions 686

$ sudo make modules_install
cd datapath/linux && make modules_install
make[1]: Entering directory `/home/tsubo/openvswitch-2.0.1/datapath/linux'
make -C /lib/modules/3.2.0-60-generic/build M=/home/tsubo/openvswitch-2.0.1/datapath/linux modules_install
make[2]: Entering directory `/usr/src/linux-headers-3.2.0-60-generic'
  INSTALL /home/tsubo/openvswitch-2.0.1/datapath/linux/openvswitch.ko
  DEPMOD  3.2.0-60-generic
make[2]: Leaving directory `/usr/src/linux-headers-3.2.0-60-generic'
depmod `sed -n 's/#define UTS_RELEASE "\([^"]*\)"/\1/p' /lib/modules/3.2.0-60-generic/build/include/generated/utsrelease.h`
make[1]: Leaving directory `/home/tsubo/openvswitch-2.0.1/datapath/linux'

$ sudo modprobe gre
$ sudo modprobe libcrc32c
$ sudo insmod ./datapath/linux/openvswitch.ko

$ lsmod|grep open
openvswitch            75156  0 
libcrc32c              12543  1 openvswitch
gre                    12853  1 openvswitch


$ sudo vi /etc/network/interfaces
————————
auto eth0
iface eth0 inet static
address 192.168.0.1
netmask 255.255.255.0

auto eth1
iface eth1 inet manual
up ifconfig $IFACE 0.0.0.0 up
up ip link set $IFACE promisc on
down ip link set $IFACE promisc off
down ifconfig $IFACE down

auto eth2
iface eth2 inet manual
up ifconfig $IFACE 0.0.0.0 up
up ip link set $IFACE promisc on
down ip link set $IFACE promisc off
down ifconfig $IFACE down
————————

$ sudo reboot

$ sudo ovs-vsctl add-br br0
$ sudo ovs-vsctl add-port br0 eth1
$ sudo ovs-vsctl add-port br0 eth2
$ sudo ovs-vsctl set-controller br0 tcp:192.168.0.100:6633
$ sudo ovs-vsctl set bridge br0 other-config:datapath-id=0000000000000001
$ sudo ovs-vsctl set bridge br0 protocols=OpenFlow13

datapath-idもデフォルト値を使用せず、敢えて、「0000000000000001」を前提としております。
OpenvSwitch設定パラメータは以下の通りです。
(OpenFlowチャネルも、昔のポート番号6633のままとしております)

3. OpenFlow簡易ルータの動作準備

ここからは、PC版OpenvSwitchによるOpenFlow簡易ルータの動作準備とまったく同一ですが、いちおう再掲しておきます。
Ryu SDN Frameworkが動作する環境に、OpenFlow簡易ルータのプログラム一式を以下のサイトからダウンロードした上で、 Ryuコントローラを起動します。
Release OpenFlow簡易ルータ(基本動作版) · ttsubo/simpleRouter · GitHub

  • Ryuコントローラの起動
$ cd simpleRouter-0.1/ryu-app/
$ 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
(10256) wsgi starting up on http://0.0.0.0:8080/

4. OpenFlow簡易ルータのアドレス等の設定

OpenFlow簡易ルータの物理ポートにIPアドレスを付与して、デフォルトゲートウェイ設定を行います。通常のルータ機器であれば、CLIで実施する作業でしょうけど、ここでは、RESTful-IFにて、パラメータ設定を行っております。
注)ポート番号とIPアドレスの対応付けは、ここで指定することになります。よって、実際の物理ポートとケーブル結線が一致していないと通信できません。

  • eth1側の物理ポート設定
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:01", "ipaddress": "192.168.100.100", "port": "1", "opposite_ipaddress": "192.168.100.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool
{
    "id": "0000000000000001", 
    "interface": {
        "ipaddress": "192.168.100.100", 
        "macaddress": "00:00:00:00:00:01", 
        "opposite_ipaddress": "192.168.100.1", 
        "port": "1"
    }
}
  • eth2側の物理ポート設定
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:02", "ipaddress": "192.168.101.100", "port": "2", "opposite_ipaddress": "192.168.101.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool
{
    "id": "0000000000000001", 
    "interface": {
        "ipaddress": "192.168.101.100", 
        "macaddress": "00:00:00:00:00:02", 
        "opposite_ipaddress": "192.168.101.1", 
        "port": "2"
    }
}
$ curl -s -X POST -d '{"gateway": {"ipaddress": "192.168.100.1"}}' http://localhost:8080/openflow/0000000000000001/gateway | python -mjson.tool
{
    "gateway": {
        "ipaddress": "192.168.100.1"
    }, 
    "id": "0000000000000001"
}

以上で、環境準備は終了です。

◆実際、使ってみて ...

Linuxボックスで構築したOpenFlowスイッチを介して実際にインターネットにアクセスしてみました。
結論としては、PC版OpenvSwitchと同様に、普段のインターネット利用での操作感と、まったく遜色ありませんでした。通常の検索ポータルでのキーワード検索や、YouTubeなども、普通に利用できました。
さきほど配信されていたustreamでのオープン戦のライブ映像も、ストレスなく閲覧できておりました。
f:id:ttsubo:20140309161521j:plain

あと、回線速度計測の結果も、良好でしたね。
f:id:ttsubo:20140309173133j:plain

今回の技術興味のポイントとしては、実際の通信パケットが、OpenFlowスイッチを通過する度に、Linuxボックス側のCPUがFlowエントリに従って、宛先MACアドレス,送信元MACアドレスを書き換えた上で、パケット転送処理を実施している点であり、DNA940の搭載CPU「Intel® Celeron® M 600MHz」が、パケット転送のオーバヘッドとして、「どの程度の影響を与えるか?」という点です。
結論としては、通常のインターネット利用の体感に、ほとんど影響するものではありませんでした。

(DNA940は、GigabitEthernet搭載なので、このあたりの処理限界を確認できてはおりませんが...)

◆終わりに

今回は、LinuxボックスDNA940で構築したをOpenFlowスイッチを自宅ネットワークに導入して、インターネットが利用できるところまで確認できました。結果には、大変、満足しております。
あとは、時間がゆるせば、今後、最新OpenvSwitch機能を試しておきたいところですね。

OpenFlow簡易ルータの実践活用(2) 〜LINC-Switch導入編〜

前回は、OpenvSwitch (2.0.0)で構築したOpenFlowスイッチとOpenFlow簡易ルータを、自宅ネットワークに導入してみました。
今回は、OpenFlowスイッチとして、LINC-Switchを採用して、前回と同様に自宅ネットワークに導入してみたいと思います。

◆導入形態

導入形態は、前回とまったく同様の構成になります。
OpenFlow簡易ルータの実践活用(1) 〜OpenvSwitch導入編〜 - SDN開発エンジニアを目指した活動ブログ

f:id:ttsubo:20140308074413j:plain

1. Ryuコントローラの最新化

Ryuコントローラのインストールが最近行われていない場合は、後述のof_configが失敗する可能性があります。
私のRyuコントローラ環境では、lxmlをアップグレードすることでof_configが使用できるようになりました。

$ sudo pip install lxml --upgrade

2. LINC-Switchの環境構築

つぎに、LINC-Switch環境手順です。
こちらのブログ記事を参考にさせて頂きました。
Raspberry Piで家庭内LANをOpenFlow化 (part 1) | d.yasukun

LINC-Switchのインストールが完了したら、早速、LINC-Switchを起動してみます。

$ sudo LINC-Switch/rel/linc/bin/linc console
Exec: /home/tsubo/LINC-Switch/rel/linc/erts-5.10.4/bin/erlexec -boot /home/tsubo/LINC-Switch/rel/linc/releases/1.0/linc -mode embedded -config /home/tsubo/LINC-Switch/rel/linc/releases/1.0/sys.config -args_file /home/tsubo/LINC-Switch/rel/linc/releases/1.0/vm.args -- console
Root: /home/tsubo/LINC-Switch/rel/linc
Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

22:09:22.086 [info] Application lager started on node linc@OFS
22:09:22.087 [info] Application ssh started on node linc@OFS
22:09:22.087 [info] Application enetconf started on node linc@OFS
22:09:22.125 [info] Application linc started on node linc@OFS
Eshell V5.10.4  (abort with ^G)
(linc@OFS)1> 22:09:22.158 [info] Created port: {port,1,[{queues_status,disabled},{queues,[]},{config,{port_configuration,undefined,up,false,false,false}},{features,{features,undefined,'100Mb-FD',true,copper,unsupported}},{queues,[]},{interface,"eth2"}]}
22:09:22.194 [info] Created port: {port,2,[{queues_status,disabled},{queues,[]},{config,{port_configuration,undefined,up,false,false,false}},{features,{features,undefined,'100Mb-FD',true,copper,unsupported}},{queues,[]},{interface,"eth1"}]} 

3. of_configによるdatapath-idの変更

LINC-Switchのdatapath-idは、デフォルト値を使用せず、「0000000000000001」に変更する必要があります。
LINC-Switchでは、of-configによりdatapath-idを変更できるようです。
Ryuコントローラも、of_configに対応しておりますので、今回は、of_config用pythonスクリプトで対応します。

from ryu.lib.of_config.capable_switch import OFCapableSwitch
import time

sess = OFCapableSwitch(
    host='192.168.0.1',
    port=1830,
    username='linc',
    password='linc',
    unknown_host_cb=lambda host, fingeprint: True)

#-------------------------------------------
#  edit_config "
#-------------------------------------------
csw = sess.get_config('running')
for p in csw.logical_switches.switch:
    p.datapath_id = '00:00:00:00:00:01:00:00'
sess.edit_config('running', csw)
time.sleep(3)

#-------------------------------------------
#  get_config "
#-------------------------------------------
csw = sess.get_config('running')
for p in csw.logical_switches.switch:
    print p

of_config用pythonスクリプトを、Ryuコントローラから起動します。

$ python of_config.py 
OFLogicalSwitchType(capabilities=None,check_controller_certificate=None,controllers=OFLogicalSwitchControllersType(controller=[OFControllerType(id='Switch0-DefaultController',ip_address='192.168.0.100',local_ip_address=None,local_port=None,port=6633,protocol='tcp',role='equal',state=OFControllerStateType(connection_state='down',current_version=None,local_ip_address_in_use=None,local_port_in_use=None,supported_versions=[1.3]))]),datapath_id='00:00:00:00:00:01:00:00',enabled=None,id='LogicalSwitch0',lost_connection_behavior=None,resources=OFLogicalSwitchResourcesType(certificate=None,flow_table=[],port=['LogicalSwitch0-Port2', 'LogicalSwitch0-Port1'],queue=[]))
$

4. OpenFlow簡易ルータの動作準備

ここからは、前回とまったく同様の手順です。
Ryu SDN Frameworkが動作する環境に、OpenFlow簡易ルータのプログラム一式を以下のサイトからダウンロードした上で、 Ryuコントローラを起動します。
Release OpenFlow簡易ルータ(基本動作版) · ttsubo/simpleRouter · GitHub

  • Ryuコントローラの起動
$ cd simpleRouter-0.1/ryu-app/
$ 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
(10256) wsgi starting up on http://0.0.0.0:8080/
  • eth1側の物理ポート設定
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:01", "ipaddress": "192.168.100.100", "port": "1", "opposite_ipaddress": "192.168.100.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool
{
    "id": "0000000000000001", 
    "interface": {
        "ipaddress": "192.168.100.100", 
        "macaddress": "00:00:00:00:00:01", 
        "opposite_ipaddress": "192.168.100.1", 
        "port": "1"
    }
}
  • eth2側の物理ポート設定
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:02", "ipaddress": "192.168.101.100", "port": "2", "opposite_ipaddress": "192.168.101.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool
{
    "id": "0000000000000001", 
    "interface": {
        "ipaddress": "192.168.101.100", 
        "macaddress": "00:00:00:00:00:02", 
        "opposite_ipaddress": "192.168.101.1", 
        "port": "2"
    }
}
$ curl -s -X POST -d '{"gateway": {"ipaddress": "192.168.100.1"}}' http://localhost:8080/openflow/0000000000000001/gateway | python -mjson.tool
{
    "gateway": {
        "ipaddress": "192.168.100.1"
    }, 
    "id": "0000000000000001"
}

以上で、環境準備は終了です。

◆iperfを用いたスループットの計測

LINC-Switchのパフォーマンスを測ってみました。

f:id:ttsubo:20140302154957j:plain

$ iperf -c 192.168.100.1
------------------------------------------------------------
Client connecting to 192.168.100.1, TCP port 5001
TCP window size:  129 KByte (default)
------------------------------------------------------------
[  4] local 192.168.101.1 port 62192 connected with 192.168.100.1 port 5001
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0-10.0 sec   110 MBytes  92.0 Mbits/sec
  • iperf確認結果(ThinkPad T61側)
$ iperf -c 192.168.101.1
------------------------------------------------------------
Client connecting to 192.168.101.1, TCP port 5001
TCP window size: 23.5 KByte (default)
------------------------------------------------------------
[  3] local 192.168.100.1 port 59915 connected with 192.168.101.1 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec   110 MBytes  92.1 Mbits/sec

計測結果としては、前回のOpenvSwitchと、ほぼ同等のTCPスループットでした。

$ ping 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes
64 bytes from 192.168.100.1: icmp_seq=0 ttl=64 time=1.465 ms
64 bytes from 192.168.100.1: icmp_seq=1 ttl=64 time=1.792 ms
64 bytes from 192.168.100.1: icmp_seq=2 ttl=64 time=1.549 ms
64 bytes from 192.168.100.1: icmp_seq=3 ttl=64 time=1.577 ms
64 bytes from 192.168.100.1: icmp_seq=4 ttl=64 time=2.072 ms
^C
--- 192.168.100.1 ping statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 1.465/1.691/2.072/0.219 ms

MacBookThinkPad間でのRTTは、概ね、1.5ms程度でした。

◆実際、使ってみて ...

LINC-Switchを介して実際にインターネットにアクセスしてみました。
使い勝手としては、前回のOpenvSwitchよりも、Webブラウジングのレスポンス性が芳しくありませんでした。
Safariのブラウザからだと、通常の検索ポータルでのキーワード検索や、ustreamが利用できましたが、操作感はストレスを感じるものでした。
なお、firefoxのブラウザだと、軒並み以下のエラー画面が表示されてしまいました。
f:id:ttsubo:20140308004200j:plain

◆OpenvSwitchとのスピードテスト結果の比較

インターネット上のスピードテストを計測できるサイトを活用して、OpenvSwitchとLINC-Switchの回線速度を比較してみました。
使用したスピード計測サイトを以下となります。
BNR スピードテスト 回線速度/通信速度 測定

1. LINC-Switchの場合

昔のダイアルアップ接続の回線速度と同程度という結果でした。
やはり、LINC-Switchはユーザランドでパケット転送処理を実施しているため、回線速度の低下してしまうということでしょうか
f:id:ttsubo:20140308004215j:plain

2. OpenvSwitchの場合

前回のWebブラウジングでの操作感と同様に、想定どおりの回線速度が確認できました。
OpenvSwitchはカーネルモジュールでパケット転送処理を実施しているため、スループット劣化していないようです。
f:id:ttsubo:20140308004228j:plain

◆終わりに

LINC-Switchを実際に使ってみて、ちょっと、実用性は低そうです。
ただ、OpenFlowコントローラの勉強用(デバック用)として活用する場合には、とても利用価値が高い製品だと思います。

OpenFlow簡易ルータの実践活用(1) 〜OpenvSwitch導入編〜

前回まで、Ryu SDN Frameworkを活用したOpenFlow簡易ルータ作成を行ってきましたが、OpenFlow勉強の素材として、当初想定していた必要機能は一通り具備できたと思います。早速、OpenFlow簡易ルータを自宅ネットワークに導入して、その使い勝手を確認してみたいと思います。

◆導入形態

OpenFlow簡易ルータの自宅ネットワークへの導入形態としては、新たなサブネットと既存サブネットとをゲートウェイ的に相互接続し、新セグメント上に配備したMacBookからインターネットにアクセスできる形態を目指します。

◆導入にあたっての準備

OpenFlowコントローラやOpenFlowスイッチを動作できる環境を構築します。
また、自宅ネットワーク側でのBBルータでのルーティング追加などが必要ですが、ここでは設定方法などは割愛します。

f:id:ttsubo:20140302143041j:plain

1. Ryuコントローラの環境構築

まずは、Ryuコントローラ構築からはじめます。

$ sudo apt-get -y install python-pip python-dev libxml2-dev libxslt1-dev python-lxml
$ sudo pip install ryu

2. OpenvSwitch(2.0.0)の環境構築

つぎに、OpenvSwitch環境手順ですが、こちらのブログ記事を参考にさせて頂きました。本来であれば、Ubuntu Server版でOpenvSwitchを構築すべきなんですが、今回が初回ということもあり、環境構築の準備中に、Wiresharkを動作させたかったので、まずは実績つくりを優先してDesktop版を使用しました。
Ubuntu-12.04.3にopenvswitch-2.0.0をインストール | 迷い庭

あと、datapath-idもデフォルト値を使用せず、敢えて、「0000000000000001」を前提としております。
OpenvSwitch設定パラメータは以下の通りです。
(OpenFlowチャネルも、昔のポート番号6633のままとしております)

$ sudo ovs-vsctl add-br br0
$ sudo ovs-vsctl add-port br0 eth1
$ sudo ovs-vsctl add-port br0 eth2
$ sudo ovs-vsctl set-controller br0 tcp:192.168.0.100:6633
$ sudo ovs-vsctl set bridge br0 other-config:datapath-id=0000000000000001
$ sudo ovs-vsctl set bridge br0 protocols=OpenFlow13

3. OpenFlow簡易ルータの動作準備

Ryu SDN Frameworkが動作する環境に、OpenFlow簡易ルータのプログラム一式を以下のサイトからダウンロードした上で、 Ryuコントローラを起動します。
Release OpenFlow簡易ルータ(基本動作版) · ttsubo/simpleRouter · GitHub

  • Ryuコントローラの起動
$ cd simpleRouter-0.1/ryu-app/
$ 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
(10256) wsgi starting up on http://0.0.0.0:8080/

OpenFlow簡易ルータの物理ポートにIPアドレスを付与して、デフォルトゲートウェイ設定を行います。通常のルータ機器であれば、CLIで実施する作業でしょうけど、ここでは、RESTful-IFにて、パラメータ設定を行っております。
注)ポート番号とIPアドレスの対応付けは、ここで指定することになります。よって、実際の物理ポートとケーブル結線が一致していないと通信できません。

  • eth1側の物理ポート設定
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:01", "ipaddress": "192.168.100.100", "port": "1", "opposite_ipaddress": "192.168.100.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool
{
    "id": "0000000000000001", 
    "interface": {
        "ipaddress": "192.168.100.100", 
        "macaddress": "00:00:00:00:00:01", 
        "opposite_ipaddress": "192.168.100.1", 
        "port": "1"
    }
}
  • eth2側の物理ポート設定
$ curl -s -X POST -d '{"interface": {"macaddress": "00:00:00:00:00:02", "ipaddress": "192.168.101.100", "port": "2", "opposite_ipaddress": "192.168.101.1"}}' http://localhost:8080/openflow/0000000000000001/interface | python -mjson.tool
{
    "id": "0000000000000001", 
    "interface": {
        "ipaddress": "192.168.101.100", 
        "macaddress": "00:00:00:00:00:02", 
        "opposite_ipaddress": "192.168.101.1", 
        "port": "2"
    }
}
$ curl -s -X POST -d '{"gateway": {"ipaddress": "192.168.100.1"}}' http://localhost:8080/openflow/0000000000000001/gateway | python -mjson.tool
{
    "gateway": {
        "ipaddress": "192.168.100.1"
    }, 
    "id": "0000000000000001"
}

◆OpenFlow簡易ルータの動作確認

基本的な準備が完了したところで、正しくOpenFlow簡易ルータが動作しているかを確認してみましょう。
なお、動作確認で使用したスクリプトは、こちらから利用可能です。
simpleRouter/rest-client at master · ttsubo/simpleRouter · GitHub
(1) Arpテーブル確認
 : 物理ポート毎の接続先ホスト(MacBook, BBルータ)のMacアドレスが取得できていることを確認します。

$ ./get_arp.sh 
/openflow/0000000000000001/arp
-----------------------------------------------------------
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json; charset=UTF-8
header: Content-Length: 238
header: Date: Sat, 01 Mar 2014 23:25:44 GMT
+++++++++++++++++++++++++++++++
2014/03/02 08:25:44 : ArpTable 
+++++++++++++++++++++++++++++++
portNo   MacAddress        IpAddress
-------- ----------------- ------------
       1 10:66:82:93:c4:f0 192.168.100.1
       2 7c:c3:a1:87:8f:65 192.168.101.1

注)さきほど、RESTful-IFで設定したポート番号とIPアドレスの対応付けが、実際の物理ポートとケーブル結線が一致していない場合には、Arpテーブルに該当情報が表示されません。

◆実際、使ってみて ...

OpenFlow簡易ルータの動作確認を終了したので、いよいよ、実際にインターネットにアクセスしてみました。
結論としては、普段のインターネット利用での操作感と、まったく遜色ありませんでした。
通常の検索ポータルでのキーワード検索や、YouTubeなども、普通に利用できました。
今朝のustreamでの鈴鹿サーキット公式レースのライブ映像も、ストレスなく閲覧できておりました。
f:id:ttsubo:20140302153236j:plain

あと、ざっくりですが、OpenvSwitchでのトラフィックカウンタも確認してみました。
(1) PortStats確認
 : 物理ポート毎のトラフィックカウンタが取得できていることを確認しました

$ ./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: 443
header: Date: Sat, 01 Mar 2014 23:35:25 GMT
+++++++++++++++++++++++++++++++
2014/03/02 08:35:25 : PortStats
+++++++++++++++++++++++++++++++
portNo   rxPackets rxBytes  rxErrors txPackets txBytes  txErrors
-------- --------- -------- -------- --------- -------- --------
       1     31631 41554372        0     16960  2475911        0
       2     17342  2553369        0     30423 41169870        0
fffffffe        10      844        0       164    38702        0

(2) FlowStats確認
 : Flowエントリ毎のトラフィックカウンタが取得できていることを確認しました

$ ./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: 454
header: Date: Sat, 01 Mar 2014 23:35:32 GMT
+++++++++++++++++++++++++++++++
2014/03/02 08:35:32 : FlowStats
+++++++++++++++++++++++++++++++
inPort   ethSrc             ethDst             ipv4Dst         packets  bytes
-------- ------------------ ------------------ --------------- -------- --------
       1  10:66:82:93:c4:f0  00:00:00:00:00:01   192.168.101.1    29859 41033174
       2  7c:c3:a1:87:8f:65  00:00:00:00:00:02   192.168.100.1      159    13110
       *                  *                  *       0.0.0.0/0    17345  2659435

◆簡単な動作検証

iperf等でOpenFlow簡易ルータの簡単なパフォーマンスを測ってみました。
(ちなみに、ここでの通信はすべて、Flowエントリに基づいた転送処理になっています。)

f:id:ttsubo:20140302154957j:plain

$ iperf -c 192.168.100.1
------------------------------------------------------------
Client connecting to 192.168.100.1, TCP port 5001
TCP window size:  129 KByte (default)
------------------------------------------------------------
[  4] local 192.168.101.1 port 57447 connected with 192.168.100.1 port 5001
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0-10.0 sec   112 MBytes  94.3 Mbits/sec
  • iperf確認結果(ThinkPad T61側)
$ iperf -c 192.168.101.1
------------------------------------------------------------
Client connecting to 192.168.101.1, TCP port 5001
TCP window size: 23.5 KByte (default)
------------------------------------------------------------
[  3] local 192.168.100.1 port 51676 connected with 192.168.101.1 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec   114 MBytes  95.2 Mbits/sec
$ ping 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes
64 bytes from 192.168.100.1: icmp_seq=0 ttl=64 time=0.907 ms
64 bytes from 192.168.100.1: icmp_seq=1 ttl=64 time=0.989 ms
64 bytes from 192.168.100.1: icmp_seq=2 ttl=64 time=0.908 ms
64 bytes from 192.168.100.1: icmp_seq=3 ttl=64 time=0.873 ms
64 bytes from 192.168.100.1: icmp_seq=4 ttl=64 time=0.892 ms
64 bytes from 192.168.100.1: icmp_seq=5 ttl=64 time=1.196 ms
^C
--- 192.168.100.1 ping statistics ---
6 packets transmitted, 6 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.873/0.961/1.196/0.111 ms

MacBookThinkPad間でのRTTは、概ね、1ms程度でした。

◆終わりに

実際にOpenFlow簡易ルータを使ってみて、想定通りの動作を確認できました。
前回まで、仮想VM環境で同等の動作確認を行ってきたわけですし、OpenvSwitch動作環境として、それなりのスペックを取り揃えたわけですから、今回の結果は最初から想定できた内容なのですが、実際に実機と繋がったワクワク感は、純粋に楽しいですよね。まあ、今後の課題は、如何にコモディティ化を図った安価な機器に置き換えられるというところでしょうけど ...

あと、Mininet環境だと、ちゃんと動作したのに実機だと想定どおり動作しない場面もよく遭遇しまよね。この時のトラブルシューティング経験が、SDN開発エンジニアとしての技術知識の糧になるものだと思いますので、これからも実機での作業を大切にしていきたいです。

次回からは、OpenFlowスイッチとして、LINC-Switch環境を導入していきたいと思います。