= Part 2 Design and Setup = == 1 Write Application for !OpenFlow Statistics Measurement == === 1.1 Get Flow Statistics you want to measure === Define stats_reply in /root/learning-switch-copy.rb as follows {{{ def stats_reply (dpid, message) puts "[flow stats_reply #{@my_switch}]---------------------------------" byte_count = 0 packet_count = 0 flow_count = 0 throughput = 0 inst_throughput =0 total_flow_count = message.stats.length if(total_flow_count != 0) message.stats.each do | flow_msg | # WARNING: This only works for the EXACT case of two actions. If we add more than two actions the flow monitoring # will break. flow_ip = flow_msg.match puts "This is the message #{flow_ip.nw_src}" flow_count = flow_count + 1 byte_count += flow_msg.byte_count packet_count += flow_msg.packet_count if flow_msg.duration_sec + flow_msg.duration_nsec/1000000000 != 0 throughput += flow_msg.byte_count/(flow_msg.duration_sec + flow_msg.duration_nsec/1000000000) file = File.open("/tmp/flowstats.out", "a") file.puts "#{flow_ip.nw_src} #{flow_count.to_s} #{byte_count} #{packet_count} #{throughput} Bps" file.close end end end @prev_byte_count = byte_count end }}} === 1.2 Define Flow Statistics measurement points === {{{ class MPThroughput < OML4R::MPBase name :ofthroughput param :srcaddr, :type => :string param :numflows, :type => :int64 param :numbytes, :type => :int64 param :numpacket, :type => :int64 param :throughput, :type => :int64 param :units, :type => :string end }}} === 1.3 Parse Measurement Fields === {{{ def processOutput(output) column = output.split(" ") puts "Each line process" # Inject the measurements into OML MPThroughput.inject("#{column[0]}", column[1], column[2], column[3], column[4], "#{column[5]}") end }}} === 1.4 Write application Script === {{{ !/usr/bin/env ruby require 'rubygems' require 'oml4r' require 'file-tail' APPNAME = "ofstats" class MPThroughput < OML4R::MPBase name :ofthroughput param :srcaddr, :type => :string param :numflows, :type => :int64 param :numbytes, :type => :int64 param :numpacket, :type => :int64 param :throughput, :type => :int64 param :units, :type => :string end class OFStatsWrapper def initialize(args) @addr = nil @if_num = ' ' @trema_port = ' ' @trema_path = ' ' @verbose = true @numeric = ' ' OML4R::init(args, :appName => "#{APPNAME}_wrapper", :domain => 'foo', :collect => 'file:-') { |argParser| argParser.banner = "Reports OpenFlow stat measurements via OML\n\n" argParser.on("-f" , "--file_path ADDRESS", "Path where output is saved"){ |address| @addr = address } argParser.on("-i","--interface IFNUM","Interface number"){ |if_num| @if_num ="#{if_num.to_i()}" } argParser.on("-q", "--no-quiet ","Don't show of stats output on console"){ @verbose = false } argParser.on("-n", "--[no]-numeric ", "No attempt twill be made to look up symbolic names for host addresses"){ @numeric ='-n' } } unless @addr !=nil raise "You did not specify path of file (-p option)" end end class MyFile < File include File::Tail end def start() log = MyFile.new("#{@addr}") log.interval = @if_num log.backward(3) puts "#{@if_num}" log.tail { |line| print line processOutput(line) } end def processOutput(output) column = output.split(" ") puts "Each line process" # Inject the measurements into OML MPThroughput.inject("#{column[0]}", column[1], column[2], column[3], column[4], "#{column[5]}") end end begin app = OFStatsWrapper.new(ARGV) app.start() rescue SystemExit rescue SignalException puts "OFWrapper stopped." rescue Exception => ex puts "Error - When executing the wrapper application!" puts "Error - Type: #{ex.class}" puts "Error - Message: #{ex}\n\n" # Uncomment the next line to get more info on errors # puts "Trace - #{ex.backtrace.join("\n\t")}" end OML4R::close() # Local Variables: # mode:ruby # End: # vim: ft=ruby:sw=2 }}} == 2. Write OEDL Script to run in !LabWiki == === 2.1 Define Resource name === Here you will identify the nodes you used for the tutorial as a combination of the {{{ defProperty('source1', "switch1-rspecforMax", "ID of a resource") defProperty('source2', "switch2-rspecforMax", "ID of a resource") defProperty('source3', "switch1-rspecforMax", "ID of a resource") defProperty('theSender1', "nodeb-rspecforMax", "ID of a resource") defProperty('theSender2', "nodec-rspecforMax", "ID of a resource") defProperty('theSender3', "noded-rspecforMax", "ID of a resource") defProperty('theSender4', "nodec-rspecforMax", "ID of a resource") defProperty('theSender5', "nodee-rspecforMax", "ID of a resource") defProperty('theReceiver', "nodef-rspecforMax", "ID of a resource") }}} === 2.2 Specify the location where Flow Statistics will be stored === {{{ defProperty('pathfile', "/tmp/flowstats.out", "Path to file") }}} === 2.3 Define the Application created in Step 1) in OEDL === {{{ defApplication('ofstats') do |app| app.description = 'Simple Definition for the of-collect application' # Define the path to the binary executable for this application app.binary_path = '/usr/local/bin/learn_ofcollect.rb' app.defProperty('target', 'Address to output file', '-f', {:type => :string}) app.defProperty("interval","Interval",'-i', {:type => :string}) app.defMeasurement('wrapper_ofthroughput') do |m| m.defMetric(':srcaddr', :string) m.defMetric('throughput',:int64) end end }}} === 2.4 Create Node Group with Application === {{{ defGroup('Source3', property.source1) do |node| node.addApplication("ofstats") do |app| app.setProperty('target', property.pathfile) app.setProperty('interval', property.intervalcol) app.measure('wrapper_ofthroughput', :samples => 1) end end }}} === 2.5 Define parameters for graphs === {{{ defGraph 'Throughput' do |g| g.ms('wrapper_ofthroughput').select(:oml_ts_client, :throughput, :srcaddr) g.caption "Throughput of Flows" g.type 'line_chart3' g.mapping :x_axis => :oml_ts_client, :y_axis => :throughput, :group_by => :srcaddr g.xaxis :legend => 'oml_ts' g.yaxis :legend => 'Throughput', :ticks => {:format => 's'} end }}} = [wiki:GENIFIRE/Labwiki/Execute Next: Run Experiment] =