diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..db6a6de --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source :rubygems +gem 'redcarpet' +gem 'showoff' +gem 'heroku' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..56e1cb2 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,47 @@ +GEM + remote: http://rubygems.org/ + specs: + addressable (2.2.7) + blankslate (2.1.2.4) + bluecloth (2.2.0) + gli (1.5.1) + heroku (2.21.3) + launchy (>= 0.3.2) + netrc (~> 0.7.1) + rest-client (~> 1.6.1) + rubyzip + json (1.6.5) + launchy (2.0.5) + addressable (~> 2.2.6) + mime-types (1.17.2) + netrc (0.7.1) + nokogiri (1.5.2) + parslet (1.3.0) + blankslate (~> 2.0) + rack (1.4.1) + rack-protection (1.2.0) + rack + redcarpet (2.1.0) + rest-client (1.6.7) + mime-types (>= 1.16) + rubyzip (0.9.6.1) + showoff (0.7.0) + bluecloth + gli (>= 1.3.2) + json + nokogiri + parslet + sinatra + sinatra (1.3.2) + rack (~> 1.3, >= 1.3.6) + rack-protection (~> 1.2) + tilt (~> 1.3, >= 1.3.3) + tilt (1.3.3) + +PLATFORMS + ruby + +DEPENDENCIES + heroku + redcarpet + showoff diff --git a/README.md b/README.md new file mode 100644 index 0000000..2bdfc7b --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Quick Start + + git clone git://github.com/trema/tutorial.git + cd tutorial + + # run the standard presentation + showoff serve + +This will launch a local Sinatra server on port 9090. Open your browser to `localhost:9090`. On a Mac you can run: + + open http://localhost:9090 + +Use arrow keys to navigate through the slides. Press '?' to see a help window with more key commands. + + +# Printing slides (PDF) + +Try this: first `gem install pdfkit`, then visit + + http://localhost:9090/pdf + + +# LICENSE +Copyright (c) 2012 Yasuhito Takamiya + +Licensed under the GPL3 license diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..b0d48a4 --- /dev/null +++ b/config.ru @@ -0,0 +1,2 @@ +require "showoff" +run ShowOff.new diff --git a/hello_switch/hello_switch.md b/hello_switch/hello_switch.md new file mode 100644 index 0000000..978a1ba --- /dev/null +++ b/hello_switch/hello_switch.md @@ -0,0 +1,84 @@ + +# Task B: Hello Switch! ######################################################## +## OpenFlow スイッチとコントローラを接続 + + + +## "OpenFlow スイッチを持っていないけど、
どうすればいい?" + + + +# 演習 : Hello Switch コントローラ ############################################ + + $ trema run hello-switch.rb -c hello-switch.conf + Password: xxxxxxxx # Enter your password here + Hello 0xabc! # Ctrl-c to quit + +* ソフトウェア版 OpenFlow スイッチ (dpid = 0xabc) を起動し、コントローラと接続します +* コントローラは `"Hello 0xabc!"` と表示します +* ソフトウェア版 OpenFlow スイッチの起動は `hello-switch.conf` に定義します + + + +![overview](hello_switch.png) + + + +# hello-switch.conf ############################################################ + + @@@ ruby + # + # Add a switch with dpid == 0xabc + # + vswitch { dpid "0xabc" } + # or + vswitch { datapath_id "0xabc" } + +* ソフトウェア版 OpenFlow スイッチが起動し、コントローラとのコネクションを確立します +* Trema は Full-stack の開発フレームワークです。ノート PC が一台あれば、物理スイッチを持っていなくても開発ができます + + + +# `hello-switch.rb` ############################################################ + + @@@ ruby + class HelloSwitch < Controller + def switch_ready dpid + info "Hello #{ dpid.to_hex }!" + end + end + +* `switch_ready` は、スイッチがコントローラに接続したときに呼ばれるハンドラです +* 引数の `dpid` には接続したスイッチの ID が格納されます +* `.to_hex` をつけることで `dpid` を 16 進数で表示します + + + +# 演習: スイッチの追加 #################################################### + + @@@ ruby + # hello-switch.conf + vswitch { dpid "0x1" } + vswitch { dpid "0x2" } + vswitch { dpid "0x3" } + ... + + + $ trema run hello-switch.rb -c hello-switch.conf + ??? + +* `hello-switch.conf` にスイッチを追加して `trema run` したとき、何が表示される? +* 注 : 各スイッチの dpid はユニークである必要があります + + + +# ここまでのサマリー ############################################################### + +## Trema は "Post-Rails" なモダンなフレームワークです + +
+ +* 書いたコードをすぐ動かせる: `trema run` +* Coding by Convention: 分かりやすく名付けられた各種メソッド +* Full-Stack: ネットワーク DSL によるエミュレーション +* 便利なサブコマンド : `trema ruby` diff --git a/hello_switch/hello_switch.png b/hello_switch/hello_switch.png new file mode 100644 index 0000000..5c86737 Binary files /dev/null and b/hello_switch/hello_switch.png differ diff --git a/hello_trema/hello_trema.md b/hello_trema/hello_trema.md new file mode 100644 index 0000000..25afbf2 --- /dev/null +++ b/hello_trema/hello_trema.md @@ -0,0 +1,160 @@ + +# Task A: Hello Trema! ######################################################### + + + +## 演習: "Hello Trema!" を実行 ############################################# + +### 以下のコマンドを入力し、Trema を実行します : + + $ cd Tutorials/Trema + $ trema run hello-trema.rb + Hello Trema! # Ctrl-C to quit + + + +![overview](hello_trema.png) + + + +# 基本コマンド : `trema run` ############################################### + + $ trema run [controller-file] + +* 上記コマンドで、コントローラを実行します +* Ctrl-c で停止します +* `trema help run` でオプションリストを表示します + + + +# 書いたコードをすぐ動かす ################################################################# + +* `trema run` コマンドで、書いたコントローラをすぐ実行できます +* 書いたコントローラを、即座にテストできます +* 短いサイクルで "コーディング、テスト、デバッグ" を繰り返す開発スタイルを実現できます + + + +# Trema 上での コントローラの書き方 ############################################# + + + +# hello-trema.rb ############################################################### + + @@@ ruby + class HelloController < Controller + def start + info "Hello Trema!" + end + end + +* シンプルですが、これだけで完全なコントローラのコードになっています +* (ただし Hello Trema! と表示するだけのものです) + + + +# コントローラクラス ############################################################# + + @@@ ruby + class HelloController < Controller + # ... + end + +* すべてのコントローラは、クラスとして実装します (`class HelloController`) +* Trema クラスライブラリに用意されている `Controller` クラスのサブクラスとして実装します +* コントローラに必要なメソッドは、自動的に継承されます (flow-mod メッセージの送信等) + + + +# イベントハンドラ ############################################################### + + @@@ ruby + class MyController < Controller + def start # start-up event handler + # ... + end + + def packet_in dpid, msg # Packet-in received handler + # ... + end + + # ... + end + +* イベントドリブン形式で、コントローラを記述します +* 各イベントハンドラを、インスタンスメソッドとして実装します + + + +# イベントハンドラ (Floodlight の場合) ################################################# + + @@@ java + // Packet-in handling in Floodlight + public Command receive(IOFSwitch sw, ...) { + switch (msg.getType()) { + case PACKET_IN: + return this.handlePacketIn(sw, ...); + ... + private Command handlePacketIn(IOFSwitch sw, ...) { + ... + +* Floodlight では、複雑なイベント振り分けを必要とします +* おまじないが多いため、コードの見通しが悪くなります + + + +# イベントの振り分け ################################################################ + + @@@ ruby + # Packet-in handling in Trema + class MyController < Controller + def start # automatically called at startup + # ... + end + + def packet_in dpid, msg # automatically caled when receiving a packet-in + # ... + end + end + +* Trema はイベントの振り分けにリフレクションを使っています +* そのため、複雑になりがちなディスパッチやハンドラ登録を行う必要はありません + + + +# コーディングのための工夫 ####################################################### + +* 簡潔なコードを書くための工夫 + * e.g., "handler name" == "message name" +* イベントディスパッチのような、おまじないを不要に +* 楽しいプログラミングのために、お約束事やつまらない部分を削減 + + + +# 短く書く ################################################################ + +* コードの長さと生産性の間には強い相関関係 + * e.g. Arc Programming Language [Paul Graham] +* コードを短くすることで、 + * お約束コードを書く時間を最小にする + * バグ混入の可能性を少なくする + +
+ +## Trema は、実行時の効率性よりも +## プログラマーの生産性に重きをおいています + + + +# Logging API ################################################################## + + @@@ ruby + class HelloController < Controller + def start + info "Hello Trema!" # outputs an info level message + end + end + +* ロギングレベル毎に用意されたシンプルな API (debug, info, etc) +* `trema ruby` で、Logging API を含む API リファレンスを表示 + diff --git a/hello_trema/hello_trema.png b/hello_trema/hello_trema.png new file mode 100644 index 0000000..1f63a01 Binary files /dev/null and b/hello_trema/hello_trema.png differ diff --git a/intermission/intermission.md b/intermission/intermission.md new file mode 100644 index 0000000..0623e0f --- /dev/null +++ b/intermission/intermission.md @@ -0,0 +1,2 @@ + +# Intermission (10 minutes) #################################################### diff --git a/intro/intro.md b/intro/intro.md new file mode 100644 index 0000000..ac1c01f --- /dev/null +++ b/intro/intro.md @@ -0,0 +1,42 @@ + +# 作ってわかる OpenFlow ######################################################## +## Trema チュートリアル&ハンズオン + +### 鈴木 一哉 +### 高宮 安仁 + + + +# 本日のゴール ################################################################# + +## "トラフィックモニターつき L2 スイッチ" の実装 + +* Tutorial Kit: +* "Hello World" から始め、5 つの段階を踏んで開発を行います +* Trema を使い OpenFlow コントローラの開発サイクルを体験します + + + +# Trema とは ################################################################ + +* Ruby と C 向けの OpenFlow コントローラ開発フレームワーク + * GPL2 + * +* "Post-Rails" 高い生産性を実現 + * 書いたコードをすぐ動かせる + * よくある処理を短く書ける + * 統合されたテスト環境 + + + +# Trema = ###################################################################### +## OpenFlow コントローラ向けライブラリ +## (Ruby and C) +## + +## ネットワークエミュレータ +## + +## `trema` コマンド + + + +![overview](overview.png) diff --git a/intro/overview.png b/intro/overview.png new file mode 100644 index 0000000..739bbb8 Binary files /dev/null and b/intro/overview.png differ diff --git a/learning_switch/dump_flows.png b/learning_switch/dump_flows.png new file mode 100644 index 0000000..60f30f3 Binary files /dev/null and b/learning_switch/dump_flows.png differ diff --git a/learning_switch/learning_switch.md b/learning_switch/learning_switch.md new file mode 100644 index 0000000..271a846 --- /dev/null +++ b/learning_switch/learning_switch.md @@ -0,0 +1,183 @@ + +# Task D: Learning Switch ###################################################### + +## Sending flow\_mod and packet\_out + + + +# Exercise: Packet Stats Info ################################################## + +## Launch a L2 switch controller: + + $ trema run learning-switch.rb -c learning-switch.conf + +
+
+ +## Send a test packet on another terminal, +## then `show_stats` to view sent/received packet stats information + + $ trema send_packet --source host1 --dest host2 + $ trema show_stats host1 + $ trema show_stats host2 + + + +![overview](show_stats.png) + + + +# Exercise: View the Flow Table #################################################### + + $ trema send_packet --source host2 --dest host1 + $ trema dump_flows 0xabc + +## The above command displays the flow-table entries stored in the switch `0xabc` + + + +![overview](dump_flows.png) + + + +# Useful Sub-Commands ########################################################## + +* `trema show_stats HOST_NAME` +* `trema dump_flows SWITCH_NAME` + +## Various stats and internal info can be displayed with one simple command + + + +# Source Code: Learning Switch ################################################# + + + +# Learning Switch ############################################################## + + @@@ ruby + class LearningSwitch < Controller + # ... + def packet_in dpid, message + @fdb.learn message.macsa, message.in_port + port_no = @fdb.lookup( message.macda ) + if port_no + flow_mod dpid, message, port_no + packet_out dpid, message, port_no + else + flood dpid, message + end + end + # ... + end + +# Reads smoothly like a pseudo code!? + + + +# Read It Aloud! ############################################################### + + @@@ ruby + class LearningSwitch < Controller + # ... + def packet_in dpid, message + @fdb.learn message.macsa, message.in_port + port_no = @fdb.lookup( message.macda ) + if port_no + flow_mod dpid, message, port_no + packet_out dpid, message, port_no + else + flood dpid, message + end + end + # ... + end + +* When a packet comes in as a packet-in message, make FDB learn its macsa and the in_port +* Look up the destination's port number from packet's macda +* If found: update switch's flow-table and do packet-out the packet +* If not-found: flood the packet + + + +# Private Methods ############################################################## + +* Actually `flow_mod`, `packet_out`, `flood` are not part of the Trema API, but defined as private methods here +* Proper use of names for private methods makes your code clean and can be read like pseudo-code + + + +# Flow-Mod ##################################################################### + + @@@ ruby + class LearningSwitch < Controller + # ... + private + def flow_mod dpid, message, port_no + send_flow_mod_add( + dpid, + :match => ExactMatch.from( message ), + :actions => ActionOutput.new( port_no + 1 ) + ) + end + # ... + end + +* Echoes the packet that exactly matches with `message` to the next port +* Short and clean + + + +# Syntactic Sugar: `ExactMatch.from()` ######################################### + + @@@ ruby + ExactMatch.from( message ) + +# vs. + + @@@ ruby + Match.new( + :in_port => message.in_port, + :nw_src => message.nw_src, + :nw_dst => message.nw_dst, + :tp_src => message.tp_src, + :tp_dst => message.tp_dst, + :dl_src => message.dl_src, + :dl_dst => message.dl_dst, + ... + ) + + + +# Trema vs. NOX Python ######################################################### + + @@@ ruby + # Trema + send_flow_mod_add( + dpid, + :match => ExactMatch.from( message ), + :actions => ActionOutput.new( port_no ) + ) + +# vs. + + @@@ python + # NOX Python + inst.install_datapath_flow( + dpid, + extract_flow(packet), + CACHE_TIMEOUT, + openflow.OFP_FLOW_PERMANENT, + [[openflow.OFPAT_OUTPUT, [0, prt[0]]]], + bufid, + openflow.OFP_DEFAULT_PRIORITY, + inport, + buf + ) + + + +# Learning Switch: Summary ##################################################### + +* Stats info: `trema show_stats`, `trema dump_flows` +* "Write it short" API: `ExactMatch.from`, `send_flow_mod_add` diff --git a/learning_switch/show_stats.png b/learning_switch/show_stats.png new file mode 100644 index 0000000..0295983 Binary files /dev/null and b/learning_switch/show_stats.png differ diff --git a/outro/outro.md b/outro/outro.md new file mode 100644 index 0000000..1b7316e --- /dev/null +++ b/outro/outro.md @@ -0,0 +1,76 @@ + +# Summary ####################################################################### + + + +# Trema: "OpenFlow like Rails" ################################################## + +* Run It Quick: Tight loops of coding, run, and debug + * Virtual network DSL + * `trema {run, send_packets, show_stats, up, kill}` +* Coding by Convention: Write it short + * Auto handler dispatch by naming convention + * Class attributes: `periodic_timer_event` + * Syntactic sugars: `ExactMatch.from` + * Default options: `send_flow_mod_add` +* Useful Sub-commands + * `trema {dump_flows, ruby}` + + + +# Next Step For Developers ##################################################### + +* `[trema]/src/examples` + * Simple samples demonstrating API usage + * Good references for understanding both Ruby and C APIs +* Trema/Apps + * Practical/experimental controllers developed on top of Trema + * Good starting point for developing real-world controllers + + + +# Love Ruby? ################################################################### + + + +# Love C? ###################################################################### + + + +# Trema C ###################################################################### + +* It's your choice ... Trema provides libraries for both Ruby and C +* Trema C is also simple as Trema Ruby + +
+ + $ gcc myapp.c `trema-config -c -l` -o myapp + $ trema run myapp + + + +# Sources ###################################################################### + +* This Tutorial: +* Trema: +* Trema/Apps: +* Web Page: +* Twitter: +* Mailing List: +* Bugs: + + + +# Contributors! ################################################################ + +* Free Trema T-shirt for contributors! + * Patch (New features/apps, enhancements, bug-fixes) + * Bug report + * Documentation etc. +* Send pull-requests and get the T! + + + +# Questions? ################################################################### + + diff --git a/packetin_dumper/packetin_dumper.md b/packetin_dumper/packetin_dumper.md new file mode 100644 index 0000000..c02ac94 --- /dev/null +++ b/packetin_dumper/packetin_dumper.md @@ -0,0 +1,123 @@ + +# Task C: Packet-In Dumper ##################################################### + +## Packet-In メッセージの扱い + + + +## 演習 : Packet-In メッセージの内容を表示 ############################# + + $ trema run packetin-dumper.rb -c packetin-dumper.conf + +* Packet-In dumper コントローラを起動します +* 仮想ネットワークも同時に起動します (= 1 台の仮想スイッチと 2 台の仮想ホスト host1, host2) + + + +![overview](packetin_dumper1.png) + + + +## 演習 : Packet-In メッセージの内容を表示 ############################# + + $ trema send_packets --source host1 --dest host2 + +* 別のターミナルを開き、host1 から host2 へとパケットを送信します +* その結果、コントローラに送られた Packet In メッセージがダンプ表示されます + + + +![overview](packetin_dumper2.png) + + + +## Q: How did you do that (sending test packets)? ############################## + + + +# Virtual Host And Virtual Link ################################################ + +## Connect virtual hosts (host1, host2) to the virtual switch 0xabc + + @@@ ruby + # Add one virtual switch + vswitch { dpid "0xabc" } + # Add two virtual hosts + vhost "host1" + vhost "host2" + # Then connect them to the switch 0xabc + link "0xabc", "host1" + link "0xabc", "host2" + +## Send test packets between virtual hosts as defined above + + $ trema send_packets --source host1 --dest host2 + + + +# Network Configuration File ################################################### + +* Simple enough to configure a test environment +* Specify and construct any arbitrary network by just writing configuration statements in DSL +* And also send test packet by one simple command + + + +# Example: A More Complicated Network ############################################ + + @@@ ruby + vswitch { dpid "0x1" } + vswitch { dpid "0x2" } + ... + vhost "host1" + vhost "host2" + vhost "host3" + vhost "host4" + ... + link "0x1", "0x2 + ... + link "0x1", "host1" + link "0x1", "host2" + link "0x2", "host3" + link "0x2", "host4" + ... + + + +# Handling Packet-In ########################################################### + + + +# `PacketinDumper#packet_in` ################################################### + + @@@ ruby + # packetin-dumper.rb + class PacketinDumper < Controller + def packet_in dpid, message + info "received a packet_in" + info "dpid: #{ datapath_id.to_hex }" + info "in_port: #{ message.in_port }" + end + end + +* `packet_in`: arguments are dpid and a Packet-In message object (`message`) +* `message.attribute` for inspecting the attributes of the Packet-In message + + + +# Exercise: Inspecting Other Packet-In Attributes ############################## + + @@@ ruby + # packetin-dumper.rb + class PacketinDumper < Controller + def packet_in dpid, message + info "received a packet_in" + info "dpid: #{ datapath_id.to_hex }" + info "in_port: #{ message.in_port }" + info "total_len: #{ message.total_len }" + ... + end + end + +* Display other Packet-In attributes (total_len, macsa, macda ...) +* Hint: Use `trema ruby` for the full API reference of PacketIn class diff --git a/packetin_dumper/packetin_dumper1.png b/packetin_dumper/packetin_dumper1.png new file mode 100644 index 0000000..b69d442 Binary files /dev/null and b/packetin_dumper/packetin_dumper1.png differ diff --git a/packetin_dumper/packetin_dumper2.png b/packetin_dumper/packetin_dumper2.png new file mode 100644 index 0000000..58ea9b2 Binary files /dev/null and b/packetin_dumper/packetin_dumper2.png differ diff --git a/showoff.json b/showoff.json new file mode 100644 index 0000000..5f646e0 --- /dev/null +++ b/showoff.json @@ -0,0 +1,14 @@ +{ + "name" : "Trema Tutorial", + + "sections" : [ + {"section" : "intro"}, + {"section" : "hello_trema"}, + {"section" : "hello_switch"}, + {"section" : "packetin_dumper"}, + {"section" : "intermission"}, + {"section" : "learning_switch"}, + {"section" : "traffic_monitor"}, + {"section" : "outro"} + ] +} diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..6fc557e --- /dev/null +++ b/styles.css @@ -0,0 +1,17 @@ +.small { + font-size: 70%; +} + +.smaller { + font-size: 60%; +} + +.slide_info { + width: 100%; + position: absolute; + bottom: 30px; + left: 0; + margin: 0 auto; + text-align: center; + z-index: 2147483647; /* max, see http://www.puidokas.com/max-z-index/ */ +} diff --git a/traffic_monitor/traffic_monitor.md b/traffic_monitor/traffic_monitor.md new file mode 100644 index 0000000..b7491b1 --- /dev/null +++ b/traffic_monitor/traffic_monitor.md @@ -0,0 +1,101 @@ + +# Task E: Traffic Monitor ###################################################### + +## Getting traffic data from flow_removed messages + + + +# Exercise: Displaying Traffic Data ############################################ + + $ trema run traffic-monitor.rb -c traffic-monitor.conf + + + # (On another terminal,) + $ trema send_packets --source host1 --dest host2 + $ trema send_packets --source host1 --dest host2 + $ trema send_packets --source host2 --dest host1 + +* Launch a "L2 switch with traffic monitoring" controller +* Send test packets randomly +* The controller displays and updates the traffic stats of each host + + + +![overview](traffic_monitor.png) + + + +# Getting Traffic Data ######################################################### + + @@@ ruby + class TrafficMonitor < Controller + # ... + def flow_removed dpid, message + @counter.add message.match.dl_src, message.byte_count + end + + private + + def flow_mod dpid, macsa, macda, out_port + send_flow_mod_add( + dpid, + :hard_timeout => 10, # flows lifetime = 10 seconds. + :match => Match.new( :dl_src => macsa, :dl_dst => macda ), + :actions => ActionOutput.new( out_port ) + ) + end + # ... + end + + +* Set each flow's lifetime to 10 seconds +* Handle flow\_removed messages generated when a flow timeouts +* Record the traffic amount transferred from the removed flow + + + +# Displaying Traffic Info ###################################################### + + @@@ ruby + class TrafficMonitor < Controller + periodic_timer_event :show_counter, 10 + + # ... + + private + + def show_counter + puts Time.now + @counter.each_pair do | mac, nbytes | + puts "#{ mac } #{ nbytes } bytes" + end + end + + # ... + end + +* Shows the current time and traffic data stored in `@counter` every 10 seconds + + + +# Timer Attribute ############################################################## + + @@@ ruby + class TrafficMonitor < Controller + periodic_timer_event :show_counter, 10 + + # ... + + def show_counter ... + end + +* You can define timer handlers like a class attribute +* Don't need to implement timer handling by yourself using threads etc. +* Another example of coding by convention + + + +# Traffic Monitor: Summary ##################################################### + +* Shows how to use the traffic data stored in flow_removed messages +* A practical example of learning switch controller diff --git a/traffic_monitor/traffic_monitor.png b/traffic_monitor/traffic_monitor.png new file mode 100644 index 0000000..cf9220e Binary files /dev/null and b/traffic_monitor/traffic_monitor.png differ