blob: 687f91532d082de317bb5425030b42f2b716f820 [file] [log] [blame]
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2016 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07003
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070011 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20"""
Jon Hall1efcb3f2016-08-23 13:42:15 -070021import os
Jon Hall1efcb3f2016-08-23 13:42:15 -070022import time
23import json
24import urllib
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -070025import re
Jon Hall1efcb3f2016-08-23 13:42:15 -070026from core import utilities
27
28
29class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070030
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070031 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070032
Jon Hall1efcb3f2016-08-23 13:42:15 -070033 @staticmethod
34 def initTest( main ):
35 """
36 - Construct tests variables
37 - GIT ( optional )
38 - Checkout ONOS master branch
39 - Pull latest ONOS code
40 - Building ONOS ( optional )
41 - Install ONOS package
42 - Build ONOS package
43 """
Devin Lim58046fa2017-07-05 16:55:00 -070044 try:
45 from tests.dependencies.ONOSSetup import ONOSSetup
46 main.testSetUp = ONOSSetup()
47 except ImportError:
48 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070049 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080050 from tests.dependencies.Network import Network
51 main.Network = Network()
Devin Lim0c972b72018-02-08 14:53:59 -080052 main.testSetUp.envSetupDescription( False )
Devin Lim58046fa2017-07-05 16:55:00 -070053 stepResult = main.FALSE
54 try:
Devin Lim58046fa2017-07-05 16:55:00 -070055 # Test variables
56 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
57 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070058 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080059 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
60 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
61 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080062 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
63 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
64 else:
65 main.useBmv2 = False
Devin Lim57221b02018-02-14 15:45:36 -080066 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070067 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080068 main.forJson = "json/"
69 main.forChart = "chart/"
70 main.forConfig = "conf/"
71 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080072 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080073 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070074 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070075 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080076 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
77 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080078 main.bmv2 = "bmv2.py"
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070079 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070080 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall1efcb3f2016-08-23 13:42:15 -070081
Devin Lim0c972b72018-02-08 14:53:59 -080082 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070083 except Exception as e:
84 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070085
Devin Lim58046fa2017-07-05 16:55:00 -070086 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070087
Jon Hall1efcb3f2016-08-23 13:42:15 -070088 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080089 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
90 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -070091 """
92 - Set up cell
93 - Create cell file
94 - Set cell file
95 - Verify cell file
96 - Kill ONOS process
97 - Uninstall ONOS cluster
98 - Verify ONOS start up
99 - Install ONOS cluster
100 - Connect to cli
101 """
102 # main.scale[ 0 ] determines the current number of ONOS controller
You Wangd87b2312018-01-30 12:47:17 -0800103 if not main.apps:
Jon Hall1efcb3f2016-08-23 13:42:15 -0700104 main.log.error( "App list is empty" )
Jon Hall3c910162018-03-07 14:42:16 -0800105 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
106 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700107 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800108 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800109 skipPack=skipPackage,
110 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800111 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700112 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
113 main.FALSE,
You Wang1cdc5f52017-12-19 16:47:51 -0800114 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700115 attempts=10 )
116 if ready:
117 ready = main.TRUE
118 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700119 onpass="ONOS summary command succeded",
120 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700121 if not ready:
122 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700123 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700124
Devin Lim142b5342017-07-20 15:22:39 -0700125 for ctrl in main.Cluster.active():
126 ctrl.CLI.logSet( "DEBUG", "org.onosproject.segmentrouting" )
You Wangf5f104f2018-03-30 17:09:10 -0700127 ctrl.CLI.logSet( "DEBUG", "org.onosproject.driver" )
Devin Lim142b5342017-07-20 15:22:39 -0700128 ctrl.CLI.logSet( "DEBUG", "org.onosproject.net.flowobjective.impl" )
You Wangf5f104f2018-03-30 17:09:10 -0700129 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.impl" )
130 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.store" )
131 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routing.fpm" )
Jon Hall9677ed32018-04-24 11:16:23 -0700132 ctrl.CLI.logSet( "TRACE", "org.onosproject.events" )
133 ctrl.CLI.logSet( "DEBUG", "org.onosproject.mcast" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700134
135 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800136 def loadCount( main ):
137 with open("%s/count/%s.count" % (main.configPath, main.cfgName)) as count:
You Wang5df1c6d2018-04-06 18:02:02 -0700138 main.count = json.load(count)
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800139
140 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800141 def loadJson( main ):
142 with open( "%s%s.json" % ( main.configPath + main.forJson,
143 main.cfgName ) ) as cfg:
144 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
145
146 @staticmethod
147 def loadChart( main ):
148 try:
149 with open( "%s%s.chart" % ( main.configPath + main.forChart,
150 main.cfgName ) ) as chart:
151 main.pingChart = json.load(chart)
152 except IOError:
153 main.log.warn( "No chart file found." )
154
155 @staticmethod
156 def loadHost( main ):
157 with open( "%s%s.host" % ( main.configPath + main.forHost,
158 main.cfgName ) ) as host:
159 main.expectedHosts = json.load( host )
160
161 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800162 def loadSwitchFailureChart( main ):
163 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
164 main.cfgName ) ) as sfc:
165 main.switchFailureChart = json.load( sfc )
166
167 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800168 def loadLinkFailureChart( main ):
169 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700170 main.cfgName ) ) as lfc:
171 main.linkFailureChart = json.load( lfc )
172
173 @staticmethod
174 def loadMulticastConfig( main ):
175 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
176 main.cfgName ) ) as cfg:
177 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800178
179 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700180 def startMininet( main, topology, args="" ):
You Wangd87b2312018-01-30 12:47:17 -0800181 copyResult = main.ONOSbench.scp( main.Mininet1,
182 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700183 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800184 direction="to" )
185 if main.topologyLib:
186 for lib in main.topologyLib.split(","):
187 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
188 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700189 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800190 direction="to" )
191 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700192 import re
193 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
194 index = 0
You Wangd87b2312018-01-30 12:47:17 -0800195 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700196 # Update zebra configurations with correct ONOS instance IP
197 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
198 ip = controllerIPs[ index ]
199 index = ( index + 1 ) % len( controllerIPs )
200 with open( main.configPath + main.forConfig + conf ) as f:
201 s = f.read()
202 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
203 with open( main.configPath + main.forConfig + conf, "w" ) as f:
204 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800205 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800206 main.configPath + main.forConfig + conf,
You Wangd87b2312018-01-30 12:47:17 -0800207 "~/",
208 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800209 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700210 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800211 main.Mininet1.home + "custom",
212 direction="to" )
You Wangd87b2312018-01-30 12:47:17 -0800213 stepResult = copyResult
214 utilities.assert_equals( expect=main.TRUE,
215 actual=stepResult,
216 onpass="Successfully copied topo files",
217 onfail="Failed to copy topo files" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700218 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700219 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700220 main.topology = topology
221 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700222 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700223 stepResult = topoResult
224 utilities.assert_equals( expect=main.TRUE,
225 actual=stepResult,
226 onpass="Successfully loaded topology",
227 onfail="Failed to load topology" )
228 # Exit if topology did not load properly
229 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700230 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700231
232 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700233 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800234 main.step( "Connecting to physical netowrk" )
235 topoResult = main.NetworkBench.connectToNet()
236 stepResult = topoResult
237 utilities.assert_equals( expect=main.TRUE,
238 actual=stepResult,
239 onpass="Successfully loaded topology",
240 onfail="Failed to load topology" )
241 # Exit if topology did not load properly
242 if not topoResult:
243 main.cleanAndExit()
244
245 main.step( "Assign switches to controllers." )
246 assignResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700247 switches = main.NetworkBench.getSwitches()
248 pool = []
249 for name in switches.keys():
250 thread = main.Thread( target=main.NetworkBench.assignSwController,
251 name="assignSwitchToController",
252 args=[ name, main.Cluster.getIps(), '6653' ] )
253 pool.append( thread )
254 thread.start()
255 for thread in pool:
256 thread.join( 300 )
257 if not thread.result:
258 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800259 utilities.assert_equals( expect=main.TRUE,
260 actual=stepResult,
261 onpass="Successfully assign switches to controllers",
262 onfail="Failed to assign switches to controllers" )
263
You Wang4cc61912018-08-28 10:10:58 -0700264 # Check devices
265 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
266 time.sleep( float( main.params[ "timers" ][ "connectToNetSleep" ] ) )
267 # Connecting to hosts that only have data plane connectivity
268 main.step( "Connecting inband hosts" )
269 stepResult = main.Network.connectInbandHosts()
270 utilities.assert_equals( expect=main.TRUE,
271 actual=stepResult,
272 onpass="Successfully connected inband hosts",
273 onfail="Failed to connect inband hosts" )
274
You Wang84f981d2018-01-12 16:11:50 -0800275 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700276 def saveOnosDiagnostics( main ):
277 """
278 Get onos-diags.tar.gz and save it to the log directory.
279 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
280 """
281 main.log.info( "Collecting onos-diags..." )
282 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
283 main.logdir,
284 "-CASE%d" % main.CurrentTestCaseNumber )
285
286 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700287 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700288 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700289
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700290 main.failures = int( main.params[ 'failures' ] )
291 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700292
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700293 if main.cfgName == '2x2':
294 spine = {}
295 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
296 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
297 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700298
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700299 spine = {}
300 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
301 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
302 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700303
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700304 elif main.cfgName == '4x4':
305 spine = {}
306 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
307 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
308 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700309
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700310 spine = {}
311 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
312 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
313 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700314
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700315 spine = {}
316 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
317 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
318 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700319
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700320 spine = {}
321 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
322 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
323 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700324
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700325 else:
Piera2a7e1b2016-10-04 11:51:43 -0700326 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700327 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800328
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800329 @staticmethod
330 def addStaticOnosRoute( main, subnet, intf):
331 """
332 Adds an ONOS static route with the use route-add command.
333 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800334 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
335
Piera2a7e1b2016-10-04 11:51:43 -0700336 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700337 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700338 """
339 Check number of groups for each subnet on device deviceId and matches
340 it with an expected value. subnetDict is a dictionarty containing values
341 of the type "10.0.1.0/24" : 5.
342 """
You Wangc02f3be2018-05-18 12:14:23 -0700343 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
344 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
345 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700346
You Wangc02f3be2018-05-18 12:14:23 -0700347 result = main.TRUE
348 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700349 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700350 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700351 # this will match the group id that this flow entry points to, for example :
352 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700353 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700354 count = 0
355 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700356 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700357 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700358 if count - 1 != numberInSelect:
359 result = main.FALSE
360 main.log.warn( "Mismatch in number of buckets of select group, found {0}, expected {1} for subnet {2} on device {3}".format( count - 1, numberInSelect, subnet, deviceId ) )
361 utilities.assert_equals( expect=main.TRUE, actual=result,
362 onpass="All bucket numbers are as expected",
363 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700364
365 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900366 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700367 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800368 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900369 if tag == "":
370 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700371 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700372 main.FALSE,
373 kwargs={ 'min': minFlowCount },
374 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800375 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800376 if count == main.FALSE:
377 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700378 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700379 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800380 actual=( count > minFlowCount ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700381 onpass="Flow count looks correct: " + str( count ),
382 onfail="Flow count looks wrong: " + str( count ) )
383
384 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700385 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700386 main.FALSE,
387 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800388 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800389 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700390 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700391 expect=main.TRUE,
392 actual=flowCheck,
393 onpass="Flow status is correct!",
394 onfail="Flow status is wrong!" )
395 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700396 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700397 "flows",
398 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900399 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700400 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700401 "groups",
402 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900403 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700404
405 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700406 def checkDevices( main, switches, tag="", sleep=10 ):
407 main.step(
408 "Check whether the switches count is equal to %s" % switches )
409 if tag == "":
410 tag = 'CASE%d' % main.CurrentTestCaseNumber
411 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
412 main.FALSE,
413 kwargs={ 'numoswitch': switches},
414 attempts=10,
415 sleep=sleep )
416 utilities.assert_equals( expect=main.TRUE, actual=result,
417 onpass="Device up successful",
418 onfail="Failed to boot up devices?" )
419
420 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800421 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
422 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800423 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
424 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
425 main.FALSE,
426 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800427 attempts=5,
428 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800429 if count == main.FALSE:
430 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800431 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800432 expect=True,
433 actual=( count > minFlowCount ),
434 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800435 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800436
437 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700438 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800439 main.step(
440 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
441 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
442 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700443 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800444 attempts=5,
445 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800446 if count == main.FALSE:
447 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800448 utilities.assertEquals(
449 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800450 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700451 onpass="Flow count looks correct: " + str( count ) ,
452 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800453
454 @staticmethod
455 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
456 main.step(
457 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
458 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
459 main.FALSE,
460 args=( dpid, groupCount, False, 1),
461 attempts=5,
462 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800463 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800464 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800465 utilities.assertEquals(
466 expect=True,
467 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700468 onpass="Group count looks correct: " + str( count ) ,
469 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800470
471 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700472 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800473
474 for dpid, values in main.count.items():
475 flowCount = values["flows"]
476 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700477 main.log.report( "Check flow count for dpid " + str( dpid ) +
478 ", should be " + str( flowCount ) )
479 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800480
Jon Hall9677ed32018-04-24 11:16:23 -0700481 main.log.report( "Check group count for dpid " + str( dpid ) +
482 ", should be " + str( groupCount ) )
483 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800484
485 return
486
487 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700488 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
489 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800490 '''
You Wangba231e72018-03-01 13:18:21 -0800491 Verify connectivity between hosts according to the ping chart
492 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800493 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800494 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800495 '''
You Wangba231e72018-03-01 13:18:21 -0800496 main.log.report( "Check host connectivity" )
497 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800498 if tag == "":
499 tag = 'CASE%d' % main.CurrentTestCaseNumber
500 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800501 main.log.debug( "Entry in ping chart: %s" % entry )
502 expect = entry[ 'expect' ]
503 if expect == "Unidirectional":
504 # Verify ping from each src host to each dst host
505 src = entry[ 'src' ]
506 dst = entry[ 'dst' ]
507 expect = main.TRUE
508 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
509 if basedOnIp:
510 if ("v4" in src[0]):
511 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
512 utilities.assert_equals( expect=expect, actual=pa,
513 onpass="IPv4 connectivity successfully tested",
514 onfail="IPv4 connectivity failed" )
515 if ("v6" in src[0]):
516 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
517 utilities.assert_equals( expect=expect, actual=pa,
518 onpass="IPv6 connectivity successfully tested",
519 onfail="IPv6 connectivity failed" )
520 else:
521 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
522 utilities.assert_equals( expect=expect, actual=pa,
523 onpass="IP connectivity successfully tested",
524 onfail="IP connectivity failed" )
525 else:
526 # Verify ping between each host pair
527 hosts = entry[ 'hosts' ]
528 try:
529 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
530 except:
531 expect = main.FALSE
532 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
533 if basedOnIp:
534 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800535 pa = utilities.retry( main.Network.pingallHosts,
536 main.FALSE if expect else main.TRUE,
537 args=(hosts,),
538 attempts=retryAttempts,
539 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800540 utilities.assert_equals( expect=expect, actual=pa,
541 onpass="IPv4 connectivity successfully tested",
542 onfail="IPv4 connectivity failed" )
543 if ("v6" in hosts[0]):
544 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
545 utilities.assert_equals( expect=expect, actual=pa,
546 onpass="IPv6 connectivity successfully tested",
547 onfail="IPv6 connectivity failed" )
548 else:
You Wangf19d9f42018-02-23 16:34:19 -0800549 pa = main.Network.pingallHosts( hosts )
550 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800551 onpass="IP connectivity successfully tested",
552 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700553 if skipOnFail and pa != expect:
554 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700555 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700556 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800557
558 if dumpflows:
559 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
560 "flows",
561 main.logdir,
562 tag + "_FlowsOn" )
563 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
564 "groups",
565 main.logdir,
566 tag + "_GroupsOn" )
567
568 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700569 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700570 """
571 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
572 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
573 Kill a link and verify ONOS can see the proper link change
574 """
Jon Halla604fd42018-05-04 14:27:27 -0700575 if sleep is None:
576 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
577 else:
578 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700579 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700580 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
581 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
582 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700583 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700584 "Waiting %s seconds for link down to be discovered" % sleep )
585 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700586 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700587 main.FALSE,
588 kwargs={ 'numoswitch': switches,
589 'numolink': links },
590 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700591 sleep=sleep )
592 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700593 utilities.assert_equals( expect=main.TRUE, actual=result,
594 onpass="Link down successful",
595 onfail="Failed to turn off link?" )
596
597 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700598 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800599 """
600 links = list of links (src, dst) to bring down.
601 """
602
603 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700604 if sleep is None:
605 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
606 else:
607 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800608
609 for end1, end2 in links:
610 main.Network.link( END1=end1, END2=end2, OPTION="down")
611 main.Network.link( END1=end2, END2=end1, OPTION="down")
612
Jon Halla604fd42018-05-04 14:27:27 -0700613 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800614 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700615 "Waiting %s seconds for links down to be discovered" % sleep )
616 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800617
618 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
619 main.FALSE,
620 kwargs={ 'numoswitch': switches,
621 'numolink': linksAfter },
622 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700623 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800624
You Wang2854bce2018-03-30 10:15:32 -0700625 utilities.assert_equals( expect=main.TRUE, actual=topology,
626 onpass="Link batch down successful",
627 onfail="Link batch down failed" )
628
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800629 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700630 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800631 """
632 links = list of link (src, dst) to bring up again.
633 """
634
635 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700636 if sleep is None:
637 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
638 else:
639 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800640
641 for end1, end2 in links:
642 main.Network.link( END1=end1, END2=end2, OPTION="up")
643 main.Network.link( END1=end2, END2=end1, OPTION="up")
644
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800645 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700646 "Waiting %s seconds for links up to be discovered" % sleep )
647 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800648
649 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
650 main.FALSE,
651 kwargs={ 'numoswitch': switches,
652 'numolink': linksAfter },
653 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700654 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800655
You Wang2854bce2018-03-30 10:15:32 -0700656 utilities.assert_equals( expect=main.TRUE, actual=topology,
657 onpass="Link batch up successful",
658 onfail="Link batch up failed" )
659
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800660 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700661 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
662 """
663 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
664 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
665 switches, links: number of expected switches and links after link change, ex.: '4', '6'
666 """
667 if sleep is None:
668 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
669 else:
670 sleep = float( sleep )
671 main.step( "Disable a batch of ports" )
672 for dpid, port in ports:
673 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
674 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
675 time.sleep( sleep )
676 if switches and links:
677 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
678 numolink=links )
679 utilities.assert_equals( expect=main.TRUE, actual=result,
680 onpass="Port down successful",
681 onfail="Port down failed" )
682
683 @staticmethod
684 def enablePortBatch( main, ports, switches, links, sleep=None ):
685 """
686 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
687 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
688 switches, links: number of expected switches and links after link change, ex.: '4', '6'
689 """
690 if sleep is None:
691 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
692 else:
693 sleep = float( sleep )
694 main.step( "Enable a batch of ports" )
695 for dpid, port in ports:
696 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
697 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
698 time.sleep( sleep )
699 if switches and links:
700 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
701 numolink=links )
702 utilities.assert_equals( expect=main.TRUE, actual=result,
703 onpass="Port up successful",
704 onfail="Port up failed" )
705
706 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700707 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700708 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700709 """
710 Params:
711 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700712 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700713 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
714 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
715 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
716 Kill a link and verify ONOS can see the proper link change
717 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700718 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700719 if sleep is None:
720 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
721 else:
722 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700723 result = False
724 count = 0
725 while True:
726 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700727 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800728 main.Network.link( END1=end1, END2=end2, OPTION="up" )
729 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700730 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700731 "Waiting %s seconds for link up to be discovered" % sleep )
732 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700733
You Wangc02d8352018-04-17 16:42:10 -0700734 if portUp:
735 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
736 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700737 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700738
Jon Halla604fd42018-05-04 14:27:27 -0700739 result = ctrl.CLI.checkStatus( numoswitch=switches,
740 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700741 if count > 5 or result:
742 break
743 utilities.assert_equals( expect=main.TRUE, actual=result,
744 onpass="Link up successful",
745 onfail="Failed to bring link up" )
746
747 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700748 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700749 """
750 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
751 Completely kill a switch and verify ONOS can see the proper change
752 """
Jon Halla604fd42018-05-04 14:27:27 -0700753 if sleep is None:
754 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
755 else:
756 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700757 switch = switch if isinstance( switch, list ) else [ switch ]
758 main.step( "Kill " + str( switch ) )
759 for s in switch:
760 main.log.info( "Stopping " + s )
761 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700762 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700763
764 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700765 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700766 sleep ) )
767 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700768 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700769 main.FALSE,
770 kwargs={ 'numoswitch': switches,
771 'numolink': links },
772 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700773 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700774 utilities.assert_equals( expect=main.TRUE, actual=topology,
775 onpass="Kill switch successful",
776 onfail="Failed to kill switch?" )
777
778 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700779 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700780 """
781 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
782 Recover a switch and verify ONOS can see the proper change
783 """
Jon Halla604fd42018-05-04 14:27:27 -0700784 if sleep is None:
785 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
786 else:
787 sleep = float( sleep )
788 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700789 switch = switch if isinstance( switch, list ) else [ switch ]
790 main.step( "Recovering " + str( switch ) )
791 for s in switch:
792 main.log.info( "Starting " + s )
793 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700794 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700795 sleep ) )
796 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700797 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700798 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700799 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700800 sleep ) )
801 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700802
Devin Lim142b5342017-07-20 15:22:39 -0700803 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700804 main.FALSE,
805 kwargs={ 'numoswitch': switches,
806 'numolink': links },
807 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700808 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700809 utilities.assert_equals( expect=main.TRUE, actual=topology,
810 onpass="Switch recovery successful",
811 onfail="Failed to recover switch?" )
812
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700813 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700814 def killRouter( main, router, sleep=None ):
815 """
816 Kill bgpd process on a quagga router
817 router: name of the router to be killed. E.g. "bgp1"
818 """
819 sleep = float( sleep )
820 main.step( "Kill " + str( router ) )
821 if hasattr( main, 'Mininet1' ):
822 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
823 main.Mininet1.handle.expect( "mininet>" )
824 else:
825 # TODO: support killing router in physical network
826 pass
827 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
828 time.sleep( sleep )
829
830 @staticmethod
831 def recoverRouter( main, router, sleep=None ):
832 """
833 Restart bgpd process on a quagga router
834 router: name of the router to be recovered. E.g. "bgp1"
835 """
836 sleep = float( sleep )
837 main.step( "Recovering " + str( router ) )
838 if hasattr( main, 'Mininet1' ):
839 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
840 main.Mininet1.handle.expect( "mininet>" )
841 else:
842 # TODO: support recovering router in physical network
843 pass
844 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
845 time.sleep( sleep )
846
847 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700848 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700849 """
850 Stop Onos-cluster.
851 Stops Mininet
852 Copies ONOS log
853 """
You Wang4cc61912018-08-28 10:10:58 -0700854 from tests.dependencies.utils import Utils
855 main.utils = Utils()
856 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700857 if hasattr( main, "scapyHosts" ):
858 scapyResult = main.TRUE
859 for host in main.scapyHosts:
860 scapyResult = host.stopScapy() and scapyResult
861 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
862 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700863 if hasattr( main, 'Mininet1' ):
864 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
865 else:
866 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700867 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
868 main.scapyHosts = []
869
You Wang5da39c82018-04-26 22:55:08 -0700870 if removeHostComponent:
871 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
872 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700873 if hasattr( main, 'Mininet1' ):
874 pass
875 else:
876 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700877 main.Network.removeHostComponent( host )
878
You Wang5df1c6d2018-04-06 18:02:02 -0700879 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700880 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700881 else:
882 main.Network.disconnectInbandHosts()
883 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700884
You Wang5df1c6d2018-04-06 18:02:02 -0700885 if copyKarafLog:
886 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700887
Devin Lim142b5342017-07-20 15:22:39 -0700888 for ctrl in main.Cluster.active():
889 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700890
891 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700892 def verifyNodes( main ):
893 """
894 Verifies Each active node in the cluster has an accurate view of other node's and their status
895
896 Params:
897 nodes, integer array with position of the ONOS nodes in the CLIs array
898 """
899 nodeResults = utilities.retry( main.Cluster.nodesCheck,
900 False,
901 attempts=10,
902 sleep=10 )
903 utilities.assert_equals( expect=True, actual=nodeResults,
904 onpass="Nodes check successful",
905 onfail="Nodes check NOT successful" )
906
907 if not nodeResults:
908 for ctrl in main.Cluster.runningNodes:
909 main.log.debug( "{} components not ACTIVE: \n{}".format(
910 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -0800911 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -0800912 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -0700913 main.cleanAndExit()
914
915 @staticmethod
916 def verifyTopology( main, switches, links, expNodes ):
917 """
918 Verifies that the ONOS cluster has an acuurate view of the topology
919
920 Params:
921 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
922 """
923 main.step( "Check number of topology elements" )
924 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
925 main.FALSE,
926 kwargs={ 'numoswitch': switches,
927 'numolink': links,
928 'numoctrl': expNodes },
929 attempts=10,
930 sleep=12 )
931 utilities.assert_equals( expect=main.TRUE, actual=topology,
932 onpass="Number of topology elements are correct",
933 onfail="Unexpected number of links, switches, and/or controllers" )
934
935 @staticmethod
936 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700937 """
938 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
939 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
940 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
941 """
Jon Halla604fd42018-05-04 14:27:27 -0700942 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800943 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700944 if sleep is None:
945 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
946 else:
947 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700948
Jon Hall1efcb3f2016-08-23 13:42:15 -0700949 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700950 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700951 utilities.assert_equals( expect=main.TRUE, actual=killResult,
952 onpass="ONOS instance Killed",
953 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700954 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700955 main.Cluster.reset()
956 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700957
Devin Lim142b5342017-07-20 15:22:39 -0700958 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700959 Testcaselib.verifyNodes( main )
960 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700961
962 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700963 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700964 """
965 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
966 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
967 Recover an ONOS instance and verify the ONOS cluster can see the proper change
968 """
Jon Hall3c910162018-03-07 14:42:16 -0800969 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700970 if sleep is None:
971 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
972 else:
973 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700974 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700975 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700976 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700977 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700978 utilities.assert_equals( expect=main.TRUE, actual=isUp,
979 onpass="ONOS service is ready",
980 onfail="ONOS service did not start properly" )
981 for i in nodes:
982 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700983 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900984 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700985 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
986 commandlineTimeout=60,
987 onosStartTimeout=100 )
988 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -0700989 utilities.assert_equals( expect=main.TRUE,
990 actual=cliResult,
991 onpass="ONOS CLI is ready",
992 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700993
Jon Halla604fd42018-05-04 14:27:27 -0700994 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -0700995 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -0700996 Testcaselib.verifyNodes( main )
997 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -0700998
Devin Lim142b5342017-07-20 15:22:39 -0700999 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
1000 main.FALSE,
1001 attempts=10,
1002 sleep=12 )
1003 if ready:
1004 ready = main.TRUE
1005 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001006 onpass="ONOS summary command succeded",
1007 onfail="ONOS summary command failed" )
1008 if not ready:
1009 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001010 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001011
1012 @staticmethod
1013 def addHostCfg( main ):
1014 """
1015 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001016 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001017 """
1018 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001019 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001020 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001021 hostCfg = json.load( template )
1022 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1023 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001024 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001025 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1026 subjectClass="hosts",
1027 subjectKey=urllib.quote( mac,
1028 safe='' ),
1029 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001030 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1031 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001032 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001033 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1034 subjectClass="hosts",
1035 subjectKey=urllib.quote( mac,
1036 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001037 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001038 main.pingChart.update( { 'vlan1': { "expect": "True",
1039 "hosts": [ "olt1", "vsg1" ] } } )
1040 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1041 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001042 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001043 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001044 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1045 subjectClass="apps",
1046 subjectKey="org.onosproject.segmentrouting",
1047 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001048
1049 @staticmethod
1050 def delHostCfg( main ):
1051 """
1052 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001053 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001054 """
1055 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001056 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001057 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001058 hostCfg = json.load( template )
1059 main.step( "Removing host configuration" )
1060 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001061 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001062 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1063 subjectKey=urllib.quote(
1064 mac,
1065 safe='' ),
1066 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001067 main.step( "Removing configuration" )
1068 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001069 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001070 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1071 subjectKey=urllib.quote(
1072 mac,
1073 safe='' ),
1074 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001075 main.step( "Removing vlan configuration" )
1076 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001077 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1078 subjectKey="org.onosproject.segmentrouting",
1079 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001080
1081 @staticmethod
1082 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1083 """
1084 Verifies IP address assignment from the hosts
1085 """
1086 main.step( "Verify IP address assignment from hosts" )
1087 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001088 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001089 # Find out names of disconnected hosts
1090 disconnectedHosts = []
1091 if hasattr( main, "disconnectedIpv4Hosts" ):
1092 for host in main.disconnectedIpv4Hosts:
1093 disconnectedHosts.append( host )
1094 if hasattr( main, "disconnectedIpv6Hosts" ):
1095 for host in main.disconnectedIpv6Hosts:
1096 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001097 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001098 # Exclude disconnected hosts
1099 if hostName in disconnectedHosts:
1100 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1101 continue
You Wang53dba1e2018-02-02 17:45:44 -08001102 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1103 main.FALSE,
1104 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001105 'prefix': ip,
1106 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001107 attempts=attempts,
1108 sleep=sleep )
1109 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1110 onpass="Verify network host IP succeded",
1111 onfail="Verify network host IP failed" )
1112
1113 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001114 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001115 """
1116 Verifies host IP address assignment from ONOS
1117 """
1118 main.step( "Verify host IP address assignment in ONOS" )
1119 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001120 # Find out IPs of disconnected hosts
1121 disconnectedIps = []
1122 if hasattr( main, "disconnectedIpv4Hosts" ):
1123 for host in main.disconnectedIpv4Hosts:
1124 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1125 if hasattr( main, "disconnectedIpv6Hosts" ):
1126 for host in main.disconnectedIpv6Hosts:
1127 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001128 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001129 # Exclude disconnected hosts
1130 if ip in disconnectedIps:
1131 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1132 continue
You Wang53dba1e2018-02-02 17:45:44 -08001133 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1134 main.FALSE,
1135 kwargs={ 'hostList': [ hostName ],
1136 'prefix': ip },
1137 attempts=attempts,
1138 sleep=sleep )
1139 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1140 onpass="Verify ONOS host IP succeded",
1141 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001142 if not ipResult and skipOnFail:
1143 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001144 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001145 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001146
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001147 @staticmethod
1148 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1149 """
1150 Description:
1151 Updates interface configuration in ONOS, with given IP and vlan parameters
1152 Required:
1153 * connectPoint: connect point to update configuration
1154 Optional:
1155 * ips: list of IP addresses, combined with '/xx' subnet representation,
1156 corresponding to 'ips' field in the configuration
1157 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1158 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1159 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1160 """
1161 cfg = dict()
1162 cfg[ "ports" ] = dict()
1163 cfg[ "ports" ][ connectPoint ] = dict()
1164 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1165 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1166 if untagged > 0:
1167 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1168 else:
1169 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1170 if native > 0:
1171 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1172
1173 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001174
1175 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001176 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001177 """
1178 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001179 scapyNames: list of names that will be used as component names for scapy hosts
1180 mininetNames: used when scapy host names are different from the host names
1181 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1182 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001183 """
1184 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001185 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1186 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001187 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001188 if hasattr( main, 'Mininet1' ):
1189 main.Scapy.createHostComponent( scapyName )
1190 scapyHandle = getattr( main, scapyName )
1191 if mininetNames:
1192 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1193 else:
1194 mininetName = None
1195 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001196 else:
You Wang0fc21702018-11-02 17:49:18 -07001197 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001198 scapyHandle = getattr( main, scapyName )
1199 scapyHandle.connectInband()
1200 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001201 scapyHandle.startScapy()
1202 scapyHandle.updateSelf()
1203 main.log.debug( scapyHandle.name )
1204 main.log.debug( scapyHandle.hostIp )
1205 main.log.debug( scapyHandle.hostMac )
1206
1207 @staticmethod
1208 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1209 """
1210 Verify unicast traffic by pinging from source hosts to the destination IP
1211 and capturing the packets at the destination host using Scapy.
1212 srcHosts: List of host names to send the ping packets
1213 dstIp: destination IP of the ping packets
1214 dstHost: host that runs Scapy to capture the packets
1215 dstIntf: name of the interface on the destination host
1216 expect: use True if the ping is expected to be captured at destination;
1217 Otherwise False
1218 skipOnFail: skip the rest of this test case if result is not expected
1219 maxRetry: number of retries allowed
1220 """
1221 from tests.dependencies.topology import Topology
1222 try:
1223 main.topo
1224 except ( NameError, AttributeError ):
1225 main.topo = Topology()
1226 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1227 result = main.TRUE
1228 for srcHost in srcHosts:
1229 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1230 expect, maxRetry, True )
1231 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001232 result = main.FALSE
1233 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1234 utilities.assert_equals( expect=main.TRUE,
1235 actual=result,
1236 onpass="Verify traffic to {}: Pass".format( dstIp ),
1237 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1238 if skipOnFail and result != main.TRUE:
1239 Testcaselib.saveOnosDiagnostics( main )
1240 Testcaselib.cleanup( main, copyKarafLog=False )
1241 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001242
1243 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001244 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001245 """
1246 Verify multicast traffic using scapy
1247 """
You Wangc564c6f2018-05-01 15:24:57 -07001248 from tests.dependencies.topology import Topology
1249 try:
1250 main.topo
1251 except ( NameError, AttributeError ):
1252 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001253 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001254 routeData = main.multicastConfig[ routeName ]
1255 srcs = main.mcastRoutes[ routeName ][ "src" ]
1256 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1257 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1258 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001259 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001260 for src in srcs:
1261 srcEntry = routeData[ "src" ][ src ]
1262 for dst in dsts:
1263 dstEntry = routeData[ "dst" ][ dst ]
1264 sender = getattr( main, srcEntry[ "host" ] )
1265 receiver = getattr( main, dstEntry[ "host" ] )
1266 main.Network.addRoute( str( srcEntry[ "host" ] ),
1267 str( routeData[ "group" ] ),
1268 str( srcEntry[ "interface" ] ),
1269 True if routeData[ "ipVersion" ] == 6 else False )
1270 # Build the packet
1271 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1272 if routeData[ "ipVersion" ] == 4:
1273 sender.buildIP( dst=str( routeData[ "group" ] ) )
1274 elif routeData[ "ipVersion" ] == 6:
1275 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1276 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1277 sIface = srcEntry[ "interface" ]
1278 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1279 pktFilter = srcEntry[ "filter" ]
1280 pkt = srcEntry[ "packet" ]
1281 # Send packet and check received packet
1282 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001283 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001284 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001285 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1286 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001287 if not trafficResult:
1288 result = main.FALSE
1289 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1290 dstEntry[ "host" ] ) )
1291 utilities.assert_equals( expect=main.TRUE,
1292 actual=result,
1293 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1294 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001295 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001296 Testcaselib.saveOnosDiagnostics( main )
1297 Testcaselib.cleanup( main, copyKarafLog=False )
1298 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001299
1300 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001301 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001302 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1303 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001304 """
1305 Verify reachability from each host in srcList to each host in dstList
1306 """
1307 from tests.dependencies.topology import Topology
1308 try:
1309 main.topo
1310 except ( NameError, AttributeError ):
1311 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001312 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001313 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001314 utilities.assert_equals( expect=main.TRUE,
1315 actual=pingResult,
1316 onpass="{}: Pass".format( stepMsg ),
1317 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001318 if not pingResult and skipOnFail:
1319 Testcaselib.saveOnosDiagnostics( main )
1320 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1321 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001322
1323 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001324 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001325 """
1326 Verify if the specified host is discovered by ONOS on the given locations
1327 Required:
You Wang85747762018-05-11 15:51:50 -07001328 locationDict: a dictionary that maps host names to expected locations.
1329 locations could be a string or a list.
1330 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001331 Returns:
1332 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1333 """
You Wang85747762018-05-11 15:51:50 -07001334 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1335 result = main.TRUE
1336 for hostName, locations in locationDict.items():
1337 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1338 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1339 if not hostIp:
1340 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1341 if not hostIp:
1342 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1343 result = main.FALSE
1344 continue
1345 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1346 main.FALSE,
1347 args=( hostIp, locations ),
1348 attempts=retry + 1,
1349 sleep=10 )
1350 if not locationResult:
1351 result = main.FALSE
1352 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001353 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001354 onpass="Location verification passed",
1355 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001356
1357 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001358 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001359 """
1360 Move specified host from srcSw to dstSw.
1361 If srcSw and dstSw are same, the host will be moved from current port to
1362 next available port.
1363 Required:
1364 hostName: name of the host. e.g., "h1"
1365 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1366 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1367 gw: ip address of the gateway of the new location
1368 Optional:
1369 macAddr: if specified, change MAC address of the host to the specified MAC address.
1370 prefixLen: prefix length
1371 cfg: port configuration as JSON string
1372 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001373 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001374 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001375 if not hasattr( main, 'Mininet1' ):
1376 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1377 return
1378
You Wang6e5b48e2018-07-23 16:17:38 -07001379 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1380 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1381 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001382 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001383 if cfg:
1384 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1385 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001386 # Wait for the host to get RA for setting up default gateway
1387 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001388
1389 main.Mininet1.discoverHosts( [ hostName, ] )
1390
1391 # Update expectedHost when MAC address is changed.
1392 if macAddr is not None:
1393 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1394 if ipAddr is not None:
1395 for hostName, ip in main.expectedHosts[ "onos" ].items():
1396 if ip == ipAddr:
1397 vlan = hostName.split( "/" )[ -1 ]
1398 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001399 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001400 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001401
1402 @staticmethod
1403 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001404 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001405 """
1406 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1407 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1408 to next available port.
1409 Required:
1410 hostName: name of the host. e.g., "h1"
1411 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1412 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1413 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1414 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1415 gw: ip address of the gateway of the new location
1416 Optional:
1417 macAddr: if specified, change MAC address of the host to the specified MAC address.
1418 prefixLen: prefix length
1419 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001420 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001421 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001422 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001423 if not hasattr( main, 'Mininet1' ):
1424 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1425 return
1426
You Wang6e5b48e2018-07-23 16:17:38 -07001427 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1428 srcSw, srcPairSw, dstSw, dstPairSw ) )
1429 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1430 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1431 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001432 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001433 if cfg:
1434 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1435 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001436 # Wait for the host to get RA for setting up default gateway
1437 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001438
1439 main.Mininet1.discoverHosts( [ hostName, ] )
1440
1441 # Update expectedHost when MAC address is changed.
1442 if macAddr is not None:
1443 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1444 if ipAddr is not None:
1445 for hostName, ip in main.expectedHosts[ "onos" ].items():
1446 if ip == ipAddr:
1447 vlan = hostName.split( "/" )[ -1 ]
1448 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001449 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip