2013年12月11日水曜日

OpenStack と Trema Sliceable Switch とつないでみる

日本 OpenStack ユーザー会 Advent Calendar の 11日目ということで、Neutron と Trema Sliceable Switch を組み合わせて動かしてみようと思います。Okinawa OpenDays の BOF でプレゼンしながらデバッグしています。

devstack を使って動かしていますが、Ubuntu 12.04 でパッケージを使った Havana with Neutron のインストールガイドも https://github.com/amotoki/openstack-havana-install-guideで作っています。今は NEC OpenFlow Plugin のみですが、ML2 Plugin も準備中です。

Trema は OpenFlow Controller Framework で C と Ruby で OpenFlow Controller を書くことができます。みなさん知っていますね。 Sliceable Switch のアプリケーションで、 OpenFlow Controller として動作します。

Neutron のプラグインは NEC OpenFlow Plugin を使います。Sliceable Switch には REST API があり、この API を Plugin から呼び出して、OpenFlow ネットワーク上に複数の論理ネットワークを作成します。

今回は以下のような 3ノードの構成を使用しました。使用したマシンは Ubuntu 12.04 の KVM の VM です。メモリは 2GB です。 NIC は 1つです。 OVS 間のデータプレーンは GRE トンネルで接続しました。
  • Controller Node (nova, neutron のすべてのサービスを動かします)
  • Compute Node
  • OpenFlow Controller


最初に Sliceable Switch をセットアップします。 RVM 環境を利用して Ruby 2.0.0 の環境で動かします。 Trema は Ubuntu 12.04 の ruby 1.8.7 でも動作しますが、 ruby 1.8.7 はすでにサポートが終わっていること、依存モジュールが今後動かないなどのトラブルが出てくる可能性もあります。

Trema のインストール

依存パッケージのインストール以外は root 権限は不要です。
sudo aptitude install gcc make ruby rubygems ruby-dev libpcap-dev libsqlite3-dev libglib2.0-dev sqlite3 libdbi-perl libdbd-sqlite3-perl apache2 libjson-perl
# rvm インストール
\curl -sSL https://get.rvm.io | bash -s stable
# rvm 環境の反映 (ログインし直すか、source .bash_profile と PATH の追加)
PATH=$PATH:$HOME/.rvm/bin
source .bash_profile
# ruby 2.0.0 インストール
rvm install 2.0.0
# trema インストール
gem install trema
bundle install

Sliceable Switch のインストール

インストールは方法は trema apps の sliceable switch の README.md に使い方が書かれています。https://github.com/amotoki/openstack-havana-install-guide/wiki/TremaSliceableSwitch にも詳しく書いておきました。

sliceable switch の実行

最後の起動方法だけが rvm 環境なので少し違います。もっといい方法を調べたいと思います。
sudo bash --login
LOGGING_LEVEL=info TREMA_TMP=$HOME/trema/work/trema trema run -d -c ~/trema/work/sliceable_switch/etc/sliceable.conf
sliceable switch の設定ファイルを引数に指定して trema を実行します。
デバッグレベルを変更する場合は TREMA_LOG_LEVEL で debug などを指定します。
TREMA_TMP 以下に一時ファイル、ログなどが生成されます。

きちんと起動していることを確認しておきます。
$ ps auxw | grep trema
root   24938 0.0 0.0 15024 1844 ?    Ss  17:50  0:00 /home/ubuntu/.rvm/gems/ruby-2.0.0-p353/gems/trema-0.4.6/objects/switch_manager/switch_manager --daemonize --port=6653 -- port_status::topology packet_in::filter state_notify::topology vendor::sliceable_switch
root   24940 0.0 0.0 15216 2044 ?    Ss  17:50  0:00 /home/ubuntu/.rvm/gems/ruby-2.0.0-p353/gems/trema-0.4.6/objects/packetin_filter/packetin_filter --daemonize --name=filter lldp::topology_discovery packet_in::sliceable_switch
root   24942 0.0 0.0 15284 2364 ?    Ss  17:50  0:00 /home/ubuntu/trema/apps/./topology/topology --name topology -d
root   24944 0.0 0.0 15608 2664 ?    Ss  17:50  0:00 /home/ubuntu/trema/apps/./topology/topology_discovery --name topology_discovery -d
root   24946 0.0 0.0 16752 3576 ?    Ss  17:50  0:00 /home/ubuntu/trema/apps/./flow_manager/flow_manager --name flow_manager -d
root   24948 0.0 0.2 21588 8652 ?    Ss  17:50  0:00 /home/ubuntu/trema/apps/./sliceable_switch/sliceable_switch --name sliceable_switch -d -s /home/ubuntu/trema/work/sliceable_switch/db/slice.db -a /home/ubuntu/trema/work/sliceable_switch/db/filter.db
ubuntu  25048 0.0 0.0  8108  896 pts/0  R+  17:53  0:00 grep --color=auto trema
6653/tcp と 8888/tcp が LISTEN されています。 6653 は OpenFlow の controller channel (secure channel) です。 8888 は Sliceable Switch の仮想ネットワークを操作するための REST API です。
$ netstat -ntl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address      Foreign Address     State
tcp    0   0 0.0.0.0:80       0.0.0.0:*        LISTEN
tcp    0   0 0.0.0.0:22       0.0.0.0:*        LISTEN
tcp    0   0 0.0.0.0:8888      0.0.0.0:*        LISTEN
tcp    0   0 0.0.0.0:6653      0.0.0.0:*        LISTEN
tcp6    0   0 :::22          :::*          LISTEN
OpenFlow Controller の準備は終わりです。

OpenStack Controller ノード


devstack を使ってインストールします。
パッケージを使った手順はhttps://github.com/amotoki/openstack-havana-install-guide/wiki/ControllerNodeに書いていますので、参考にして下さい。

localrc はこんな感じです。

KEYSTONE_TOKEN_FORMAT=UUID
PRIVATE_NETWORK_NAME=net1
PUBLIC_NETWORK_NAME=ext_net

disable_service n-net
enable_service neutron q-svc q-agt
enable_service q-dhcp
enable_service q-l3
enable_service q-meta

Q_USE_DEBUG_COMMAND=True
Q_PLUGIN=nec
GRE_LOCAL_IP=10.56.45.216:10.56.45.226
OFC_DRIVER=trema
OFC_API_HOST=10.56.45.218
OFC_API_PORT=8888
OFC_OFP_HOST=10.56.45.218
OFC_OFP_PORT=6653

LOGDIR=$DEST/logs
SCREEN_LOGDIR=$LOGDIR
LOGFILE=$LOGDIR/devstack.log
ADMIN_PASSWORD=pass
MYSQL_PASSWORD=stackdb
RABBIT_PASSWORD=stackqueue
SERVICE_PASSWORD=$ADMIN_PASSWORD
SERVICE_TOKEN=xyzpdqlazydog

Neutron を有効にして、プラグインは NEC OpenFlow Plugin を指定しています。OpenFlow Controller の情報を指定して実行します。ノード間は GRE トンネルで接続するので、GRE で接続するノードリストを指定しています。

./stack.sh を実行して待ちましょう。

OpenStack Compute Node ノード


こちらも同様に devstack を使ってインストールします。
パッケージを使った手順は XXXXXX に書いていますので、参考にして下さい。

localrc はこんな感じです。こちらはいたってシンプルです。
USE_NEUTRON=True

CC_HOST=10.56.45.216
MYSQL_HOST=${CC_HOST}
SERVICE_HOST=${CC_HOST}
RABBIT_HOST=${CC_HOST}
Q_HOST=${CC_HOST}

HOST_IP=$(get_host_ip)

ENABLED_SERVICES=n-cpu,rabbit

enable_service n-novnc
VNCSERVER_PROXYCLIENT_ADDRESS=$HOST_IP
VNCSERVER_LISTEN=$HOST_IP

enable_service q-agt

Q_PLUGIN=nec
GRE_REMOTE_IPS=10.56.45.216:10.56.45.226
OFC_OFP_HOST=${CC_HOST}

LOGDIR=$DEST/logs
SCREEN_LOGDIR=$LOGDIR
LOGFILE=$LOGDIR/devstack.log
LOG_COLOR=False

ADMIN_PASSWORD=pass
MYSQL_PASSWORD=stackdb
RABBIT_PASSWORD=stackqueue
SERVICE_PASSWORD=$ADMIN_PASSWORD
SERVICE_TOKEN=xyzpdqlazydog
こちらもしばらく待ちます。

初期状態の確認


一通り動かし終わったので、状態を見てみましょう。

