wiki:GEC22Agenda/LabWiki/ModuleE/DesignSetup

Version 1 (modified by divyashri.bhat@gmail.com, 9 years ago) (diff)

--

Module E 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. This file is the Trema controller script which we ran in ModuleC. For the purpose of this tutorial, the modified script has been downloaded into switch1 prior to this tutorial.
You can find this file in the node called switch1. If you need help with logging in to your nodes, please refer How To Login.

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

We now proceed to write the application which collects the measurement points defined in the controller code above.
The complete script is already pre-loaded into the node switch1 at /usr/local/bin/learn_ofcollect.rb. The steps provided here are for your reference.

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

This script is used to orchestrate the OML application we just wrote. It is pre-loaded into your LabWiki directory as GEC20_flowstatistics.oedl.
The steps provided here are for your reference.

2.1 Define Resource name

Here you will identify the nodes you used for the tutorial as a combination of the <node-slicename>

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

Next: Run Experiment

Module E Introduction