Version 19 (modified by 10 years ago) (diff) | ,
---|
How to use OML4R to write your OML application
1. Setup your Application
1.1 Download and build the tar file of your application
sudo su wget http://www.gpolab.bbn.com/experiment-support/gec17/pingPlus/pingPlus_v3.tar.gz tar xvzf pingPlus_v3.tar.gz cd pingPlus_v3 make
1.2 Test connectivity
On the receiver
chmod +x pingPlusListener ping -c 5 10.10.10.1 ifconfig eth1 0.0.0.0 ping -c 5 10.10.10.1 ./pingPlusListener 10002
The format for the pingPlusListener is sudo ./pingPlusListener <EtherType>
On the sender
ping -c 5 10.10.10.2 ifconfig eth1 0.0.0.0 ping -c 5 10.10.10.2 chmod +x pingPlus ./pingPlus 02:26:ae:0e:9b:3e eth1 10002
The format for the sender is
./pingPlus <server mac> <client i/f name> <EtherType> <count>
1. Observe your Output
root@sender:/users/dbhat/pingPlus_v3# ./pingPlus 02:26:ae:0e:9b:3e eth1 10002 5 RQ:'9641+4173' to 2:26:ae:e:9b:3e. RL:9641+4173=13814 from 2:26:ae:e:9b:3e. RTT = 0.920166 RQ:'2271+7533' to 2:26:ae:e:9b:3e. RL:2271+7533=9804 from 2:26:ae:e:9b:3e. RTT = 0.654053 RQ:'8858+353' to 2:26:ae:e:9b:3e. RL:8858+353=9211 from 2:26:ae:e:9b:3e. RTT = 0.489014 RQ:'447+5696' to 2:26:ae:e:9b:3e. RL:447+5696=6143 from 2:26:ae:e:9b:3e. RTT = 0.290039 RQ:'7238+5082' to 2:26:ae:e:9b:3e. RL:7238+5082=12320 from 2:26:ae:e:9b:3e. RTT = 0.252930
2. Write your OML Application
2.1 Write your OML Parser
def process_output(row) if not (parse= /RQ:'(?<pktsnt1>\d*)\+(?<pktsnt2>\d*)' to (?<host>[a-f0-9:]*)/.match(row)).nil? puts "ReturnQual #{parse[:pktsnt1]}\n" MPrt.inject(parse[:pktsnt1], parse[:pktsnt2],parse[:host]) elsif not (parse= /RL:(?<numofpkt1>\d*)\+(?<numofpkt2>\d*)=(?<totpktrec>\d*) from (?<dest_hw_addr>[a-f0-9:]*)/.match(row)).nil? puts "ReturnLength\n" p parse p MPrl.inject(parse[:numofpkt1],parse[:numofpkt2],parse[:totpktrec],parse[:dest_hw_addr]) elsif not (parse = /RTT = (?<rtt>[0-9.]*)/.match(row)).nil? puts "RoundTripTime #{parse[:rtt]}\n" p parse p MPrtt.inject(parse[:rtt]) end end
2.2 Write your OML Application
Define all varying parameters as properties that can be set within your Application.
Save the following code to any location on your node. E.g /usr/local/bin/pingl2.rb
#!/usr/bin/ruby1.9.1 require 'rubygems' require 'oml4r' class MPrt < OML4R::MPBase name :pingrt param :pktsnt1, :type => :uint64 param :pktsnt2, :type => :uint64 param :host, :type => :string end class MPrl < OML4R::MPBase name :pingrl param :totpktrec, :type => :uint64 param :numofpkt1, :type => :uint64 param :numofpkt2, :type => :uint64 param :dest_hw_addr, :type => :string end class MPrtt < OML4R::MPBase name :pingrtt param :rtt, :type => :double end class Pingl2Wrapper def initialize(args) @addr = nil @if_num = '' @eth = nil @verbose = true @numeric = '' leftover = OML4R::init(args, :appName => 'pingl2') do |argParser| argParser.banner = "Runs layer 2 ping and reports measurements via OML\n\n" argParser.on("-a" , "--dest_hw_addr ADDRESS", "Hardware address to ping (the -a switch is optional)"){ |address| @addr = address.to_s() } argParser.on("-i","--interface IFNUM","Interface number"){ |if_num| @if_num ="#{if_num.to_i()}" } argParser.on("-e", "--eth ETHTYPE","Ethernet Type") { |ethtype| @eth = ethtype.to_s() } argParser.on("-c","--count NUMBER","Number of pings (default: infinite)"){ |count| @count = "#{count.to_i()}"} argParser.on("-q", "--no-quiet ","Don't show layer 2 ping 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' } end if @addr.nil? if leftover.length > 0 @addr = leftover [0] else raise "You did not specify an address to ping!" end end end def process_output(row) if not (parse= /RQ:'(?<pktsnt1>\d*)\+(?<pktsnt2>\d*)' to (?<host>[a-f0-9:]*)/.match(row)).nil? puts "ReturnQual #{parse[:pktsnt1]}\n" MPrt.inject(parse[:pktsnt1], parse[:pktsnt2],parse[:host]) elsif not (parse= /RL:(?<numofpkt1>\d*)\+(?<numofpkt2>\d*)=(?<totpktrec>\d*) from (?<dest_hw_addr>[a-f0-9:]*)/.match(row)).nil? puts "ReturnLength\n" p parse p MPrl.inject(parse[:numofpkt1],parse[:numofpkt2],parse[:totpktrec],parse[:dest_hw_addr]) elsif not (parse = /RTT = (?<rtt>[0-9.]*)/.match(row)).nil? puts "RoundTripTime #{parse[:rtt]}\n" p parse p MPrtt.inject(parse[:rtt]) end end def pingl2() @pingio = IO.popen("/bin/pingPlus #{@addr} #{@eth} #{@if_num} #{@count}") while true row = @pingio.readline puts row if @verbose process_output(row) end end def start() return if not @pingio.nil? # handle for OMF's exit command a = Thread.new do $stdin.each do |line| if /^exit/ =~ line Process.kill("INT",0) end end end # Handle Ctrl+C and OMF's SIGTERM Signal.trap("INT", stop) Signal.trap("TERM", stop) begin pingl2 rescue EOFError end end def stop() return if @pingio.nil? # Kill the ping process, which will result in EOFError from ping() Process.kill("INT", @pingio.pid) end end begin $stderr.puts "INFO\tpingl2 2.11.0\n" app = Pingl2Wrapper.new(ARGV) app.start() sleep 1 rescue Interrupt rescue Exception => ex $stderr.puts "Error\t#{ex}\n" end # Local Variables: # mode:ruby # End: # vim: ft=ruby:sw=2
3. Instrument your Application using LabWiki
3.1 Copy binaries and set permissions
cp pingPlusListener /bin cp ping2.rb /usr/local/bin chmod +x /bin/pingPluListener chmod +x /usr/local/bin/pingl2.rb
3.2 Write your LabWiki Application
3.2.1 Edit and save a Markdown and Experiment Script in the Prepare Window
Markdown Script
#Example: Writing an OML Layer 2 Ping Application (aka pingPlus)# ##Prerequisites## Setup your experiment as shown here with the pingPlus package [link](http://www.gpolab.bbn.com/experiment-support/gec17/pingPlus/pingPlus_v3.tar.gz): http://groups.geni.net/geni/wiki/Tutorials/ICDCS2013/GettingStartedWithGENI_I/Procedure/DesignSetup ##Results## ![](_) __Figure 1__. My layer 2 Ping Application ##Write your Application## To write a omlified ping application, we can firstly parse output to get Measurement points: def process_output(row) if not (parse= /RQ:'(?<pktsnt1>\d*)\+(?<pktsnt2>\d*)' to (?<host>[a-f0-9:]*)/.match(row)).nil? puts "ReturnQual #{parse[:pktsnt1]}\n" MPrt.inject(parse[:pktsnt1], parse[:pktsnt2],parse[:host]) elsif not (parse= /RL:(?<numofpkt1>\d*)\+(?<numofpkt2>\d*)=(?<totpktrec>\d*) from (?<dest_hw_addr>[a-f0-9:]*)/.match(row)).nil? puts "ReturnLength\n" p parse p MPrl.inject(parse[:numofpkt1],parse[:numofpkt2],parse[:totpktrec],parse[:dest_hw_addr]) elsif not (parse = /RTT = (?<rtt>[0-9.]*)/.match(row)).nil? puts "RoundTripTime #{parse[:rtt]}\n" p parse p MPrtt.inject(parse[:rtt]) end end Then write the whole application script: #!/usr/bin/ruby1.9.1 require 'rubygems' require 'oml4r' class MPrt < OML4R::MPBase name :pingrt param :pktsnt1, :type => :uint64 param :pktsnt2, :type => :uint64 param :host, :type => :string end class MPrl < OML4R::MPBase name :pingrl param :totpktrec, :type => :uint64 param :numofpkt1, :type => :uint64 param :numofpkt2, :type => :uint64 param :dest_hw_addr, :type => :string end class MPrtt < OML4R::MPBase name :pingrtt param :rtt, :type => :double end class Pingl2Wrapper def initialize(args) @addr = nil @if_num = '' @eth = nil @verbose = true @numeric = '' leftover = OML4R::init(args, :appName => 'pingl2') do |argParser| argParser.banner = "Runs layer 2 ping and reports measurements via OML\n\n" argParser.on("-a" , "--dest_hw_addr ADDRESS", "Hardware address to ping (the -a switch is optional)"){ |address| @addr = address.to_s() } argParser.on("-i","--interface IFNUM","Interface number"){ |if_num| @if_num ="#{if_num.to_i()}" } argParser.on("-e", "--eth ETHTYPE","Ethernet Type") { |ethtype| @eth = ethtype.to_s() } argParser.on("-c","--count NUMBER","Number of pings (default: infinite)"){ |count| @count = "#{count.to_i()}"} argParser.on("-q", "--no-quiet ","Don't show layer 2 ping 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' } end if @addr.nil? if leftover.length > 0 @addr = leftover [0] else raise "You did not specify an address to ping!" end end end def process_output(row) if not (parse= /RQ:'(?<pktsnt1>\d*)\+(?<pktsnt2>\d*)' to (?<host>[a-f0-9:]*)/.match(row)).nil? puts "ReturnQual #{parse[:pktsnt1]}\n" MPrt.inject(parse[:pktsnt1], parse[:pktsnt2],parse[:host]) elsif not (parse= /RL:(?<numofpkt1>\d*)\+(?<numofpkt2>\d*)=(?<totpktrec>\d*) from (?<dest_hw_addr>[a-f0-9:]*)/.match(row)).nil? puts "ReturnLength\n" p parse p MPrl.inject(parse[:numofpkt1],parse[:numofpkt2],parse[:totpktrec],parse[:dest_hw_addr]) elsif not (parse = /RTT = (?<rtt>[0-9.]*)/.match(row)).nil? puts "RoundTripTime #{parse[:rtt]}\n" p parse p MPrtt.inject(parse[:rtt]) end end def pingl2() @pingio = IO.popen("/bin/pingPlus #{@addr} #{@eth} #{@if_num} #{@count}") while true row = @pingio.readline puts row if @verbose process_output(row) end end def start() return if not @pingio.nil? # handle for OMF's exit command a = Thread.new do $stdin.each do |line| if /^exit/ =~ line Process.kill("INT",0) end end end # Handle Ctrl+C and OMF's SIGTERM Signal.trap("INT", stop) Signal.trap("TERM", stop) begin pingl2 rescue EOFError end end def stop() return if @pingio.nil? # Kill the ping process, which will result in EOFError from ping() Process.kill("INT", @pingio.pid) end end begin $stderr.puts "INFO\tpingl2 2.11.0\n" app = Pingl2Wrapper.new(ARGV) app.start() sleep 1 rescue Interrupt rescue Exception => ex $stderr.puts "Error\t#{ex}\n" end # Local Variables: # mode:ruby # End: # vim: ft=ruby:sw=2 ##Test your Application## Finally write OEDL Script to test application: defProperty('source1', "client-testpingplus", "ID of a resource") #defProperty('source2', "ig-utah-testBBN", "ID of a resource") #defProperty('source3', "nodeC-createexoimage", "ID of a resource") #defProperty('source4', "nodeD-createexoimage", "ID of a resource") #defProperty('source5', "nodeE-createexoimage", "ID of a resource") defProperty('graph', true, "Display graph or not") defProperty('sinkaddr11', 'fe:16:3e:00:74:38', "Ping destination address") defProperty('eth11','eth1',"Output Eth interface") defProperty('sinkaddr12', 'fe:16:3e:00:74:38', "Ping destination address") #defProperty('sinkaddr11', '192.168.6.10', "Ping destination address") #defProperty('sinkaddr12', '192.168.5.12', "Ping destination address") #defProperty('sinkaddr21', '192.168.4.11', "Ping destination address") #defProperty('sinkaddr22', '192.168.2.12', "Ping destination address") #defProperty('sinkaddr23', '192.168.1.13', "Ping destination address") #defProperty('sinkaddr31', '192.168.5.11', "Ping destination address") #defProperty('sinkaddr32', '192.168.2.10', "Ping destination address") #defProperty('sinkaddr33', '192.168.3.13', "Ping destination address") #defProperty('sinkaddr34', '192.168.6.14', "Ping destination address") #defProperty('sinkaddr41', '192.168.1.10', "Ping destination address") #defProperty('sinkaddr42', '192.168.3.12', "Ping destination address") #defProperty('sinkaddr51', '192.168.6.12', "Ping destination address") defApplication('ping') do |app| app.description = 'Simple Definition for the pingl2 application' # Define the path to the binary executable for this application app.binary_path = '/usr/local/bin/pingl2' # Define the configurable parameters for this application # For example if target is set to foo.com and count is set to 2, then the # application will be started with the command line: # /usr/bin/ping-oml2 -a foo.com -c 2 app.defProperty('target', 'Address to ping', '-a', {:type => :string}) app.defProperty('count', 'Number of times to ping', '-c', {:type => :integer}) app.defProperty('if_num', 'interface number', '-i', {:type => :integer}) app.defProperty('eth', 'Ethernet Type', '-e', {:type => :string}) # Define the OML2 measurement point that this application provides. # Here we have only one measurement point (MP) named 'ping'. Each measurement # sample from this MP will be composed of a 4-tuples (addr,ttl,rtt,rtt_unit) app.defMeasurement('ping') do |m| m.defMetric('hw_dest_addr',:string) m.defMetric('rtt',:double) end end defGroup('Source1', property.source1) do |node| node.addApplication("ping") do |app| app.setProperty('target', property.sinkaddr11) app.setProperty('count', 30) app.setProperty('if_num', 10002) app.setProperty('eth',property.eth11) app.measure('ping', :samples => 1) end end #defGroup('Source2', property.source2) do |node| # node.addApplication("ping") do |app| # app.setProperty('target', property.sinkaddr11) # app.setProperty('count', 30) #app.setProperty('interval', 1) # app.measure('ping', :samples => 1) #end #end onEvent(:ALL_UP_AND_INSTALLED) do |event| info "Starting the ping" after 5 do allGroups.startApplications end after 70 do info "Stopping the ping" allGroups.stopApplications Experiment.done end end defGraph 'RTT' do |g| g.ms('ping').select(:oml_seq, :hw_dest_addr, :rtt) g.caption "RTT of received packets." g.type 'line_chart3' g.mapping :x_axis => :oml_seq, :y_axis => :rtt, :group_by => :hw_dest_addr g.xaxis :legend => 'oml_seq' g.yaxis :legend => 'rtt', :ticks => {:format => 's'} end ##Troubleshooting## To debug and test application manually on RC (resource controller): Manually run the command and store data on any location in the RC (~/testpingnow.out) env -i /usr/local/bin/pingl2 -a fe:16:3e:00:74:38 -c 5 -i 10002 -e eth1 --oml-id pingl2 --oml-domain tetspingl2 --oml-collect file:/home/dbhat/testpingnow.out Contents of ~/testpingnow.out: protocol: 4 content: text domain: tetspingl2 start-time: 1387350654 sender-id: pingl2 app-name: pingl2 schema: 0 _experiment_metadata subject:string key:string value:string schema: 1 pingl2_pingrt pktsnt1:integer pktsnt2:integer host:string schema: 2 pingl2_pingrl totpktrec:integer numofpkt1:integer numofpkt2:integer dest_hw_addr:string schema: 3 pingl2_pingrtt rtt:double 0.008326062 1 1 8769 3486 fe:16:3e:0:74:38 0.008561018 2 1 8769 3486 12255 fe:16:3e:0:74:38 0.008747358 3 1 4.083984 0.008879672 1 2 219 3026 fe:16:3e:0:74:38 0.009011919 2 2 8769 3486 12255 fe:16:3e:0:74:38 0.009165199 3 2 1.743896
3.2.2 Copy the following script into the Prepare Window
OEDL Script
defProperty('source1', "sender-gimiinsta", "ID of a resource") defProperty('sinkaddr11', '02:ee:1a:a2:51:11', "Ping destination address") defProperty('eth11','eth1',"Output Eth interface") defApplication('pingl2') do |app| app.description = 'Simple Definition for the pingl2 application' # Define the path to the binary executable for this application app.binary_path = '/usr/local/bin/pingl2.rb' # Define the configurable parameters for this application # For example if target is set to foo.com and count is set to 2, then the # application will be started with the command line: # /usr/bin/ping-oml2 -a macaddress -c 2 app.defProperty('target', 'Address to ping', '-a', {:type => :string}) app.defProperty('count', 'Number of times to ping', '-c', {:type => :integer}) app.defProperty('if_num', 'interface number', '-i', {:type => :integer}) app.defProperty('eth', 'Ethernet Type', '-e', {:type => :string}) # Define the OML2 measurement point that this application provides. app.defMeasurement('pingrl') do |m| m.defMetric('dest_hw_addr',:string) end app.defMeasurement('pingrtt') do |m| m.defMetric('rtt',:double) end end defGroup('Source1', property.source1) do |node| node.addApplication("pingl2") do |app| app.setProperty('target', property.sinkaddr11) app.setProperty('count', 30) app.setProperty('if_num', 10002) app.setProperty('eth',property.eth11) app.measure('pingrl', :samples => 1) app.measure('pingrtt', :samples => 1) end end onEvent(:ALL_UP_AND_INSTALLED) do |event| info "Starting the ping" after 5 do allGroups.startApplications end after 70 do info "Stopping the ping" allGroups.stopApplications Experiment.done end end defGraph 'RTT' do |g| g.ms('pingrtt').select(:rtt__oml_seq, :rtt__rtt, :rl__dest_hw_addr)\ .from(:pingl2_pingrtt___rtt, :pingl2_pingrl___rl)\ .where(:rtt__oml_seq => :rl__oml_seq) g.caption "RTT of received packets." g.type 'line_chart3' g.mapping :x_axis => :oml_seq, :y_axis => :rtt, :group_by => :dest_hw_addr g.xaxis :legend => 'oml_seq' g.yaxis :legend => 'rtt', :ticks => {:format => 's'} end defGraph 'RTT2' do |g| g.ms('pingrtt').select(:rtt__oml_seq, :rtt__rtt, :rl__dest_hw_addr)\ .from(:pingl2_pingrtt___rtt, :pingl2_pingrl___rl)\ .where(:rtt__oml_seq => :rl__oml_seq) g.caption "RTT of received packets." g.type 'histogram2' g.mapping :value => :rtt, :group_by => :dest_hw_addr g.xaxis :legend => 'RTT [ms]' g.yaxis :legend => 'Density [%]' end
3.2.3 Start your application from LabWiki
Attachments (4)
- markdown.png (337.9 KB) - added by 10 years ago.
- graphresults.png (430.0 KB) - added by 10 years ago.
- editscriptLW.png (286.3 KB) - added by 10 years ago.
- pingedit.png (289.4 KB) - added by 10 years ago.
Download all attachments as: .zip