まずは Neutron 側の情報から。
$ cd devstack
$ . openrc
$ neutron net-list
+--------------------------------------+---------+--------------------------------------------------+
| id                                   | name    | subnets                                          |
+--------------------------------------+---------+--------------------------------------------------+
| f567b464-2968-4d78-a884-875259bc9fc0 | net1    | 042d74c4-434a-4f52-884d-61c10539d2de 10.0.0.0/24 |
| ff946453-aa0e-492c-af8a-f0c53be78448 | ext_net | 73c5c8ca-8c94-4921-88a4-af77ef000fb8             |
+--------------------------------------+---------+--------------------------------------------------+
$ neutron net-show net1
+-----------------+--------------------------------------+
| Field           | Value                                |
+-----------------+--------------------------------------+
| admin_state_up  | True                                 |
| id              | f567b464-2968-4d78-a884-875259bc9fc0 |
| name            | net1                                 |
| router:external | False                                |
| shared          | False                                |
| status          | ACTIVE                               |
| subnets         | 042d74c4-434a-4f52-884d-61c10539d2de |
| tenant_id       | c980a2144ebc4a2dbeb0562218b96fb9     |
+-----------------+--------------------------------------+
$ neutron port-list -c id -c device_owner -c fixed_ips
+--------------------------------------+--------------------------+---------------------------------------------------------------------------------+
| id                                   | device_owner             | fixed_ips                                                                       |
+--------------------------------------+--------------------------+---------------------------------------------------------------------------------+
| 26755062-0bb2-41ff-a85c-95c927d2f5d1 | network:dhcp             | {"subnet_id": "042d74c4-434a-4f52-884d-61c10539d2de", "ip_address": "10.0.0.3"} |
| c8993f73-f737-4cd5-9736-4194cb6624db | compute:probe            | {"subnet_id": "042d74c4-434a-4f52-884d-61c10539d2de", "ip_address": "10.0.0.2"} |
| f48d65b7-85e0-4389-b271-144bde7b8b58 | network:router_interface | {"subnet_id": "042d74c4-434a-4f52-884d-61c10539d2de", "ip_address": "10.0.0.1"} |
+--------------------------------------+--------------------------+---------------------------------------------------------------------------------+
次に OpenFlow Controller 側の情報です。
$ netstat -nt
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address      Foreign Address     State
tcp    0   0 10.56.45.218:6653    10.56.45.226:55373   ESTABLISHED
tcp    0   0 10.56.45.218:6653    10.56.45.216:46843   ESTABLISHED
tcp    0   0 10.56.45.218:22      10.56.45.227:52031   ESTABLISHED
6653/tcp は OpenFlow の control channel です。 6653/tcp の接続が二つあります。
Controller ノードと Compute ノードの OVS br-int が OpenFlow Switch として動作していて、接続に来ていることがわかります。

br-int の設定方法は Install Guide の "Setup datapath bridge" https://github.com/amotoki/openstack-havana-install-guide/wiki/ComputeNodeNeutronNecPlugin を見てください。
set-controller というコマンドを実行すると、OpenFlow Switch として動作します。
ovs-vsctl --no-wait set-controller br-int tcp:10.56.45.210:6653
trema のログを見てみましょう。
trema では switch_manager が接続をうけて、個別の switch daemon を起動します。
switch.0xXXXXXXXXXXXXX.log があることから OVS から接続に来ていることが分かります。
% ls -1l trema/log/
total 12
-rw-r--r-- 1 root root  0 Dec 11 19:18 filter.log
-rw-r--r-- 1 root root  0 Dec 11 19:18 flow_manager.log
-rw-r--r-- 1 root root 6121 Dec 11 19:24 sliceable_switch.log
-rw-rw-rw- 1 root root  0 Dec 11 19:21 switch.0x10056045216.log
-rw-rw-rw- 1 root root  0 Dec 11 19:24 switch.0x10056045226.log
-rw-r--r-- 1 root root  0 Dec 11 19:18 switch_manager.log
-rw-r--r-- 1 root root  0 Dec 11 19:18 topology_discovery.log
-rw-r--r-- 1 root root  82 Dec 11 19:24 topology.log
sliceable_switch.log を見てみます。
以下は dpid = 0x10056045216 の OVS から接続があったことが分かります。
Wed Dec 11 19:21:12 2013 [info] Adding a port: dpid = 0x10056045216, port = 65534 ( "br-int" )
Wed Dec 11 19:22:04 2013 [info] Adding a port: dpid = 0x10056045216, port = 1 ( "tapc8993f73-f7" )
Wed Dec 11 19:22:09 2013 [info] Adding a port: dpid = 0x10056045216, port = 2 ( "tap26755062-0b" )
Wed Dec 11 19:22:17 2013 [info] Adding a port: dpid = 0x10056045216, port = 3 ( "tapf48d65b7-85" )
devstack の中で Neutron Plugin が仮想ネットワークの REST API が呼ばれて、スライス定義が登録されています。
Wed Dec 11 19:18:22 2013 [info] Loading slice definitions.
Wed Dec 11 19:18:22 2013 [info] Adding a port-slice binding ( type = 0x1, datapath_id = 0x10056045216, port = 0x1, vid = 0xffff, slice_number = 0x1, id = 3a084cc4-c090-456f-ac79-7acc9aa20c08, dynamic = 0, updated_at = 1386757102 ).
Wed Dec 11 19:18:22 2013 [info] Adding a port-slice binding ( type = 0x1, datapath_id = 0x10056045216, port = 0x2, vid = 0xffff, slice_number = 0x1, id = def41b36-0d8b-4651-b0dc-b6ede86877a3, dynamic = 0, updated_at = 1386757102 ).
Wed Dec 11 19:18:22 2013 [info] Adding a port-slice binding ( type = 0x1, datapath_id = 0x10056045216, port = 0x3, vid = 0xffff, slice_number = 0x1, id = 59392aa3-8779-403e-92b3-bdc8805630b9, dynamic = 0, updated_at = 1386757102 ).
Wed Dec 11 19:18:22 2013 [info] Adding a port-slice binding ( type = 0x1, datapath_id = 0x10056045216, port = 0x1, vid = 0xffff, slice_number = 0x3, id = 6dfd6bf6-ce17-409a-85f3-6b12f0059570, dynamic = 0, updated_at = 1386757102 ).
Sliceable Switch 側での仮想ネットワーク情報の確認もしてみます。期待通り。
% SLICE_DB_FILE=/home/ubuntu/trema/work/sliceable_switch/db/slice.db ./slice list
               ID               Description
