1 | | |
2 | | |
3 | | == 1.1 !OpenFlow Statistics Measurement == |
4 | | |
5 | | ofcollect.rb |
6 | | {{{ |
7 | | |
8 | | #!/usr/bin/env ruby |
| 1 | = Module E Design and Setup = |
| 2 | |
| 3 | == 1 Write Application for !OpenFlow Statistics Measurement == |
| 4 | |
| 5 | === 1.1 Get Flow Statistics you want to measure === |
| 6 | |
| 7 | Define stats_reply in /root/learning-switch-copy.rb as follows |
| 8 | |
| 9 | |
| 10 | {{{ |
| 11 | def stats_reply (dpid, message) |
| 12 | puts "[flow stats_reply #{@my_switch}]---------------------------------" |
| 13 | byte_count = 0 |
| 14 | packet_count = 0 |
| 15 | flow_count = 0 |
| 16 | throughput = 0 |
| 17 | inst_throughput =0 |
| 18 | total_flow_count = message.stats.length |
| 19 | if(total_flow_count != 0) |
| 20 | message.stats.each do | flow_msg | |
| 21 | # WARNING: This only works for the EXACT case of two actions. If we add more than two actions the flow monitoring |
| 22 | # will break. |
| 23 | flow_ip = flow_msg.match |
| 24 | puts "This is the message #{flow_ip.nw_src}" |
| 25 | flow_count = flow_count + 1 |
| 26 | byte_count += flow_msg.byte_count |
| 27 | packet_count += flow_msg.packet_count |
| 28 | if flow_msg.duration_sec + flow_msg.duration_nsec/1000000000 != 0 |
| 29 | throughput += flow_msg.byte_count/(flow_msg.duration_sec + flow_msg.duration_nsec/1000000000) |
| 30 | file = File.open("/tmp/flowstats.out", "a") |
| 31 | file.puts "#{flow_ip.nw_src} #{flow_count.to_s} #{byte_count} #{packet_count} #{throughput} Bps" |
| 32 | file.close |
| 33 | end |
| 34 | end |
| 35 | end |
| 36 | @prev_byte_count = byte_count |
| 37 | end |
| 38 | |
| 39 | }}} |
| 40 | |
| 41 | === 1.2 Define Flow Statistics measurement points === |
| 42 | |
| 43 | {{{ |
| 44 | class MPThroughput < OML4R::MPBase |
| 45 | name :ofthroughput |
| 46 | param :srcaddr, :type => :string |
| 47 | param :numflows, :type => :int64 |
| 48 | param :numbytes, :type => :int64 |
| 49 | param :numpacket, :type => :int64 |
| 50 | param :throughput, :type => :int64 |
| 51 | param :units, :type => :string |
| 52 | end |
| 53 | }}} |
| 54 | |
| 55 | === 1.3 Parse Measurement Fields === |
| 56 | |
| 57 | {{{ |
| 58 | def processOutput(output) |
| 59 | column = output.split(" ") |
| 60 | puts "Each line process" |
| 61 | # Inject the measurements into OML |
| 62 | MPThroughput.inject("#{column[0]}", column[1], column[2], column[3], column[4], "#{column[5]}") |
| 63 | end |
| 64 | }}} |
| 65 | |
| 66 | === 1.4 Write application Script === |
| 67 | {{{ |
| 68 | |
| 69 | !/usr/bin/env ruby |
84 | | OEDL script |
85 | | {{{ |
86 | | |
87 | | defProperty('source1', "nowcastbox-sdxdemo", "ID of a resource") |
88 | | defProperty('intervalcol',"1", "Interval to Tail") |
89 | | |
| 141 | == 2. Write OEDL Script to run in LabWiki == |
| 142 | |
| 143 | |
| 144 | === 2.1 Define Resource name === |
| 145 | |
| 146 | Here you will identify the nodes you used for the tutorial as a combination of the <node-slicename> |
| 147 | |
| 148 | |
| 149 | {{{ |
| 150 | defProperty('source1', "switch1-rspecforMax", "ID of a resource") |
| 151 | defProperty('source2', "switch2-rspecforMax", "ID of a resource") |
| 152 | defProperty('source3', "switch1-rspecforMax", "ID of a resource") |
| 153 | defProperty('theSender1', "nodeb-rspecforMax", "ID of a resource") |
| 154 | defProperty('theSender2', "nodec-rspecforMax", "ID of a resource") |
| 155 | defProperty('theSender3', "noded-rspecforMax", "ID of a resource") |
| 156 | defProperty('theSender4', "nodec-rspecforMax", "ID of a resource") |
| 157 | defProperty('theSender5', "nodee-rspecforMax", "ID of a resource") |
| 158 | defProperty('theReceiver', "nodef-rspecforMax", "ID of a resource") |
| 159 | }}} |
| 160 | |
| 161 | === 2.2 Specify the location where Flow Statistics will be stored === |
| 162 | |
| 163 | {{{ |
113 | | |
| 195 | }}} |
| 196 | |
| 197 | === 2.5 Define parameters for graphs === |
| 198 | |
| 199 | {{{ |
| 200 | defGraph 'Throughput' do |g| |
| 201 | g.ms('wrapper_ofthroughput').select(:oml_ts_client, :throughput, :srcaddr) |
| 202 | g.caption "Throughput of Flows" |
| 203 | g.type 'line_chart3' |
| 204 | g.mapping :x_axis => :oml_ts_client, :y_axis => :throughput, :group_by => :srcaddr |
| 205 | g.xaxis :legend => 'oml_ts' |
| 206 | g.yaxis :legend => 'Throughput', :ticks => {:format => 's'} |
| 207 | end |
| 208 | |
| 209 | }}} |
| 210 | |
| 211 | === 2.5 The complete OEDL script is given Below === |
| 212 | |
| 213 | OEDL script |
| 214 | {{{ |
| 215 | |
| 216 | defProperty('source1', "switch1-rspecforMax", "ID of a resource") |
| 217 | defProperty('source2', "switch2-rspecforMax", "ID of a resource") |
| 218 | defProperty('source3', "switch1-rspecforMax", "ID of a resource") |
| 219 | defProperty('theSender1', "nodeb-rspecforMax", "ID of a resource") |
| 220 | defProperty('theSender2', "nodec-rspecforMax", "ID of a resource") |
| 221 | defProperty('theSender3', "noded-rspecforMax", "ID of a resource") |
| 222 | defProperty('theSender4', "nodec-rspecforMax", "ID of a resource") |
| 223 | defProperty('theSender5', "nodee-rspecforMax", "ID of a resource") |
| 224 | defProperty('theReceiver', "nodef-rspecforMax", "ID of a resource") |
| 225 | |
| 226 | defProperty('intervalcol',"1", "Interval to Tail") |
| 227 | |
| 228 | defProperty('pathfile', "/tmp/flowstats.out", "Path to file") |
| 229 | |
| 230 | defApplication('ofstats') do |app| |
| 231 | app.description = 'Simple Definition for the of-collect application' |
| 232 | # Define the path to the binary executable for this application |
| 233 | app.binary_path = '/usr/local/bin/learn_ofcollect.rb' |
| 234 | app.defProperty('target', 'Address to output file', '-f', {:type => :string}) |
| 235 | app.defProperty("interval","Interval",'-i', {:type => :string}) |
| 236 | app.defMeasurement('wrapper_ofthroughput') do |m| |
| 237 | m.defMetric(':srcaddr', :string) |
| 238 | m.defMetric('throughput',:int64) |
| 239 | end |
| 240 | end |
| 241 | defApplication('trema') do |app| |
| 242 | app.description = 'This app runs trema from command line' |
| 243 | app.binary_path = '/usr/bin/trema run /root/learning-switch.rb' |
| 244 | end |
| 245 | |
| 246 | defApplication('iperfserv') do |app| |
| 247 | app.description = "manually run Iperf server" |
| 248 | app.binary_path = "/usr/bin/iperf -s" |
| 249 | end |
| 250 | defApplication('iperfclient') do |app| |
| 251 | app.description = "manually run Iperf client" |
| 252 | app.binary_path = "/usr/bin/iperf -c 192.168.1.15 -t 800 -P 2 -i 2" |
| 253 | end |
| 254 | defApplication('clean_iperf') do |app| |
| 255 | app.description = 'Some commands to ensure that we start with a clean slate' |
| 256 | app.binary_path = 'killall -s9 iperf' |
| 257 | app.quiet = true |
| 258 | end |
| 259 | defGroup('Source2', property.source1,property.source2) do |node| |
| 260 | node.addApplication("trema") |
| 261 | end |
| 262 | defGroup('Source3', property.source1) do |node| |
| 263 | node.addApplication("ofstats") do |app| |
| 264 | app.setProperty('target', property.pathfile) |
| 265 | app.setProperty('interval', property.intervalcol) |
| 266 | app.measure('wrapper_ofthroughput', :samples => 1) |
| 267 | end |
| 268 | end |
| 269 | defGroup('Sender1', property.theSender1) do |node| |
| 270 | node.addApplication("iperfclient") do |app| |
| 271 | end |
| 272 | end |
| 273 | defGroup('Sender2', property.theSender2) do |node| |
| 274 | node.addApplication("iperfclient") do |app| |
| 275 | end |
| 276 | end |
| 277 | defGroup('Sender3', property.theSender3) do |node| |
| 278 | node.addApplication("iperfclient") do |app| |
| 279 | end |
| 280 | end |
| 281 | defGroup('Sender4', property.theSender4) do |node| |
| 282 | node.addApplication("iperfclient") do |app| |
| 283 | end |
| 284 | end |
| 285 | defGroup('Sender5', property.theSender5) do |node| |
| 286 | node.addApplication("iperfclient") do |app| |
| 287 | end |
| 288 | end |
| 289 | defGroup('Receiver', property.theReceiver) do |node| |
| 290 | node.addApplication("iperfserv") do |app| |
| 291 | end |
| 292 | end |