Tremaに入門してみる -外部のOpen vSwitchに接続まで-

Tremaの勉強のため
https://yasuhito.github.io/trema-book/#hello_trema
を参考に入門していきます。
何点かすんなり行かなかったところもあるのでメモも兼ねて残しておきます。
一応今回のゴールとしてはTremaを入れたマシンと別のマシンで動いているOpen vSwitchにつなぐことです。

# 環境
VirtualBox上にUbuntu16.04のVMを二台用意して以下のように設定します。
![trema01.png](https://qiita-image-store.s3.amazonaws.com/0/86684/964d3d3b-6ab1-1ef9-161b-8098f83740be.png)



# Tremaインストール

Tremaはマシン2の方に入れていきます。
rubyのインストールからはじめていきます。

```
$ sudo apt-get update
$ sudo apt-get install ruby2.0 ruby2.0-dev build-essential
```

で早速エラー

```
$ sudo apt-get install ruby2.0 ruby2.0-dev build-essential
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
E: パッケージ ruby2.0 が見つかりません
E: 'ruby2.0' に一致するパッケージは見つかりませんでした
E: 正規表現 'ruby2.0' ではパッケージは見つかりませんでした
E: パッケージ ruby2.0-dev が見つかりません
E: 'ruby2.0-dev' に一致するパッケージは見つかりませんでした
E: 正規表現 'ruby2.0-dev' ではパッケージは見つかりませんでした
```

手順書ではruby2.0とありますがruby2.0 やuby2.0-devのパッケージは見当たらないので全てruby2.3にします。

```
$ sudo apt-get install ruby2.3 ruby2.3-dev build-essential
```

bundlerのインストール

```
$ sudo gem install bundler
```

Open vSwitchのインストール

```
$ sudo apt-get install openvswitch-switch
```

これでTremaの準備は終了

# Hello Trema
https://yasuhito.github.io/trema-book/#hello_trema にも書いてある
Hello World的なやつをやってみます。

ここでの操作はマシン2のみです。
まずは、プロジェクトディレクトリを作成します。

```
$ mkdir -p hello_trema/lib
$ cd hello_trema
```

Gemfileを作成しTremaをインストールします。

```Gemfile
source 'https://rubygems.org'

gem 'trema'
```

でインストールしたいのですが

```
$ bundle install
An error occurred while installing trema (0.4.7), and Bundler cannot continue.
Make sure that `gem install trema -v '0.4.7'` succeeds before bundling.
```

この時のbundlerのバージョンが1.12.5なのですが
これを1.11.2にしてみます

```
gem install bundler -v '1.11.2'
bundle _1.11.2_ install
```

これでtremaが使えるようになったはず
とりあえずバージョン確認してみる

```
$ bundle exec trema --version
trema version 0.10.1
```

次にTremaが実行する本体`lib/hello_trema.rb`を作成します。

```lib/hello_trema.rb
# Hello World!
class HelloTrema < Trema::Controller
  def start(_args)
    logger.info 'Trema started.'
  end

  def switch_ready(datapath_id)
    logger.info "Hello #{datapath_id.to_hex}!"
  end
end
```

これで、Tremaを起動すると`Trema started.`と表示され
スイッチがTremaに接続するとそのスイッチのdatapath_idが表示されます。


またTremaが自分で起動する仮想スイッチ(OpenvSwitch)の情報を`trema.conf`を作成し記述します。

```trema.conf
vswitch { datapath_id 0xabc }
```


実行してみます。

```
$ bundle exec trema run ./lib/hello_trema.rb -c trema.conf
Trema started.
Hello 0xabc!
```

これでTremaが動きました。
一旦tremaを停止させます。

```
$ bundle exec trema kill --all
```



# 別マシンのopenvswitchに接続してみる
下の図のような構成でTremaとOpenvSwitchを別マシンに入れました。
この状態で先ほどのhello_tremaを実行すると別マシンのOpen vSwitchも接続されるはず。


## マシン1の準備
OpenvSwitchをインストールします

```
$ apt-get install -y openvswitch-switch
```

ブリッジを作成、マシン2とつながるインターフェースを作成したブリッジにつなぎます。
ついでにブリッジのdatapath-idを0x1に設定します。

```
$ sudo ovs-vsctl add-br ovsbr0
$ sudo ovs-vsctl add-port ovsbr0 enp0s8
$ ovs-vsctl set bridge ovsbr0 other-config:datapath-id=0000000000000001 
```

enp0s8についていたipをブリッジに移します。

```
$ sudo ifconfig enp0s8 0.0.0.0
$ sudo ifconfig ovsbr0 192.168.239.101/24
```

状態を確認しておきます。

```
$ sudo ovs-ofctl show ovsbr0
OFPT_FEATURES_REPLY (xid=0x2): dpid:0000000000000001
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 3(enp0s8): addr:08:00:27:af:d2:31
     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
 LOCAL(ovsbr0): addr:08:00:27:af:d2:31
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
```


ovsbr0(OpenvSwitch)のコントローラをマシン2に設定しておきます

```
$ sudo ovs-vsctl set-controller ovsbr0 tcp:192.168.239.101:6653
```

## 実行

* 実行してみた(失敗)

今回はTrema側でOpen vSwitchを起動する必要がないので起動時に -c オプションは必要ありません

```
$ bundle exec trema run ./lib/hello_trema.rb

/var/lib/gems/2.3.0/gems/pio-0.30.0/lib/pio/open_flow/message.rb:21:in `rescue in read': Invalid OpenFlow10 Hello message. (Pio::ParseError)
```




* 実行してみた(成功)

マシン1でOpenvSwitchにバージョンを指定してみます。

```
sudo ovs-vsctl set bridge ovsbr0 protocols=OpenFlow10
```

もう一度実行してみると

```
$ bundle exec trema run ./lib/hello_trema.rb
Trema started.
Hello 0x1!
```

datapath-id 0x1 が繋がっていることが確認でき、成功しました。