f567b464-2968-4d78-a884-875259bc9fc0  ID=f567b464-2968-4d78-a884-875259bc9fc0 Name=net1 at Neutron.
ff946453-aa0e-492c-af8a-f0c53be78448  ID=ff946453-aa0e-492c-af8a-f0c53be78448 Name=ext_net at Neutron.

% SLICE_DB_FILE=/home/ubuntu/trema/work/sliceable_switch/db/slice.db ./slice show f567b464-2968-4d78-a884-875259bc9fc0
[Description]
ID=f567b464-2968-4d78-a884-875259bc9fc0 Name=net1 at Neutron.

[Port-based bindings]
           ID         Datapath ID    Port       VID
f48d65b7-85e0-4389-b271-144bde7b8b58      0x10056045216      3      65535
26755062-0bb2-41ff-a85c-95c927d2f5d1      0x10056045216      2      65535
c8993f73-f737-4cd5-9736-4194cb6624db      0x10056045216      1      65535

[MAC-based bindings]
No bindings found.

[MAC-based bindings on ports]
No bindings found.

Open vSwitch を見てみます。
$ sudo ovs-vsctl show
ce91e39a-ec92-4a6f-9fbe-d0c8f742c7a3
  Bridge br-ex
    Port "tap9632e3f8-53"
      Interface "tap9632e3f8-53"
    Port br-ex
      Interface br-ex
        type: internal
    Port "tap75223dc9-8f"
      Interface "tap75223dc9-8f"
  Bridge br-int
    Controller "tcp:10.56.45.218:6653"
      is_connected: true
    fail_mode: secure
    Port "tapf48d65b7-85"
      Interface "tapf48d65b7-85"
    Port br-int
      Interface br-int
        type: internal
    Port "tap26755062-0b"
      Interface "tap26755062-0b"
    Port "tapc8993f73-f7"
      Interface "tapc8993f73-f7"
  ovs_version: "1.10.2"
connected: true になっていて、接続されています。
br-int には Neutron のポートに対応するインタフェースがあることが分かります。

Compute Node の方も同じように試してみてください。
devstack を Controller Node で先に実行しているので、こちらには何もありません。

VM を起動してみる


ここで VM を起動してみましょう。
$ nova boot --image tty-quantum --flavor m1.tiny vm1
$ OS_USERNAME=admin OS_TENANT_NAME=admin nova hypervisor-servers ostack
+--------------------------------------+-------------------+---------------+---------------------+
| ID                                   | Name              | Hypervisor ID | Hypervisor Hostname |
+--------------------------------------+-------------------+---------------+---------------------+
| 9170da74-be92-4df4-8f6a-3963de13eede | instance-00000003 | 1             | ostack05            |
| a0d1f35a-0200-4145-9c17-470710f31dd0 | instance-00000004 | 2             | ostack06            |
+--------------------------------------+-------------------+---------------+---------------------+
$ OS_USERNAME=admin OS_TENANT_NAME=admin nova hypervisor-list
+----+---------------------+
| ID | Hypervisor hostname |
+----+---------------------+
| 1  | ostack05            |
| 2  | ostack06            |
+----+---------------------+
今回は Compute ノード側で起動しました。

console.log を見て、アドレスが割り当てられているか確認しましょう。

Horizon のコンソールからログインして ping が通れば成功です。

時間もせまってきたようなので、そろそろ終わりにしようと思います。
一応うまく行ったみたいです。
飲みながらやっていると、全然進みませんね。