OpenFlow Controllerフレームワークを試すメモです。
すごく簡単なL2スイッチのコントローラを似た感じの実装で並べてみます。(たいてい、各フレームワークにはサンプルでL2スイッチがついてますが、それとは別で。)
まずは、POX(Python)とTrema(Ruby)で。(CはNOXを並べておきたいけど、おいおい。JavaはFloodlightもbeaconも微妙で悩み中、後者かなあ。)
OpenFlow Swithを使った環境の準備方法は、Mininetとか、OpenvSwitchとKVMを使うとか、PC(サーバー)に多ポートNICつけてみるとか。
0. プログラム概要
一台のOpenFlow Switch用のシンプルな学習L2スイッチ。(学習: スイッチのどのポートにどのMacアドレスの通信機器がついているかを保存しておいて、それなりに振舞う。)
このプログラムは、並べて眺めるのが目的なので、まじめに使っちゃ駄目です。
プログラム構成(色分け)
・フレームワークや言語のしきたり
・Macアドレスと ポートの辞書
・OpenFlow Controller(本プログラム)スタート時の準備
・OpenFlow Switchが接続した・切断した時の振る舞い
・OpenFlow Switchからパケット扱いについて問い合わせがきた時の振る舞い
・OpenFlow Switchへの命令(フローテーブル内容変更とか、パケット送出しろとか)
あと、ちょっと珍しい用語として
・datapathは、ざっくりOpenFlow Switchのことみたいな。(そのIDをdatapath_idだとかdpidだとか。)
・FLOODは、ざっくりブロードキャストみたいな。
1. POX(Python)
プログラムファイル: ofc1.py
from pox.core import * from pox.lib.util import dpidToStr import pox.openflow.libopenflow_01 as of log = core.getLogger() macPortDic = {} def launch(): log.info("Controller Launch") core.openflow.addListenerByName("PacketIn", packet_in) core.openflow.addListenerByName("ConnectionUp", connection_up) core.openflow.addListenerByName("ConnectionDown", connection_down) def connection_up(event): log.info("Connection Up: datapath_id=%s" % dpidToStr(event.dpid)) def connection_down(event): log.info("Connection Down: datapath_id=%s" % dpidToStr(event.dpid)) def packet_in(event): packet = event.parse() log.info("Packet-in: datapath_id=%s, port=%d, src mac=%s, dst mac=%s" % (dpidToStr(event.dpid), event.port, packet.src, packet.dst)) macPortDic[packet.src] = event.port if packet.dst in macPortDic: port = macPortDic[packet.dst] flow_mod(event, packet, port) packet_out(event, port) else: packet_out(event, of.OFPP_FLOOD) # Controller-to-Switch Modify-State(Flow Table Modification) def flow_mod(event, packet, port): msg = of.ofp_flow_mod() msg.match = of.ofp_match.from_packet(packet) msg.actions.append(of.ofp_action_output(port = port)) msg.buffer_id = event.ofp.buffer_id event.connection.send(msg) # Controller-to-Switch Send-Packet def packet_out(event, port): msg = of.ofp_packet_out() msg.actions.append(of.ofp_action_output(port = port)) msg.buffer_id = event.ofp.buffer_id msg.in_port = event.port event.connection.send(msg)
実行する
pox.py ofc1
2. Trema(Ruby)
プログラムファイル: ofc1.rb
class OFC1 < Controller def start info "Controller Launch" @macportdic = Hash::new end def switch_ready datapath_id info "Connection Up: datapathid=#{ datapath_id.to_hex }" end def switch_disconnected datapath_id info "Connection Down: datapathid=#{ datapath_id.to_hex }" end def packet_in datapath_id, message info "Packet In: datapath_id=%s, port=%d, src mac=%s, dst mac=%s", datapath_id.to_hex, message.in_port, message.macsa, message.macda @macportdic[message.macsa] = message.in_port if @macportdic.has_key?(message.macda) port_no = @macportdic[message.macda] flow_mod datapath_id, message, port_no packet_out datapath_id, message, port_no else packet_out datapath_id, message, OFPP_FLOOD end end # Controller-to-Switch Modify-State(Flow Table Modification) def flow_mod datapath_id, message, port_no send_flow_mod_add( datapath_id, :match => ExactMatch.from( message ), :actions => ActionOutput.new( :port => port_no ) ) end # Controller-to-Switch Send-Packet def packet_out datapath_id, message, port_no send_packet_out( datapath_id, :packet_in => message, :actions => ActionOutput.new( :port => port_no ) ) end end
実行する
trema run ofc1.rb
--
以上
0 件のコメント:
コメントを投稿