OpenFlow入門@Trema

# OpenFlow環境構築

OpenFlowを学習するための環境構築を行う。
今回は、開発・学習コストが比較的低い「Trema」を採用し、その入門であるHello,Trema!
(https://yasuhito.github.io/trema-book/#hello_trema)
を実装する。
プログラムの解説は省略します。

##開発環境
* OS Ⅹ EL Capitan
* Vitualbox(5.1.0)
* Vagrant(1.9.1)
* Ubuntu16.04 
* Trema 0.10.1
* ruby 2.3.1
* OpenFlow 1.0

## Tremaとは 

TremaはNECによって開発されたOpenFlow1.0準拠のフルスタックのOpenFlowコントローラフレームワーク。
プログラミング言語としてはRubyに対応していて、GPL v2ライセンスで提供されている。
現在では、Tremaのフレームワークである「Trema edge」においてOpenFlow 1.3に対応している。

TremaはLinux用のソフトウェアで以下のディストリビューションで動作が可能。  

* Ubuntu Linux
* Debian GNU/Linux
* CentOS 6 系, 7系

Tremaに必要なソフトウェアは以下

* sudo : Tremaはroot権限でコマンドを実行する
* Ruby : Tremaを使ったコントローラの開発にもRubyを使う
* Bundler : Rubyライブラリのインストーラ
* Open VSwitch : OpenFlow に対応したソフトウェアスイッチの一種

Tremaの開発・学習コストが比較的低いと言われる理由は、仮想マシン1台でOpenFlowスイッチ・OpenFlow コントローラ・ホストの動作を確認できる点にある。

他のOpenFlowコントローラフレームワークを用いる場合には、仮想マシンを複数立てたり、Mininetを利用する必要がある。

## さっそく環境構築

### Vagrantで仮想マシンを立てる

* Vagrantfile(だいぶ適当です。。)

```
Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-16.04"
  #Vitual boxのケーブル接続設定
  config.vm.provider "virtualbox" do |vb|
   vb.customize ["modifyvm", :id, "--cableconnected1", "on"]
  end

  config.vm.define "trema" do |trema|
    #ホスト名の設定
    trema.vm.hostname = "trema"

	#ホストOSと通信するIPアドレスの設定
    trema.vm.network "private_network", ip: "192.168.33.33"

  end

  #ansibleの設定
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "provisioning/site.yml"
    ansible.inventory_path = "provisioning/hosts"
    ansible.limit = 'all'
  end
end
```

* 仮想マシンの起動・SSH

```
$ vagrant up
$ vagrant provison (ansibleを利用していない人は省略)
$ vagrant ssh trema
```


### Rubyのインストール

以下のサイトを参考にしました。
http://kinnnikutsuu.blogspot.jp/2016/12/linuxtrema-ruby-httpsgorails.html

* Ruby 2.3.1 を入れる(他のバージョンでもいけるかも)

```
$ sudo apt-get update
$ sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev
$ cd
$ wget http://ftp.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
$ tar -xzvf ruby-2.3.1.tar.gz
$ cd ruby-2.3.1/
$ ./configure
$ make
$ sudo make install
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
```

* Tremaの最新バージョン[0.10.1]に対応しているBundlerのバージョンを指定して、インストールする

```
$ gem install bundler -v 1.11.2
```

### Open vSwitchのインストール

```
$ sudo apt-get install -y openvswitch-switch
$ sudo service openvswitch-switch start
```

## Hello,Trema!

Hello Trema!はもっとも簡単なOpenFlowコントローラである。その機能はOpen vSwitchと接続して Hello, 0x1! (0x1 はOpen vSwitchに割り当てたdatapath-id) と表示する。

### 設定ファイル記述

* ディレクトリ構成  
プロジェクト用のディレクトリ「hello_trema」内にOpenFlowコントローラに関するすべてのファイルを置く。

```
└ hello_trema   
　├ lib  
　　　└ hello_trema.rb 
　├ trema.conf   
　└ Gemfile
```

* hello_trema.rb  
ソースコード用のディレクトリ「lib」内にOpenFlowコントローラー本体の実装を行う。

```
# Hello World!
class HelloTrema < Trema::Controller
  # Tremaの起動後に出力
  def start(_args)
    logger.info 'Trema started.'
  end
  
  # Open vSwitchと接続後に出力
  def switch_ready(datapath_id)　
    logger.info "Hello #{datapath_id.to_hex}!"
  end
end
```

* trema.comf
プログラムの実行には、OpenFlowスイッチが1台必要であるため、設定ファイル「trema.conf」に記述する。

```
vswitch {datapath_id 0x1}
```

* Gemfile  
gemの取得元`https://rubygems.org`を指定し、Tremaの実行環境(0.10.1)を取得する

```
source 'https://rubygems.org/'
 
gem 'trema','~> 0.10.1'
```


### Tremaのインストール

Bundlerを利用し、Gemfileに記述した実行環境をセットアップする。Gemfile に記述したTremaと、それに依存するgemファイル一式を自動的にインストールし、Tremaの実行コマンドを「bin」ディレクトリに生成します。

```
$ bundle install --binstubs
$ ./bin/trema -v
```

セットアップにエラーがなく、Tremaが正常にインストールされていればOK

### Tremaの実行

```
$ cd hello_trema
$ ./bin/trema run ./lib/hello_trema.rb -c trema.conf

Trema started.
Hello 0x1!
```

Open vSwitchと接続して、割り当てたdatapath-idである 「Hello, 0x1!」 が表示されれば完了。

## おわりに

今回は、Tremaの入門である「Hello,Trema！」を実行する環境を構築した。  

Tremaは仮想スイッチ(OpenvSwitch)などの情報をtrema.confに記述して実行することで、仮想マシン1台でスイッチとコントローラの動作を検証することができる。  

構成は以下のようになっている。
![Trema図.png](https://qiita-image-store.s3.amazonaws.com/0/161771/108ae17e-366e-bf8e-d962-dbbf7f23df9f.png)

前述した通り、OpenFlowスイッチはローカルループバック 127.0.0.1 経由でOpenFlowフレームワーク Trema と接続している。

つまり、この間のやり取りを見たい場合、以下のコマンドで観察できる。

```
$ tcpdump -i lo
```


## おまけ

ネットワークネームスペース機能(netns)を利用することで独立した仮想的なネットワーク環境を作ることもできます。  
これによって、様々な環境をエミュレートすることができます。
  
以下にその例を記述します。

* trema.comf

```
vswitch('0x1') { dpid 0x1 }
netns('host1') {
  ip '192.168.1.2'
  netmask '255.255.255.0'
  route net: '0.0.0.0', gateway: '192.168.1.1'
}
netns('host2') {
  ip '192.168.2.2'
  netmask '255.255.255.0'
  route net: '0.0.0.0', gateway: '192.168.2.1'
}
link '0x1', 'host1'
link '0x1', 'host2'
```

* 構成図

![Trema図2.png](https://qiita-image-store.s3.amazonaws.com/0/161771/41d51c2d-6973-bed5-daf3-72aad1566b44.png)


Tremaの魅力を分かって頂けたでしょうか？  

OpenFlow初心者は、まずリピータハブ・スイッチングハブ、ルータの動作を実現してみるといいと思います。

それでは、TremaからOpenFlowを楽しく勉強しましょう!!