blob: 4d6c1c1f3d8b01df87676161a67e2085fdb344e2 [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'
62 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
63 main.forJson = "json/"
64 main.forChart = "chart/"
65 main.forConfig = "conf/"
66 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080067 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080068 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070069 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070070 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080071 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
72 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070073 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070074 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall1efcb3f2016-08-23 13:42:15 -070075
Devin Lim0c972b72018-02-08 14:53:59 -080076 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070077 except Exception as e:
78 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070079
Devin Lim58046fa2017-07-05 16:55:00 -070080 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070081
Jon Hall1efcb3f2016-08-23 13:42:15 -070082 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080083 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
84 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -070085 """
86 - Set up cell
87 - Create cell file
88 - Set cell file
89 - Verify cell file
90 - Kill ONOS process
91 - Uninstall ONOS cluster
92 - Verify ONOS start up
93 - Install ONOS cluster
94 - Connect to cli
95 """
96 # main.scale[ 0 ] determines the current number of ONOS controller
You Wangd87b2312018-01-30 12:47:17 -080097 if not main.apps:
Jon Hall1efcb3f2016-08-23 13:42:15 -070098 main.log.error( "App list is empty" )
Jon Hall3c910162018-03-07 14:42:16 -080099 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
100 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700101 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800102 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800103 skipPack=skipPackage,
104 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800105 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700106 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
107 main.FALSE,
You Wang1cdc5f52017-12-19 16:47:51 -0800108 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700109 attempts=10 )
110 if ready:
111 ready = main.TRUE
112 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700113 onpass="ONOS summary command succeded",
114 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700115 if not ready:
116 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700117 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700118
Devin Lim142b5342017-07-20 15:22:39 -0700119 for ctrl in main.Cluster.active():
120 ctrl.CLI.logSet( "DEBUG", "org.onosproject.segmentrouting" )
You Wangf5f104f2018-03-30 17:09:10 -0700121 ctrl.CLI.logSet( "DEBUG", "org.onosproject.driver" )
Devin Lim142b5342017-07-20 15:22:39 -0700122 ctrl.CLI.logSet( "DEBUG", "org.onosproject.net.flowobjective.impl" )
You Wangf5f104f2018-03-30 17:09:10 -0700123 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.impl" )
124 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.store" )
125 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routing.fpm" )
Jon Hall9677ed32018-04-24 11:16:23 -0700126 ctrl.CLI.logSet( "TRACE", "org.onosproject.events" )
127 ctrl.CLI.logSet( "DEBUG", "org.onosproject.mcast" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700128
129 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800130 def loadCount( main ):
131 with open("%s/count/%s.count" % (main.configPath, main.cfgName)) as count:
You Wang5df1c6d2018-04-06 18:02:02 -0700132 main.count = json.load(count)
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800133
134 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800135 def loadJson( main ):
136 with open( "%s%s.json" % ( main.configPath + main.forJson,
137 main.cfgName ) ) as cfg:
138 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
139
140 @staticmethod
141 def loadChart( main ):
142 try:
143 with open( "%s%s.chart" % ( main.configPath + main.forChart,
144 main.cfgName ) ) as chart:
145 main.pingChart = json.load(chart)
146 except IOError:
147 main.log.warn( "No chart file found." )
148
149 @staticmethod
150 def loadHost( main ):
151 with open( "%s%s.host" % ( main.configPath + main.forHost,
152 main.cfgName ) ) as host:
153 main.expectedHosts = json.load( host )
154
155 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800156 def loadSwitchFailureChart( main ):
157 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
158 main.cfgName ) ) as sfc:
159 main.switchFailureChart = json.load( sfc )
160
161 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800162 def loadLinkFailureChart( main ):
163 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700164 main.cfgName ) ) as lfc:
165 main.linkFailureChart = json.load( lfc )
166
167 @staticmethod
168 def loadMulticastConfig( main ):
169 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
170 main.cfgName ) ) as cfg:
171 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800172
173 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700174 def startMininet( main, topology, args="" ):
You Wangd87b2312018-01-30 12:47:17 -0800175 copyResult = main.ONOSbench.scp( main.Mininet1,
176 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700177 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800178 direction="to" )
179 if main.topologyLib:
180 for lib in main.topologyLib.split(","):
181 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
182 main.topoPath + lib,
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.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700186 import re
187 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
188 index = 0
You Wangd87b2312018-01-30 12:47:17 -0800189 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700190 # Update zebra configurations with correct ONOS instance IP
191 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
192 ip = controllerIPs[ index ]
193 index = ( index + 1 ) % len( controllerIPs )
194 with open( main.configPath + main.forConfig + conf ) as f:
195 s = f.read()
196 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
197 with open( main.configPath + main.forConfig + conf, "w" ) as f:
198 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800199 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800200 main.configPath + main.forConfig + conf,
You Wangd87b2312018-01-30 12:47:17 -0800201 "~/",
202 direction="to" )
203 stepResult = copyResult
204 utilities.assert_equals( expect=main.TRUE,
205 actual=stepResult,
206 onpass="Successfully copied topo files",
207 onfail="Failed to copy topo files" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700208 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700209 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700210 main.topology = topology
211 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700212 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700213 stepResult = topoResult
214 utilities.assert_equals( expect=main.TRUE,
215 actual=stepResult,
216 onpass="Successfully loaded topology",
217 onfail="Failed to load topology" )
218 # Exit if topology did not load properly
219 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700220 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700221
222 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700223 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800224 main.step( "Connecting to physical netowrk" )
225 topoResult = main.NetworkBench.connectToNet()
226 stepResult = topoResult
227 utilities.assert_equals( expect=main.TRUE,
228 actual=stepResult,
229 onpass="Successfully loaded topology",
230 onfail="Failed to load topology" )
231 # Exit if topology did not load properly
232 if not topoResult:
233 main.cleanAndExit()
234
235 main.step( "Assign switches to controllers." )
236 assignResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700237 switches = main.NetworkBench.getSwitches()
238 pool = []
239 for name in switches.keys():
240 thread = main.Thread( target=main.NetworkBench.assignSwController,
241 name="assignSwitchToController",
242 args=[ name, main.Cluster.getIps(), '6653' ] )
243 pool.append( thread )
244 thread.start()
245 for thread in pool:
246 thread.join( 300 )
247 if not thread.result:
248 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800249 utilities.assert_equals( expect=main.TRUE,
250 actual=stepResult,
251 onpass="Successfully assign switches to controllers",
252 onfail="Failed to assign switches to controllers" )
253
You Wang4cc61912018-08-28 10:10:58 -0700254 # Check devices
255 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
256 time.sleep( float( main.params[ "timers" ][ "connectToNetSleep" ] ) )
257 # Connecting to hosts that only have data plane connectivity
258 main.step( "Connecting inband hosts" )
259 stepResult = main.Network.connectInbandHosts()
260 utilities.assert_equals( expect=main.TRUE,
261 actual=stepResult,
262 onpass="Successfully connected inband hosts",
263 onfail="Failed to connect inband hosts" )
264
You Wang84f981d2018-01-12 16:11:50 -0800265 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700266 def saveOnosDiagnostics( main ):
267 """
268 Get onos-diags.tar.gz and save it to the log directory.
269 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
270 """
271 main.log.info( "Collecting onos-diags..." )
272 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
273 main.logdir,
274 "-CASE%d" % main.CurrentTestCaseNumber )
275
276 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700277 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700278 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700279
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700280 main.failures = int( main.params[ 'failures' ] )
281 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700282
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700283 if main.cfgName == '2x2':
284 spine = {}
285 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
286 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
287 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700288
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700289 spine = {}
290 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
291 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
292 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700293
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700294 elif main.cfgName == '4x4':
295 spine = {}
296 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
297 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
298 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700299
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700300 spine = {}
301 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
302 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
303 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700304
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700305 spine = {}
306 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
307 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
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' ][ 'spine4' ]
312 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
313 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700314
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700315 else:
Piera2a7e1b2016-10-04 11:51:43 -0700316 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700317 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800318
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800319 @staticmethod
320 def addStaticOnosRoute( main, subnet, intf):
321 """
322 Adds an ONOS static route with the use route-add command.
323 """
324 main.step("Add static route for subnet {0} towards router interface {1}".format(subnet, intf))
325 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
326
327 utilities.assert_equals( expect=True, actual=( not routeResult ),
328 onpass="route-add command succeeded",
329 onfail="route-add command failed")
Piera2a7e1b2016-10-04 11:51:43 -0700330
331 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700332 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700333 """
334 Check number of groups for each subnet on device deviceId and matches
335 it with an expected value. subnetDict is a dictionarty containing values
336 of the type "10.0.1.0/24" : 5.
337 """
You Wangc02f3be2018-05-18 12:14:23 -0700338 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
339 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
340 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700341
You Wangc02f3be2018-05-18 12:14:23 -0700342 result = main.TRUE
343 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700344 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700345 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700346 # this will match the group id that this flow entry points to, for example :
347 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700348 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700349 count = 0
350 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700351 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700352 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700353 if count - 1 != numberInSelect:
354 result = main.FALSE
355 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 ) )
356 utilities.assert_equals( expect=main.TRUE, actual=result,
357 onpass="All bucket numbers are as expected",
358 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700359
360 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900361 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700362 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800363 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900364 if tag == "":
365 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700366 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700367 main.FALSE,
368 kwargs={ 'min': minFlowCount },
369 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800370 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700371 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700372 expect=True,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700373 actual=( count > 0 ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700374 onpass="Flow count looks correct: " + str( count ),
375 onfail="Flow count looks wrong: " + str( count ) )
376
377 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700378 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700379 main.FALSE,
380 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800381 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800382 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700383 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700384 expect=main.TRUE,
385 actual=flowCheck,
386 onpass="Flow status is correct!",
387 onfail="Flow status is wrong!" )
388 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700389 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700390 "flows",
391 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900392 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700393 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700394 "groups",
395 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900396 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700397
398 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700399 def checkDevices( main, switches, tag="", sleep=10 ):
400 main.step(
401 "Check whether the switches count is equal to %s" % switches )
402 if tag == "":
403 tag = 'CASE%d' % main.CurrentTestCaseNumber
404 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
405 main.FALSE,
406 kwargs={ 'numoswitch': switches},
407 attempts=10,
408 sleep=sleep )
409 utilities.assert_equals( expect=main.TRUE, actual=result,
410 onpass="Device up successful",
411 onfail="Failed to boot up devices?" )
412
413 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800414 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
415 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800416 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
417 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
418 main.FALSE,
419 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800420 attempts=5,
421 sleep=sleep )
422 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800423 expect=True,
424 actual=( count > minFlowCount ),
425 onpass="Flow count looks correct: " + str( count ),
426 onfail="Flow count looks wrong. " )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800427
428 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700429 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800430 main.step(
431 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
432 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
433 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700434 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800435 attempts=5,
436 sleep=sleep )
437
438 utilities.assertEquals(
439 expect=True,
440 actual=( int( count ) == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700441 onpass="Flow count looks correct: " + str( count ) ,
442 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800443
444 @staticmethod
445 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
446 main.step(
447 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
448 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
449 main.FALSE,
450 args=( dpid, groupCount, False, 1),
451 attempts=5,
452 sleep=sleep )
453
454 utilities.assertEquals(
455 expect=True,
456 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700457 onpass="Group count looks correct: " + str( count ) ,
458 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800459
460 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700461 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800462
463 for dpid, values in main.count.items():
464 flowCount = values["flows"]
465 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700466 main.log.report( "Check flow count for dpid " + str( dpid ) +
467 ", should be " + str( flowCount ) )
468 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800469
Jon Hall9677ed32018-04-24 11:16:23 -0700470 main.log.report( "Check group count for dpid " + str( dpid ) +
471 ", should be " + str( groupCount ) )
472 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800473
474 return
475
476 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700477 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
478 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800479 '''
You Wangba231e72018-03-01 13:18:21 -0800480 Verify connectivity between hosts according to the ping chart
481 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800482 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800483 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800484 '''
You Wangba231e72018-03-01 13:18:21 -0800485 main.log.report( "Check host connectivity" )
486 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800487 if tag == "":
488 tag = 'CASE%d' % main.CurrentTestCaseNumber
489 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800490 main.log.debug( "Entry in ping chart: %s" % entry )
491 expect = entry[ 'expect' ]
492 if expect == "Unidirectional":
493 # Verify ping from each src host to each dst host
494 src = entry[ 'src' ]
495 dst = entry[ 'dst' ]
496 expect = main.TRUE
497 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
498 if basedOnIp:
499 if ("v4" in src[0]):
500 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
501 utilities.assert_equals( expect=expect, actual=pa,
502 onpass="IPv4 connectivity successfully tested",
503 onfail="IPv4 connectivity failed" )
504 if ("v6" in src[0]):
505 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
506 utilities.assert_equals( expect=expect, actual=pa,
507 onpass="IPv6 connectivity successfully tested",
508 onfail="IPv6 connectivity failed" )
509 else:
510 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
511 utilities.assert_equals( expect=expect, actual=pa,
512 onpass="IP connectivity successfully tested",
513 onfail="IP connectivity failed" )
514 else:
515 # Verify ping between each host pair
516 hosts = entry[ 'hosts' ]
517 try:
518 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
519 except:
520 expect = main.FALSE
521 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
522 if basedOnIp:
523 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800524 pa = utilities.retry( main.Network.pingallHosts,
525 main.FALSE if expect else main.TRUE,
526 args=(hosts,),
527 attempts=retryAttempts,
528 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800529 utilities.assert_equals( expect=expect, actual=pa,
530 onpass="IPv4 connectivity successfully tested",
531 onfail="IPv4 connectivity failed" )
532 if ("v6" in hosts[0]):
533 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
534 utilities.assert_equals( expect=expect, actual=pa,
535 onpass="IPv6 connectivity successfully tested",
536 onfail="IPv6 connectivity failed" )
537 else:
You Wangf19d9f42018-02-23 16:34:19 -0800538 pa = main.Network.pingallHosts( hosts )
539 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800540 onpass="IP connectivity successfully tested",
541 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700542 if skipOnFail and pa != expect:
543 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700544 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700545 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800546
547 if dumpflows:
548 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
549 "flows",
550 main.logdir,
551 tag + "_FlowsOn" )
552 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
553 "groups",
554 main.logdir,
555 tag + "_GroupsOn" )
556
557 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700558 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700559 """
560 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
561 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
562 Kill a link and verify ONOS can see the proper link change
563 """
Jon Halla604fd42018-05-04 14:27:27 -0700564 if sleep is None:
565 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
566 else:
567 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700568 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700569 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
570 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
571 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700572 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700573 "Waiting %s seconds for link down to be discovered" % sleep )
574 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700575 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700576 main.FALSE,
577 kwargs={ 'numoswitch': switches,
578 'numolink': links },
579 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700580 sleep=sleep )
581 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700582 utilities.assert_equals( expect=main.TRUE, actual=result,
583 onpass="Link down successful",
584 onfail="Failed to turn off link?" )
585
586 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700587 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800588 """
589 links = list of links (src, dst) to bring down.
590 """
591
592 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700593 if sleep is None:
594 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
595 else:
596 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800597
598 for end1, end2 in links:
599 main.Network.link( END1=end1, END2=end2, OPTION="down")
600 main.Network.link( END1=end2, END2=end1, OPTION="down")
601
Jon Halla604fd42018-05-04 14:27:27 -0700602 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800603 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700604 "Waiting %s seconds for links down to be discovered" % sleep )
605 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800606
607 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
608 main.FALSE,
609 kwargs={ 'numoswitch': switches,
610 'numolink': linksAfter },
611 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700612 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800613
You Wang2854bce2018-03-30 10:15:32 -0700614 utilities.assert_equals( expect=main.TRUE, actual=topology,
615 onpass="Link batch down successful",
616 onfail="Link batch down failed" )
617
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800618 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700619 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800620 """
621 links = list of link (src, dst) to bring up again.
622 """
623
624 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700625 if sleep is None:
626 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
627 else:
628 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800629
630 for end1, end2 in links:
631 main.Network.link( END1=end1, END2=end2, OPTION="up")
632 main.Network.link( END1=end2, END2=end1, OPTION="up")
633
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800634 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700635 "Waiting %s seconds for links up to be discovered" % sleep )
636 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800637
638 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
639 main.FALSE,
640 kwargs={ 'numoswitch': switches,
641 'numolink': linksAfter },
642 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700643 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800644
You Wang2854bce2018-03-30 10:15:32 -0700645 utilities.assert_equals( expect=main.TRUE, actual=topology,
646 onpass="Link batch up successful",
647 onfail="Link batch up failed" )
648
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800649 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700650 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
651 """
652 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
653 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
654 switches, links: number of expected switches and links after link change, ex.: '4', '6'
655 """
656 if sleep is None:
657 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
658 else:
659 sleep = float( sleep )
660 main.step( "Disable a batch of ports" )
661 for dpid, port in ports:
662 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
663 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
664 time.sleep( sleep )
665 if switches and links:
666 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
667 numolink=links )
668 utilities.assert_equals( expect=main.TRUE, actual=result,
669 onpass="Port down successful",
670 onfail="Port down failed" )
671
672 @staticmethod
673 def enablePortBatch( main, ports, switches, links, sleep=None ):
674 """
675 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
676 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
677 switches, links: number of expected switches and links after link change, ex.: '4', '6'
678 """
679 if sleep is None:
680 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
681 else:
682 sleep = float( sleep )
683 main.step( "Enable a batch of ports" )
684 for dpid, port in ports:
685 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
686 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
687 time.sleep( sleep )
688 if switches and links:
689 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
690 numolink=links )
691 utilities.assert_equals( expect=main.TRUE, actual=result,
692 onpass="Port up successful",
693 onfail="Port up failed" )
694
695 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700696 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700697 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700698 """
699 Params:
700 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700701 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700702 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
703 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
704 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
705 Kill a link and verify ONOS can see the proper link change
706 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700707 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700708 if sleep is None:
709 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
710 else:
711 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700712 result = False
713 count = 0
714 while True:
715 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700716 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800717 main.Network.link( END1=end1, END2=end2, OPTION="up" )
718 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700719 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700720 "Waiting %s seconds for link up to be discovered" % sleep )
721 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700722
You Wangc02d8352018-04-17 16:42:10 -0700723 if portUp:
724 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
725 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700726 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700727
Jon Halla604fd42018-05-04 14:27:27 -0700728 result = ctrl.CLI.checkStatus( numoswitch=switches,
729 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700730 if count > 5 or result:
731 break
732 utilities.assert_equals( expect=main.TRUE, actual=result,
733 onpass="Link up successful",
734 onfail="Failed to bring link up" )
735
736 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700737 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700738 """
739 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
740 Completely kill a switch and verify ONOS can see the proper change
741 """
Jon Halla604fd42018-05-04 14:27:27 -0700742 if sleep is None:
743 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
744 else:
745 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700746 switch = switch if isinstance( switch, list ) else [ switch ]
747 main.step( "Kill " + str( switch ) )
748 for s in switch:
749 main.log.info( "Stopping " + s )
750 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700751 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700752
753 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700754 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700755 sleep ) )
756 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700757 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700758 main.FALSE,
759 kwargs={ 'numoswitch': switches,
760 'numolink': links },
761 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700762 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700763 utilities.assert_equals( expect=main.TRUE, actual=topology,
764 onpass="Kill switch successful",
765 onfail="Failed to kill switch?" )
766
767 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700768 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700769 """
770 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
771 Recover a switch and verify ONOS can see the proper change
772 """
Jon Halla604fd42018-05-04 14:27:27 -0700773 if sleep is None:
774 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
775 else:
776 sleep = float( sleep )
777 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700778 switch = switch if isinstance( switch, list ) else [ switch ]
779 main.step( "Recovering " + str( switch ) )
780 for s in switch:
781 main.log.info( "Starting " + s )
782 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700783 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700784 sleep ) )
785 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700786 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700787 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700788 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700789 sleep ) )
790 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700791
Devin Lim142b5342017-07-20 15:22:39 -0700792 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700793 main.FALSE,
794 kwargs={ 'numoswitch': switches,
795 'numolink': links },
796 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700797 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700798 utilities.assert_equals( expect=main.TRUE, actual=topology,
799 onpass="Switch recovery successful",
800 onfail="Failed to recover switch?" )
801
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700802 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700803 def killRouter( main, router, sleep=None ):
804 """
805 Kill bgpd process on a quagga router
806 router: name of the router to be killed. E.g. "bgp1"
807 """
808 sleep = float( sleep )
809 main.step( "Kill " + str( router ) )
810 if hasattr( main, 'Mininet1' ):
811 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
812 main.Mininet1.handle.expect( "mininet>" )
813 else:
814 # TODO: support killing router in physical network
815 pass
816 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
817 time.sleep( sleep )
818
819 @staticmethod
820 def recoverRouter( main, router, sleep=None ):
821 """
822 Restart bgpd process on a quagga router
823 router: name of the router to be recovered. E.g. "bgp1"
824 """
825 sleep = float( sleep )
826 main.step( "Recovering " + str( router ) )
827 if hasattr( main, 'Mininet1' ):
828 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
829 main.Mininet1.handle.expect( "mininet>" )
830 else:
831 # TODO: support recovering router in physical network
832 pass
833 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
834 time.sleep( sleep )
835
836 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700837 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700838 """
839 Stop Onos-cluster.
840 Stops Mininet
841 Copies ONOS log
842 """
You Wang4cc61912018-08-28 10:10:58 -0700843 from tests.dependencies.utils import Utils
844 main.utils = Utils()
845 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700846 if hasattr( main, "scapyHosts" ):
847 scapyResult = main.TRUE
848 for host in main.scapyHosts:
849 scapyResult = host.stopScapy() and scapyResult
850 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
851 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700852 if hasattr( main, 'Mininet1' ):
853 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
854 else:
855 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700856 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
857 main.scapyHosts = []
858
You Wang5da39c82018-04-26 22:55:08 -0700859 if removeHostComponent:
860 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
861 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700862 if hasattr( main, 'Mininet1' ):
863 pass
864 else:
865 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700866 main.Network.removeHostComponent( host )
867
You Wang5df1c6d2018-04-06 18:02:02 -0700868 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700869 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700870 else:
871 main.Network.disconnectInbandHosts()
872 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700873
You Wang5df1c6d2018-04-06 18:02:02 -0700874 if copyKarafLog:
875 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700876
Devin Lim142b5342017-07-20 15:22:39 -0700877 for ctrl in main.Cluster.active():
878 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700879
880 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700881 def verifyNodes( main ):
882 """
883 Verifies Each active node in the cluster has an accurate view of other node's and their status
884
885 Params:
886 nodes, integer array with position of the ONOS nodes in the CLIs array
887 """
888 nodeResults = utilities.retry( main.Cluster.nodesCheck,
889 False,
890 attempts=10,
891 sleep=10 )
892 utilities.assert_equals( expect=True, actual=nodeResults,
893 onpass="Nodes check successful",
894 onfail="Nodes check NOT successful" )
895
896 if not nodeResults:
897 for ctrl in main.Cluster.runningNodes:
898 main.log.debug( "{} components not ACTIVE: \n{}".format(
899 ctrl.name,
900 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
901 main.log.error( "Failed to kill ONOS, stopping test" )
902 main.cleanAndExit()
903
904 @staticmethod
905 def verifyTopology( main, switches, links, expNodes ):
906 """
907 Verifies that the ONOS cluster has an acuurate view of the topology
908
909 Params:
910 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
911 """
912 main.step( "Check number of topology elements" )
913 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
914 main.FALSE,
915 kwargs={ 'numoswitch': switches,
916 'numolink': links,
917 'numoctrl': expNodes },
918 attempts=10,
919 sleep=12 )
920 utilities.assert_equals( expect=main.TRUE, actual=topology,
921 onpass="Number of topology elements are correct",
922 onfail="Unexpected number of links, switches, and/or controllers" )
923
924 @staticmethod
925 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700926 """
927 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
928 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
929 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
930 """
Jon Halla604fd42018-05-04 14:27:27 -0700931 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800932 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700933 if sleep is None:
934 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
935 else:
936 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700937
Jon Hall1efcb3f2016-08-23 13:42:15 -0700938 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700939 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700940 utilities.assert_equals( expect=main.TRUE, actual=killResult,
941 onpass="ONOS instance Killed",
942 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700943 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700944 main.Cluster.reset()
945 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700946
Devin Lim142b5342017-07-20 15:22:39 -0700947 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700948 Testcaselib.verifyNodes( main )
949 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700950
951 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700952 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700953 """
954 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
955 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
956 Recover an ONOS instance and verify the ONOS cluster can see the proper change
957 """
Jon Hall3c910162018-03-07 14:42:16 -0800958 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700959 if sleep is None:
960 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
961 else:
962 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700963 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700964 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700965 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700966 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700967 utilities.assert_equals( expect=main.TRUE, actual=isUp,
968 onpass="ONOS service is ready",
969 onfail="ONOS service did not start properly" )
970 for i in nodes:
971 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700972 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900973 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700974 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
975 commandlineTimeout=60,
976 onosStartTimeout=100 )
977 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -0700978 utilities.assert_equals( expect=main.TRUE,
979 actual=cliResult,
980 onpass="ONOS CLI is ready",
981 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700982
Jon Halla604fd42018-05-04 14:27:27 -0700983 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -0700984 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -0700985 Testcaselib.verifyNodes( main )
986 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -0700987
Devin Lim142b5342017-07-20 15:22:39 -0700988 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
989 main.FALSE,
990 attempts=10,
991 sleep=12 )
992 if ready:
993 ready = main.TRUE
994 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700995 onpass="ONOS summary command succeded",
996 onfail="ONOS summary command failed" )
997 if not ready:
998 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700999 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001000
1001 @staticmethod
1002 def addHostCfg( main ):
1003 """
1004 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001005 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001006 """
1007 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001008 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001009 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001010 hostCfg = json.load( template )
1011 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1012 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001013 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001014 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1015 subjectClass="hosts",
1016 subjectKey=urllib.quote( mac,
1017 safe='' ),
1018 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001019 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1020 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001021 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001022 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1023 subjectClass="hosts",
1024 subjectKey=urllib.quote( mac,
1025 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001026 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001027 main.pingChart.update( { 'vlan1': { "expect": "True",
1028 "hosts": [ "olt1", "vsg1" ] } } )
1029 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1030 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001031 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001032 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001033 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1034 subjectClass="apps",
1035 subjectKey="org.onosproject.segmentrouting",
1036 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001037
1038 @staticmethod
1039 def delHostCfg( main ):
1040 """
1041 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001042 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001043 """
1044 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001045 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001046 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001047 hostCfg = json.load( template )
1048 main.step( "Removing host configuration" )
1049 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001050 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001051 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1052 subjectKey=urllib.quote(
1053 mac,
1054 safe='' ),
1055 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001056 main.step( "Removing configuration" )
1057 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001058 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001059 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1060 subjectKey=urllib.quote(
1061 mac,
1062 safe='' ),
1063 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001064 main.step( "Removing vlan configuration" )
1065 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001066 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1067 subjectKey="org.onosproject.segmentrouting",
1068 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001069
1070 @staticmethod
1071 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1072 """
1073 Verifies IP address assignment from the hosts
1074 """
1075 main.step( "Verify IP address assignment from hosts" )
1076 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001077 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001078 # Find out names of disconnected hosts
1079 disconnectedHosts = []
1080 if hasattr( main, "disconnectedIpv4Hosts" ):
1081 for host in main.disconnectedIpv4Hosts:
1082 disconnectedHosts.append( host )
1083 if hasattr( main, "disconnectedIpv6Hosts" ):
1084 for host in main.disconnectedIpv6Hosts:
1085 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001086 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001087 # Exclude disconnected hosts
1088 if hostName in disconnectedHosts:
1089 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1090 continue
You Wang53dba1e2018-02-02 17:45:44 -08001091 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1092 main.FALSE,
1093 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001094 'prefix': ip,
1095 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001096 attempts=attempts,
1097 sleep=sleep )
1098 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1099 onpass="Verify network host IP succeded",
1100 onfail="Verify network host IP failed" )
1101
1102 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001103 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001104 """
1105 Verifies host IP address assignment from ONOS
1106 """
1107 main.step( "Verify host IP address assignment in ONOS" )
1108 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001109 # Find out IPs of disconnected hosts
1110 disconnectedIps = []
1111 if hasattr( main, "disconnectedIpv4Hosts" ):
1112 for host in main.disconnectedIpv4Hosts:
1113 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1114 if hasattr( main, "disconnectedIpv6Hosts" ):
1115 for host in main.disconnectedIpv6Hosts:
1116 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001117 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001118 # Exclude disconnected hosts
1119 if ip in disconnectedIps:
1120 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1121 continue
You Wang53dba1e2018-02-02 17:45:44 -08001122 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1123 main.FALSE,
1124 kwargs={ 'hostList': [ hostName ],
1125 'prefix': ip },
1126 attempts=attempts,
1127 sleep=sleep )
1128 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1129 onpass="Verify ONOS host IP succeded",
1130 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001131 if not ipResult and skipOnFail:
1132 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001133 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001134 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001135
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001136 @staticmethod
1137 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1138 """
1139 Description:
1140 Updates interface configuration in ONOS, with given IP and vlan parameters
1141 Required:
1142 * connectPoint: connect point to update configuration
1143 Optional:
1144 * ips: list of IP addresses, combined with '/xx' subnet representation,
1145 corresponding to 'ips' field in the configuration
1146 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1147 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1148 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1149 """
1150 cfg = dict()
1151 cfg[ "ports" ] = dict()
1152 cfg[ "ports" ][ connectPoint ] = dict()
1153 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1154 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1155 if untagged > 0:
1156 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1157 else:
1158 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1159 if native > 0:
1160 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1161
1162 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001163
1164 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001165 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001166 """
1167 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001168 scapyNames: list of names that will be used as component names for scapy hosts
1169 mininetNames: used when scapy host names are different from the host names
1170 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1171 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001172 """
1173 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001174 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1175 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001176 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001177 if hasattr( main, 'Mininet1' ):
1178 main.Scapy.createHostComponent( scapyName )
1179 scapyHandle = getattr( main, scapyName )
1180 if mininetNames:
1181 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1182 else:
1183 mininetName = None
1184 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001185 else:
You Wang4cc61912018-08-28 10:10:58 -07001186 main.Network.createComponent( scapyName )
1187 scapyHandle = getattr( main, scapyName )
1188 scapyHandle.connectInband()
1189 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001190 scapyHandle.startScapy()
1191 scapyHandle.updateSelf()
1192 main.log.debug( scapyHandle.name )
1193 main.log.debug( scapyHandle.hostIp )
1194 main.log.debug( scapyHandle.hostMac )
1195
1196 @staticmethod
1197 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1198 """
1199 Verify unicast traffic by pinging from source hosts to the destination IP
1200 and capturing the packets at the destination host using Scapy.
1201 srcHosts: List of host names to send the ping packets
1202 dstIp: destination IP of the ping packets
1203 dstHost: host that runs Scapy to capture the packets
1204 dstIntf: name of the interface on the destination host
1205 expect: use True if the ping is expected to be captured at destination;
1206 Otherwise False
1207 skipOnFail: skip the rest of this test case if result is not expected
1208 maxRetry: number of retries allowed
1209 """
1210 from tests.dependencies.topology import Topology
1211 try:
1212 main.topo
1213 except ( NameError, AttributeError ):
1214 main.topo = Topology()
1215 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1216 result = main.TRUE
1217 for srcHost in srcHosts:
1218 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1219 expect, maxRetry, True )
1220 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001221 result = main.FALSE
1222 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1223 utilities.assert_equals( expect=main.TRUE,
1224 actual=result,
1225 onpass="Verify traffic to {}: Pass".format( dstIp ),
1226 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1227 if skipOnFail and result != main.TRUE:
1228 Testcaselib.saveOnosDiagnostics( main )
1229 Testcaselib.cleanup( main, copyKarafLog=False )
1230 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001231
1232 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001233 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001234 """
1235 Verify multicast traffic using scapy
1236 """
You Wangc564c6f2018-05-01 15:24:57 -07001237 from tests.dependencies.topology import Topology
1238 try:
1239 main.topo
1240 except ( NameError, AttributeError ):
1241 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001242 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001243 routeData = main.multicastConfig[ routeName ]
1244 srcs = main.mcastRoutes[ routeName ][ "src" ]
1245 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1246 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1247 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001248 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001249 for src in srcs:
1250 srcEntry = routeData[ "src" ][ src ]
1251 for dst in dsts:
1252 dstEntry = routeData[ "dst" ][ dst ]
1253 sender = getattr( main, srcEntry[ "host" ] )
1254 receiver = getattr( main, dstEntry[ "host" ] )
1255 main.Network.addRoute( str( srcEntry[ "host" ] ),
1256 str( routeData[ "group" ] ),
1257 str( srcEntry[ "interface" ] ),
1258 True if routeData[ "ipVersion" ] == 6 else False )
1259 # Build the packet
1260 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1261 if routeData[ "ipVersion" ] == 4:
1262 sender.buildIP( dst=str( routeData[ "group" ] ) )
1263 elif routeData[ "ipVersion" ] == 6:
1264 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1265 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1266 sIface = srcEntry[ "interface" ]
1267 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1268 pktFilter = srcEntry[ "filter" ]
1269 pkt = srcEntry[ "packet" ]
1270 # Send packet and check received packet
1271 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001272 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001273 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001274 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1275 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001276 if not trafficResult:
1277 result = main.FALSE
1278 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1279 dstEntry[ "host" ] ) )
1280 utilities.assert_equals( expect=main.TRUE,
1281 actual=result,
1282 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1283 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001284 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001285 Testcaselib.saveOnosDiagnostics( main )
1286 Testcaselib.cleanup( main, copyKarafLog=False )
1287 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001288
1289 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001290 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001291 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1292 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001293 """
1294 Verify reachability from each host in srcList to each host in dstList
1295 """
1296 from tests.dependencies.topology import Topology
1297 try:
1298 main.topo
1299 except ( NameError, AttributeError ):
1300 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001301 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001302 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001303 utilities.assert_equals( expect=main.TRUE,
1304 actual=pingResult,
1305 onpass="{}: Pass".format( stepMsg ),
1306 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001307 if not pingResult and skipOnFail:
1308 Testcaselib.saveOnosDiagnostics( main )
1309 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1310 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001311
1312 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001313 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001314 """
1315 Verify if the specified host is discovered by ONOS on the given locations
1316 Required:
You Wang85747762018-05-11 15:51:50 -07001317 locationDict: a dictionary that maps host names to expected locations.
1318 locations could be a string or a list.
1319 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001320 Returns:
1321 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1322 """
You Wang85747762018-05-11 15:51:50 -07001323 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1324 result = main.TRUE
1325 for hostName, locations in locationDict.items():
1326 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1327 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1328 if not hostIp:
1329 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1330 if not hostIp:
1331 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1332 result = main.FALSE
1333 continue
1334 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1335 main.FALSE,
1336 args=( hostIp, locations ),
1337 attempts=retry + 1,
1338 sleep=10 )
1339 if not locationResult:
1340 result = main.FALSE
1341 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001342 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001343 onpass="Location verification passed",
1344 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001345
1346 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001347 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001348 """
1349 Move specified host from srcSw to dstSw.
1350 If srcSw and dstSw are same, the host will be moved from current port to
1351 next available port.
1352 Required:
1353 hostName: name of the host. e.g., "h1"
1354 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1355 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1356 gw: ip address of the gateway of the new location
1357 Optional:
1358 macAddr: if specified, change MAC address of the host to the specified MAC address.
1359 prefixLen: prefix length
1360 cfg: port configuration as JSON string
1361 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001362 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001363 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001364 if not hasattr( main, 'Mininet1' ):
1365 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1366 return
1367
You Wang6e5b48e2018-07-23 16:17:38 -07001368 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1369 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1370 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001371 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001372 if cfg:
1373 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1374 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001375 # Wait for the host to get RA for setting up default gateway
1376 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001377
1378 main.Mininet1.discoverHosts( [ hostName, ] )
1379
1380 # Update expectedHost when MAC address is changed.
1381 if macAddr is not None:
1382 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1383 if ipAddr is not None:
1384 for hostName, ip in main.expectedHosts[ "onos" ].items():
1385 if ip == ipAddr:
1386 vlan = hostName.split( "/" )[ -1 ]
1387 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001388 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001389 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001390
1391 @staticmethod
1392 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001393 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001394 """
1395 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1396 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1397 to next available port.
1398 Required:
1399 hostName: name of the host. e.g., "h1"
1400 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1401 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1402 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1403 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1404 gw: ip address of the gateway of the new location
1405 Optional:
1406 macAddr: if specified, change MAC address of the host to the specified MAC address.
1407 prefixLen: prefix length
1408 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001409 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001410 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001411 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001412 if not hasattr( main, 'Mininet1' ):
1413 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1414 return
1415
You Wang6e5b48e2018-07-23 16:17:38 -07001416 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1417 srcSw, srcPairSw, dstSw, dstPairSw ) )
1418 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1419 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1420 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001421 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001422 if cfg:
1423 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1424 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001425 # Wait for the host to get RA for setting up default gateway
1426 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001427
1428 main.Mininet1.discoverHosts( [ hostName, ] )
1429
1430 # Update expectedHost when MAC address is changed.
1431 if macAddr is not None:
1432 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1433 if ipAddr is not None:
1434 for hostName, ip in main.expectedHosts[ "onos" ].items():
1435 if ip == ipAddr:
1436 vlan = hostName.split( "/" )[ -1 ]
1437 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001438 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip