blob: 9549da53a3e71e6a10b59b141446c350bb209130 [file] [log] [blame]
Brian O'Connor477ddbe2013-12-09 18:35:18 -08001#!/usr/bin/python
2'''
3 Script that tests Flow Synchronizer performance
4 Author: Brian O'Connor <bocon@onlab.us>
5
6 Usage:
7 1. Ensure that ONOS is running
8 2.
9'''
10
11import csv
12import os
Brian O'Connorb405d082013-12-09 19:45:58 -080013import sys
Brian O'Connor477ddbe2013-12-09 18:35:18 -080014from time import sleep, strftime
15from subprocess import Popen, call, check_output, PIPE
16from mininet.net import Mininet
17from mininet.topo import SingleSwitchTopo
18from mininet.node import RemoteController
19from mininet.cli import CLI
20from mininet.log import setLogLevel
21try:
22 import pexpect
23except:
24 # install pexpect if it cannot be found and re-import
25 print '* Installing Pexpect'
26 call( 'apt-get install -y python-pexpect', stdout=PIPE, shell=True )
27 import pexpect
28
Brian O'Connorb405d082013-12-09 19:45:58 -080029ONOS_HOME = '..'
30
Brian O'Connor477ddbe2013-12-09 18:35:18 -080031# Verify that tcpkill is installed
Brian O'Connorb405d082013-12-09 19:45:58 -080032if not Popen( 'which tcpkill', stdout=PIPE, shell=True).communicate():
Brian O'Connor477ddbe2013-12-09 18:35:18 -080033 print '* Installing tcpkill'
34 call( 'apt-get install -y dsniff', stdout=PIPE, shell=True )
35
36# ----------------- Tests scenarios -------------------------
37def doNothing(n):
38 print "Doing nothing with %d flows..." % n
39
40def addFakeFlows(n):
41 print "Adding %d random flows..." % n
42 for i in range( 1, (n+1) ):
43 a = i / (256*256) % 256
44 b = i / 256 % 256
45 c = i % 256
46 ip = '10.%d.%d.%d' % (a,b,c)
47 call( 'ovs-ofctl add-flow s1 "ip, nw_src=%s/32, idle_timeout=0, hard_timeout=0, cookie=%d, actions=output:2"' % ( ip, i ), shell=True )
48
49def delFlowsFromSwitch(n):
50 print "Removing all %d flows from switch..." % n
51 call( 'ovs-ofctl del-flows s1', shell=True )
52
53
54# ----------------- Utility Functions -------------------------
55def disconnect():
56 tail = Popen( "exec tail -0f ../onos-logs/onos.onosdev1.log", stdout=PIPE, shell=True )
57 tcp = Popen( 'exec tcpkill -i lo -9 port 6633 > /dev/null 2>&1', shell=True )
58 tcp = Popen( 'exec tcpkill -i lo -9 port 6633 > /tmp/tcp 2>&1', shell=True )
59 sleep(1)
60 tcp.kill()
61 results = waitForResult(tail)
62 tail.kill()
63 return results
64
65def startNet(net):
Brian O'Connorb405d082013-12-09 19:45:58 -080066 tail = pexpect.spawn( 'tail -0f %s/onos-logs/onos.onosdev1.log' % ONOS_HOME )
Brian O'Connor477ddbe2013-12-09 18:35:18 -080067 net.start()
Brian O'Connorb405d082013-12-09 19:45:58 -080068 index = tail.expect(['Sync time \(ms\)', pexpect.EOF, pexpect.TIMEOUT])
69 if index >= 1:
70 print '* ONOS not started'
71 net.stop()
72 exit(1)
73 tail.terminate()
Brian O'Connor477ddbe2013-12-09 18:35:18 -080074
75def dumpFlows():
76 return check_output( 'ovs-ofctl dump-flows s1', shell=True )
77
78def addFlowsToONOS(n):
Brian O'Connorb405d082013-12-09 19:45:58 -080079 call( './generate_flows.py 1 %d > /tmp/flows.txt' % n, shell=True )
80 call( '%s/web/add_flow.py -m onos -f /tmp/flows.txt' % ONOS_HOME, shell=True )
Brian O'Connor477ddbe2013-12-09 18:35:18 -080081 while True:
82 output = check_output( 'ovs-ofctl dump-flows s1', shell=True )
83 lines = len(output.split('\n'))
84 if lines >= (n+2):
85 break
86 sleep(1)
87 count = 0
88 while True:
Brian O'Connorb405d082013-12-09 19:45:58 -080089 output = pexpect.spawn( '%s/web/get_flow.py all' % ONOS_HOME )
Brian O'Connor477ddbe2013-12-09 18:35:18 -080090 while count < n:
91 if output.expect(['FlowEntry', pexpect.EOF], timeout=2000) == 1:
92 break
93 count += 1
94 return
95 sleep(5)
96
97def removeFlowsFromONOS():
Brian O'Connorb405d082013-12-09 19:45:58 -080098 call( '%s/web/delete_flow.py all' % ONOS_HOME, shell=True )
Brian O'Connor477ddbe2013-12-09 18:35:18 -080099 while True:
100 output = check_output( 'ovs-ofctl dump-flows s1', shell=True )
101 lines = len(output.split('\n'))
102 if lines == 2:
103 break
104 sleep(1)
105 while True:
Brian O'Connorb405d082013-12-09 19:45:58 -0800106 output = pexpect.spawn( '%s/web/get_flow.py all' % ONOS_HOME )
Brian O'Connor477ddbe2013-12-09 18:35:18 -0800107 if output.expect(['FlowEntry', pexpect.EOF], timeout=2000) == 1:
108 break
109 sleep(5)
110
111
112# ----------------- Running the test and output -------------------------
113def test(i, fn):
114 # Start tailing the onos log
Brian O'Connorb405d082013-12-09 19:45:58 -0800115 tail = pexpect.spawn( "tail -0f %s/onos-logs/onos.onosdev1.log" % ONOS_HOME )
Brian O'Connor477ddbe2013-12-09 18:35:18 -0800116 # disconnect the switch from the controller using tcpkill
117 tcp = Popen( 'exec tcpkill -i lo -9 port 6633 > /dev/null 2>&1', shell=True )
118 # wait until the switch has been disconnected
119 tail.expect( 'Switch removed' )
120 # call the test function
121 fn(i)
122 # dump to flows to ensure they have all made it to ovs
123 dumpFlows()
124 # end tcpkill process to reconnect the switch to the controller
125 tcp.terminate()
126 tail.expect('Sync time \(ms\):', timeout=6000)
Brian O'Connorb405d082013-12-09 19:45:58 -0800127 tail.expect('([\d.]+,?)+\s')
Brian O'Connor477ddbe2013-12-09 18:35:18 -0800128 print tail.match.group(0)
Brian O'Connor477ddbe2013-12-09 18:35:18 -0800129 tail.terminate()
130 sleep(3)
Brian O'Connorb405d082013-12-09 19:45:58 -0800131 return tail.match.group(0).strip().split(',')
132
133def initResults(files):
134 headers = ['# of FEs', 'Flow IDs from Graph', 'FEs from Switch', 'Compare',
135 'Read FE from graph', 'Extract FE', 'Push', 'Total' ]
136 for filename in files.values():
137 with open(filename, 'w') as csvfile:
138 writer = csv.writer(csvfile)
139 writer.writerow(headers)
Brian O'Connor477ddbe2013-12-09 18:35:18 -0800140
141def outputResults(filename, n, results):
142 results.insert(0, n)
143 print results
144 with open(filename, 'a') as csvfile:
145 writer = csv.writer(csvfile)
146 writer.writerow(results)
147
148def runPerf( resultDir, tests):
149 fileMap = { 'add': os.path.join(resultDir, 'add.csv'),
150 'delete': os.path.join(resultDir, 'delete.csv'),
151 'sync': os.path.join(resultDir, 'sync.csv') }
Brian O'Connorb405d082013-12-09 19:45:58 -0800152 initResults(fileMap)
Brian O'Connor477ddbe2013-12-09 18:35:18 -0800153 # start Mininet
154 topo = SingleSwitchTopo()
155 net = Mininet(topo=topo, controller=RemoteController)
156 startNet(net)
157 removeFlowsFromONOS() # clear ONOS before starting
158 sleep(30) # let ONOS "warm-up"
159 for i in tests:
160 addFlowsToONOS(i)
161 outputResults(fileMap['sync'], i, test(i, doNothing))
162 outputResults(fileMap['delete'], i, test(i, delFlowsFromSwitch))
163 removeFlowsFromONOS()
164 outputResults(fileMap['add'], i, test(i, addFakeFlows)) # test needs empty DB
165 net.stop()
166
167def waitForResult(tail):
168 while True:
169 line = tail.stdout.readline()
170 index = line.find('n.o.o.o.f.FlowSynchronizer')
171 if index > 0:
172 print line,
173 index = line.find('Sync time (ms):')
174 if index > 0:
175 line = line[index + 15:].strip()
176 line = line.replace('-->', '')
177 return line.split() # graph, switch, compare, total
178
179if __name__ == '__main__':
180 setLogLevel( 'output' )
181 resultDir = strftime( '%Y%m%d-%H%M%S' )
182 os.mkdir( resultDir )
Brian O'Connorb405d082013-12-09 19:45:58 -0800183 tests = sys.argv[1:]
184 if not tests:
185 tests = [1, 10, 100, 1000, 10000]
186 runPerf( resultDir, tests )
Brian O'Connor477ddbe2013-12-09 18:35:18 -0800187
188exit()
189
190# ---------------------------