blob: 7464373f659a2bf443420276662f2924171005e7 [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 Wang84f981d2018-01-12 16:11:50 -0800223 def connectToPhysicalNetwork( main, switchNames ):
224 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
237 for name in switchNames:
238 assignResult = assignResult & main.NetworkBench.assignSwController( sw=name,
239 ip=main.Cluster.getIps(),
240 port='6653' )
241 utilities.assert_equals( expect=main.TRUE,
242 actual=stepResult,
243 onpass="Successfully assign switches to controllers",
244 onfail="Failed to assign switches to controllers" )
245
246 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700247 def saveOnosDiagnostics( main ):
248 """
249 Get onos-diags.tar.gz and save it to the log directory.
250 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
251 """
252 main.log.info( "Collecting onos-diags..." )
253 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
254 main.logdir,
255 "-CASE%d" % main.CurrentTestCaseNumber )
256
257 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700258 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700259 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700260
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700261 main.failures = int( main.params[ 'failures' ] )
262 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700263
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700264 if main.cfgName == '2x2':
265 spine = {}
266 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
267 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
268 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700269
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700270 spine = {}
271 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
272 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
273 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700274
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700275 elif main.cfgName == '4x4':
276 spine = {}
277 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
278 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
279 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700280
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700281 spine = {}
282 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
283 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
284 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700285
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700286 spine = {}
287 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
288 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
289 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700290
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700291 spine = {}
292 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
293 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
294 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700295
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700296 else:
Piera2a7e1b2016-10-04 11:51:43 -0700297 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700298 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800299
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800300 @staticmethod
301 def addStaticOnosRoute( main, subnet, intf):
302 """
303 Adds an ONOS static route with the use route-add command.
304 """
305 main.step("Add static route for subnet {0} towards router interface {1}".format(subnet, intf))
306 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
307
308 utilities.assert_equals( expect=True, actual=( not routeResult ),
309 onpass="route-add command succeeded",
310 onfail="route-add command failed")
Piera2a7e1b2016-10-04 11:51:43 -0700311
312 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700313 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700314 """
315 Check number of groups for each subnet on device deviceId and matches
316 it with an expected value. subnetDict is a dictionarty containing values
317 of the type "10.0.1.0/24" : 5.
318 """
You Wangc02f3be2018-05-18 12:14:23 -0700319 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
320 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
321 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700322
You Wangc02f3be2018-05-18 12:14:23 -0700323 result = main.TRUE
324 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700325 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700326 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700327 # this will match the group id that this flow entry points to, for example :
328 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700329 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700330 count = 0
331 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700332 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700333 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700334 if count - 1 != numberInSelect:
335 result = main.FALSE
336 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 ) )
337 utilities.assert_equals( expect=main.TRUE, actual=result,
338 onpass="All bucket numbers are as expected",
339 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700340
341 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900342 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700343 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800344 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900345 if tag == "":
346 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700347 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700348 main.FALSE,
349 kwargs={ 'min': minFlowCount },
350 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800351 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700352 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700353 expect=True,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700354 actual=( count > 0 ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700355 onpass="Flow count looks correct: " + str( count ),
356 onfail="Flow count looks wrong: " + str( count ) )
357
358 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700359 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700360 main.FALSE,
361 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800362 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800363 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700364 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700365 expect=main.TRUE,
366 actual=flowCheck,
367 onpass="Flow status is correct!",
368 onfail="Flow status is wrong!" )
369 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700370 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700371 "flows",
372 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900373 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700374 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700375 "groups",
376 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900377 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700378
379 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700380 def checkDevices( main, switches, tag="", sleep=10 ):
381 main.step(
382 "Check whether the switches count is equal to %s" % switches )
383 if tag == "":
384 tag = 'CASE%d' % main.CurrentTestCaseNumber
385 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
386 main.FALSE,
387 kwargs={ 'numoswitch': switches},
388 attempts=10,
389 sleep=sleep )
390 utilities.assert_equals( expect=main.TRUE, actual=result,
391 onpass="Device up successful",
392 onfail="Failed to boot up devices?" )
393
394 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800395 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
396 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800397 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
398 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
399 main.FALSE,
400 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800401 attempts=5,
402 sleep=sleep )
403 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800404 expect=True,
405 actual=( count > minFlowCount ),
406 onpass="Flow count looks correct: " + str( count ),
407 onfail="Flow count looks wrong. " )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800408
409 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700410 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800411 main.step(
412 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
413 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
414 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700415 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800416 attempts=5,
417 sleep=sleep )
418
419 utilities.assertEquals(
420 expect=True,
421 actual=( int( count ) == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700422 onpass="Flow count looks correct: " + str( count ) ,
423 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800424
425 @staticmethod
426 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
427 main.step(
428 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
429 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
430 main.FALSE,
431 args=( dpid, groupCount, False, 1),
432 attempts=5,
433 sleep=sleep )
434
435 utilities.assertEquals(
436 expect=True,
437 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700438 onpass="Group count looks correct: " + str( count ) ,
439 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800440
441 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700442 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800443
444 for dpid, values in main.count.items():
445 flowCount = values["flows"]
446 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700447 main.log.report( "Check flow count for dpid " + str( dpid ) +
448 ", should be " + str( flowCount ) )
449 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800450
Jon Hall9677ed32018-04-24 11:16:23 -0700451 main.log.report( "Check group count for dpid " + str( dpid ) +
452 ", should be " + str( groupCount ) )
453 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800454
455 return
456
457 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700458 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
459 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800460 '''
You Wangba231e72018-03-01 13:18:21 -0800461 Verify connectivity between hosts according to the ping chart
462 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800463 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800464 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800465 '''
You Wangba231e72018-03-01 13:18:21 -0800466 main.log.report( "Check host connectivity" )
467 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800468 if tag == "":
469 tag = 'CASE%d' % main.CurrentTestCaseNumber
470 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800471 main.log.debug( "Entry in ping chart: %s" % entry )
472 expect = entry[ 'expect' ]
473 if expect == "Unidirectional":
474 # Verify ping from each src host to each dst host
475 src = entry[ 'src' ]
476 dst = entry[ 'dst' ]
477 expect = main.TRUE
478 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
479 if basedOnIp:
480 if ("v4" in src[0]):
481 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
482 utilities.assert_equals( expect=expect, actual=pa,
483 onpass="IPv4 connectivity successfully tested",
484 onfail="IPv4 connectivity failed" )
485 if ("v6" in src[0]):
486 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
487 utilities.assert_equals( expect=expect, actual=pa,
488 onpass="IPv6 connectivity successfully tested",
489 onfail="IPv6 connectivity failed" )
490 else:
491 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
492 utilities.assert_equals( expect=expect, actual=pa,
493 onpass="IP connectivity successfully tested",
494 onfail="IP connectivity failed" )
495 else:
496 # Verify ping between each host pair
497 hosts = entry[ 'hosts' ]
498 try:
499 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
500 except:
501 expect = main.FALSE
502 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
503 if basedOnIp:
504 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800505 pa = utilities.retry( main.Network.pingallHosts,
506 main.FALSE if expect else main.TRUE,
507 args=(hosts,),
508 attempts=retryAttempts,
509 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800510 utilities.assert_equals( expect=expect, actual=pa,
511 onpass="IPv4 connectivity successfully tested",
512 onfail="IPv4 connectivity failed" )
513 if ("v6" in hosts[0]):
514 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
515 utilities.assert_equals( expect=expect, actual=pa,
516 onpass="IPv6 connectivity successfully tested",
517 onfail="IPv6 connectivity failed" )
518 else:
You Wangf19d9f42018-02-23 16:34:19 -0800519 pa = main.Network.pingallHosts( hosts )
520 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800521 onpass="IP connectivity successfully tested",
522 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700523 if skipOnFail and pa != expect:
524 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700525 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700526 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800527
528 if dumpflows:
529 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
530 "flows",
531 main.logdir,
532 tag + "_FlowsOn" )
533 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
534 "groups",
535 main.logdir,
536 tag + "_GroupsOn" )
537
538 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700539 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700540 """
541 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
542 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
543 Kill a link and verify ONOS can see the proper link change
544 """
Jon Halla604fd42018-05-04 14:27:27 -0700545 if sleep is None:
546 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
547 else:
548 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700549 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700550 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
551 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
552 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700553 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700554 "Waiting %s seconds for link down to be discovered" % sleep )
555 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700556 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700557 main.FALSE,
558 kwargs={ 'numoswitch': switches,
559 'numolink': links },
560 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700561 sleep=sleep )
562 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700563 utilities.assert_equals( expect=main.TRUE, actual=result,
564 onpass="Link down successful",
565 onfail="Failed to turn off link?" )
566
567 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700568 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800569 """
570 links = list of links (src, dst) to bring down.
571 """
572
573 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700574 if sleep is None:
575 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
576 else:
577 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800578
579 for end1, end2 in links:
580 main.Network.link( END1=end1, END2=end2, OPTION="down")
581 main.Network.link( END1=end2, END2=end1, OPTION="down")
582
Jon Halla604fd42018-05-04 14:27:27 -0700583 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800584 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700585 "Waiting %s seconds for links down to be discovered" % sleep )
586 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800587
588 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
589 main.FALSE,
590 kwargs={ 'numoswitch': switches,
591 'numolink': linksAfter },
592 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700593 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800594
You Wang2854bce2018-03-30 10:15:32 -0700595 utilities.assert_equals( expect=main.TRUE, actual=topology,
596 onpass="Link batch down successful",
597 onfail="Link batch down failed" )
598
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800599 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700600 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800601 """
602 links = list of link (src, dst) to bring up again.
603 """
604
605 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700606 if sleep is None:
607 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
608 else:
609 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800610
611 for end1, end2 in links:
612 main.Network.link( END1=end1, END2=end2, OPTION="up")
613 main.Network.link( END1=end2, END2=end1, OPTION="up")
614
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800615 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700616 "Waiting %s seconds for links up to be discovered" % sleep )
617 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800618
619 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
620 main.FALSE,
621 kwargs={ 'numoswitch': switches,
622 'numolink': linksAfter },
623 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700624 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800625
You Wang2854bce2018-03-30 10:15:32 -0700626 utilities.assert_equals( expect=main.TRUE, actual=topology,
627 onpass="Link batch up successful",
628 onfail="Link batch up failed" )
629
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800630 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700631 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
632 """
633 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
634 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
635 switches, links: number of expected switches and links after link change, ex.: '4', '6'
636 """
637 if sleep is None:
638 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
639 else:
640 sleep = float( sleep )
641 main.step( "Disable a batch of ports" )
642 for dpid, port in ports:
643 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
644 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
645 time.sleep( sleep )
646 if switches and links:
647 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
648 numolink=links )
649 utilities.assert_equals( expect=main.TRUE, actual=result,
650 onpass="Port down successful",
651 onfail="Port down failed" )
652
653 @staticmethod
654 def enablePortBatch( main, ports, switches, links, sleep=None ):
655 """
656 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
657 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
658 switches, links: number of expected switches and links after link change, ex.: '4', '6'
659 """
660 if sleep is None:
661 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
662 else:
663 sleep = float( sleep )
664 main.step( "Enable a batch of ports" )
665 for dpid, port in ports:
666 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
667 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
668 time.sleep( sleep )
669 if switches and links:
670 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
671 numolink=links )
672 utilities.assert_equals( expect=main.TRUE, actual=result,
673 onpass="Port up successful",
674 onfail="Port up failed" )
675
676 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700677 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700678 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700679 """
680 Params:
681 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700682 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700683 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
684 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
685 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
686 Kill a link and verify ONOS can see the proper link change
687 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700688 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700689 if sleep is None:
690 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
691 else:
692 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700693 result = False
694 count = 0
695 while True:
696 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700697 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800698 main.Network.link( END1=end1, END2=end2, OPTION="up" )
699 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700700 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700701 "Waiting %s seconds for link up to be discovered" % sleep )
702 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700703
You Wangc02d8352018-04-17 16:42:10 -0700704 if portUp:
705 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
706 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700707 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700708
Jon Halla604fd42018-05-04 14:27:27 -0700709 result = ctrl.CLI.checkStatus( numoswitch=switches,
710 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700711 if count > 5 or result:
712 break
713 utilities.assert_equals( expect=main.TRUE, actual=result,
714 onpass="Link up successful",
715 onfail="Failed to bring link up" )
716
717 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700718 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700719 """
720 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
721 Completely kill a switch and verify ONOS can see the proper change
722 """
Jon Halla604fd42018-05-04 14:27:27 -0700723 if sleep is None:
724 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
725 else:
726 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700727 switch = switch if isinstance( switch, list ) else [ switch ]
728 main.step( "Kill " + str( switch ) )
729 for s in switch:
730 main.log.info( "Stopping " + s )
731 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700732 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700733
734 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700735 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700736 sleep ) )
737 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700738 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700739 main.FALSE,
740 kwargs={ 'numoswitch': switches,
741 'numolink': links },
742 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700743 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700744 utilities.assert_equals( expect=main.TRUE, actual=topology,
745 onpass="Kill switch successful",
746 onfail="Failed to kill switch?" )
747
748 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700749 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700750 """
751 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
752 Recover a switch and verify ONOS can see the proper change
753 """
Jon Halla604fd42018-05-04 14:27:27 -0700754 if sleep is None:
755 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
756 else:
757 sleep = float( sleep )
758 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700759 switch = switch if isinstance( switch, list ) else [ switch ]
760 main.step( "Recovering " + str( switch ) )
761 for s in switch:
762 main.log.info( "Starting " + s )
763 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700764 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700765 sleep ) )
766 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700767 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700768 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700769 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700770 sleep ) )
771 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700772
Devin Lim142b5342017-07-20 15:22:39 -0700773 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700774 main.FALSE,
775 kwargs={ 'numoswitch': switches,
776 'numolink': links },
777 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700778 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700779 utilities.assert_equals( expect=main.TRUE, actual=topology,
780 onpass="Switch recovery successful",
781 onfail="Failed to recover switch?" )
782
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700783 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700784 def killRouter( main, router, sleep=None ):
785 """
786 Kill bgpd process on a quagga router
787 router: name of the router to be killed. E.g. "bgp1"
788 """
789 sleep = float( sleep )
790 main.step( "Kill " + str( router ) )
791 if hasattr( main, 'Mininet1' ):
792 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
793 main.Mininet1.handle.expect( "mininet>" )
794 else:
795 # TODO: support killing router in physical network
796 pass
797 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
798 time.sleep( sleep )
799
800 @staticmethod
801 def recoverRouter( main, router, sleep=None ):
802 """
803 Restart bgpd process on a quagga router
804 router: name of the router to be recovered. E.g. "bgp1"
805 """
806 sleep = float( sleep )
807 main.step( "Recovering " + str( router ) )
808 if hasattr( main, 'Mininet1' ):
809 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
810 main.Mininet1.handle.expect( "mininet>" )
811 else:
812 # TODO: support recovering router in physical network
813 pass
814 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
815 time.sleep( sleep )
816
817 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700818 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700819 """
820 Stop Onos-cluster.
821 Stops Mininet
822 Copies ONOS log
823 """
Devin Lim58046fa2017-07-05 16:55:00 -0700824 try:
825 from tests.dependencies.utils import Utils
826 except ImportError:
827 main.log.error( "Utils not found exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -0700828 main.cleanAndExit()
Devin Lim58046fa2017-07-05 16:55:00 -0700829 try:
Devin Lim142b5342017-07-20 15:22:39 -0700830 main.utils
Devin Lim58046fa2017-07-05 16:55:00 -0700831 except ( NameError, AttributeError ):
Devin Lim142b5342017-07-20 15:22:39 -0700832 main.utils = Utils()
Devin Lim58046fa2017-07-05 16:55:00 -0700833
You Wange24d6272018-03-27 21:18:50 -0700834 if hasattr( main, "scapyHosts" ):
835 scapyResult = main.TRUE
836 for host in main.scapyHosts:
837 scapyResult = host.stopScapy() and scapyResult
838 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
839 for host in main.scapyHosts:
840 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
841 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
842 main.scapyHosts = []
843
You Wang5da39c82018-04-26 22:55:08 -0700844 if removeHostComponent:
845 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
846 if hasattr( main, host ):
847 main.Network.removeHostComponent( host )
848
You Wang5df1c6d2018-04-06 18:02:02 -0700849 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700850 main.utils.mininetCleanup( main.Mininet1 )
Devin Lim58046fa2017-07-05 16:55:00 -0700851
You Wang5df1c6d2018-04-06 18:02:02 -0700852 if copyKarafLog:
853 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700854
Devin Lim142b5342017-07-20 15:22:39 -0700855 for ctrl in main.Cluster.active():
856 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700857
858 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700859 def verifyNodes( main ):
860 """
861 Verifies Each active node in the cluster has an accurate view of other node's and their status
862
863 Params:
864 nodes, integer array with position of the ONOS nodes in the CLIs array
865 """
866 nodeResults = utilities.retry( main.Cluster.nodesCheck,
867 False,
868 attempts=10,
869 sleep=10 )
870 utilities.assert_equals( expect=True, actual=nodeResults,
871 onpass="Nodes check successful",
872 onfail="Nodes check NOT successful" )
873
874 if not nodeResults:
875 for ctrl in main.Cluster.runningNodes:
876 main.log.debug( "{} components not ACTIVE: \n{}".format(
877 ctrl.name,
878 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
879 main.log.error( "Failed to kill ONOS, stopping test" )
880 main.cleanAndExit()
881
882 @staticmethod
883 def verifyTopology( main, switches, links, expNodes ):
884 """
885 Verifies that the ONOS cluster has an acuurate view of the topology
886
887 Params:
888 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
889 """
890 main.step( "Check number of topology elements" )
891 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
892 main.FALSE,
893 kwargs={ 'numoswitch': switches,
894 'numolink': links,
895 'numoctrl': expNodes },
896 attempts=10,
897 sleep=12 )
898 utilities.assert_equals( expect=main.TRUE, actual=topology,
899 onpass="Number of topology elements are correct",
900 onfail="Unexpected number of links, switches, and/or controllers" )
901
902 @staticmethod
903 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700904 """
905 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
906 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
907 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
908 """
Jon Halla604fd42018-05-04 14:27:27 -0700909 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800910 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700911 if sleep is None:
912 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
913 else:
914 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700915
Jon Hall1efcb3f2016-08-23 13:42:15 -0700916 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700917 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700918 utilities.assert_equals( expect=main.TRUE, actual=killResult,
919 onpass="ONOS instance Killed",
920 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700921 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700922 main.Cluster.reset()
923 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700924
Devin Lim142b5342017-07-20 15:22:39 -0700925 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700926 Testcaselib.verifyNodes( main )
927 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700928
929 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700930 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700931 """
932 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
933 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
934 Recover an ONOS instance and verify the ONOS cluster can see the proper change
935 """
Jon Hall3c910162018-03-07 14:42:16 -0800936 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700937 if sleep is None:
938 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
939 else:
940 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700941 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700942 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700943 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700944 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700945 utilities.assert_equals( expect=main.TRUE, actual=isUp,
946 onpass="ONOS service is ready",
947 onfail="ONOS service did not start properly" )
948 for i in nodes:
949 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700950 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900951 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700952 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
953 commandlineTimeout=60,
954 onosStartTimeout=100 )
955 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -0700956 utilities.assert_equals( expect=main.TRUE,
957 actual=cliResult,
958 onpass="ONOS CLI is ready",
959 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700960
Jon Halla604fd42018-05-04 14:27:27 -0700961 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -0700962 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -0700963 Testcaselib.verifyNodes( main )
964 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -0700965
Devin Lim142b5342017-07-20 15:22:39 -0700966 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
967 main.FALSE,
968 attempts=10,
969 sleep=12 )
970 if ready:
971 ready = main.TRUE
972 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700973 onpass="ONOS summary command succeded",
974 onfail="ONOS summary command failed" )
975 if not ready:
976 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700977 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700978
979 @staticmethod
980 def addHostCfg( main ):
981 """
982 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700983 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700984 """
985 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700986 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -0800987 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -0700988 hostCfg = json.load( template )
989 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
990 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700991 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -0700992 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
993 subjectClass="hosts",
994 subjectKey=urllib.quote( mac,
995 safe='' ),
996 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700997 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
998 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700999 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001000 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1001 subjectClass="hosts",
1002 subjectKey=urllib.quote( mac,
1003 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001004 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001005 main.pingChart.update( { 'vlan1': { "expect": "True",
1006 "hosts": [ "olt1", "vsg1" ] } } )
1007 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1008 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001009 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001010 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001011 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1012 subjectClass="apps",
1013 subjectKey="org.onosproject.segmentrouting",
1014 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001015
1016 @staticmethod
1017 def delHostCfg( main ):
1018 """
1019 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001020 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001021 """
1022 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001023 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001024 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001025 hostCfg = json.load( template )
1026 main.step( "Removing host configuration" )
1027 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001028 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001029 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1030 subjectKey=urllib.quote(
1031 mac,
1032 safe='' ),
1033 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001034 main.step( "Removing configuration" )
1035 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001036 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001037 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1038 subjectKey=urllib.quote(
1039 mac,
1040 safe='' ),
1041 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001042 main.step( "Removing vlan configuration" )
1043 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001044 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1045 subjectKey="org.onosproject.segmentrouting",
1046 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001047
1048 @staticmethod
1049 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1050 """
1051 Verifies IP address assignment from the hosts
1052 """
1053 main.step( "Verify IP address assignment from hosts" )
1054 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001055 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001056 # Find out names of disconnected hosts
1057 disconnectedHosts = []
1058 if hasattr( main, "disconnectedIpv4Hosts" ):
1059 for host in main.disconnectedIpv4Hosts:
1060 disconnectedHosts.append( host )
1061 if hasattr( main, "disconnectedIpv6Hosts" ):
1062 for host in main.disconnectedIpv6Hosts:
1063 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001064 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001065 # Exclude disconnected hosts
1066 if hostName in disconnectedHosts:
1067 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1068 continue
You Wang53dba1e2018-02-02 17:45:44 -08001069 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1070 main.FALSE,
1071 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001072 'prefix': ip,
1073 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001074 attempts=attempts,
1075 sleep=sleep )
1076 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1077 onpass="Verify network host IP succeded",
1078 onfail="Verify network host IP failed" )
1079
1080 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001081 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001082 """
1083 Verifies host IP address assignment from ONOS
1084 """
1085 main.step( "Verify host IP address assignment in ONOS" )
1086 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001087 # Find out IPs of disconnected hosts
1088 disconnectedIps = []
1089 if hasattr( main, "disconnectedIpv4Hosts" ):
1090 for host in main.disconnectedIpv4Hosts:
1091 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1092 if hasattr( main, "disconnectedIpv6Hosts" ):
1093 for host in main.disconnectedIpv6Hosts:
1094 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001095 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001096 # Exclude disconnected hosts
1097 if ip in disconnectedIps:
1098 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1099 continue
You Wang53dba1e2018-02-02 17:45:44 -08001100 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1101 main.FALSE,
1102 kwargs={ 'hostList': [ hostName ],
1103 'prefix': ip },
1104 attempts=attempts,
1105 sleep=sleep )
1106 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1107 onpass="Verify ONOS host IP succeded",
1108 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001109 if not ipResult and skipOnFail:
1110 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001111 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001112 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001113
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001114 @staticmethod
1115 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1116 """
1117 Description:
1118 Updates interface configuration in ONOS, with given IP and vlan parameters
1119 Required:
1120 * connectPoint: connect point to update configuration
1121 Optional:
1122 * ips: list of IP addresses, combined with '/xx' subnet representation,
1123 corresponding to 'ips' field in the configuration
1124 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1125 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1126 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1127 """
1128 cfg = dict()
1129 cfg[ "ports" ] = dict()
1130 cfg[ "ports" ][ connectPoint ] = dict()
1131 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1132 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1133 if untagged > 0:
1134 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1135 else:
1136 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1137 if native > 0:
1138 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1139
1140 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001141
1142 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001143 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001144 """
1145 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001146 scapyNames: list of names that will be used as component names for scapy hosts
1147 mininetNames: used when scapy host names are different from the host names
1148 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1149 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001150 """
1151 main.step( "Start Scapy CLIs" )
You Wang2cb70172018-07-25 16:44:13 -07001152 if scapyNames:
1153 main.scapyNames = scapyNames
1154 else:
1155 main.scapyNames = main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
You Wangf24904e2018-08-03 15:36:41 -07001156 if not hasattr( main, "scapyHosts" ):
1157 main.scapyHosts = []
You Wang2cb70172018-07-25 16:44:13 -07001158 for scapyName in main.scapyNames:
1159 main.Scapy.createHostComponent( scapyName )
1160 scapyHandle = getattr( main, scapyName )
1161 main.scapyHosts.append( scapyHandle )
1162 if mininetNames:
1163 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1164 else:
1165 mininetName = None
1166 scapyHandle.startHostCli( mininetName )
1167 scapyHandle.startScapy()
1168 scapyHandle.updateSelf()
1169 main.log.debug( scapyHandle.name )
1170 main.log.debug( scapyHandle.hostIp )
1171 main.log.debug( scapyHandle.hostMac )
1172
1173 @staticmethod
1174 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1175 """
1176 Verify unicast traffic by pinging from source hosts to the destination IP
1177 and capturing the packets at the destination host using Scapy.
1178 srcHosts: List of host names to send the ping packets
1179 dstIp: destination IP of the ping packets
1180 dstHost: host that runs Scapy to capture the packets
1181 dstIntf: name of the interface on the destination host
1182 expect: use True if the ping is expected to be captured at destination;
1183 Otherwise False
1184 skipOnFail: skip the rest of this test case if result is not expected
1185 maxRetry: number of retries allowed
1186 """
1187 from tests.dependencies.topology import Topology
1188 try:
1189 main.topo
1190 except ( NameError, AttributeError ):
1191 main.topo = Topology()
1192 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1193 result = main.TRUE
1194 for srcHost in srcHosts:
1195 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1196 expect, maxRetry, True )
1197 if not trafficResult:
1198 main.stop()
1199 result = main.FALSE
1200 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1201 utilities.assert_equals( expect=main.TRUE,
1202 actual=result,
1203 onpass="Verify traffic to {}: Pass".format( dstIp ),
1204 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1205 if skipOnFail and result != main.TRUE:
1206 Testcaselib.saveOnosDiagnostics( main )
1207 Testcaselib.cleanup( main, copyKarafLog=False )
1208 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001209
1210 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001211 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001212 """
1213 Verify multicast traffic using scapy
1214 """
You Wangc564c6f2018-05-01 15:24:57 -07001215 from tests.dependencies.topology import Topology
1216 try:
1217 main.topo
1218 except ( NameError, AttributeError ):
1219 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001220 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001221 routeData = main.multicastConfig[ routeName ]
1222 srcs = main.mcastRoutes[ routeName ][ "src" ]
1223 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1224 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1225 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001226 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001227 for src in srcs:
1228 srcEntry = routeData[ "src" ][ src ]
1229 for dst in dsts:
1230 dstEntry = routeData[ "dst" ][ dst ]
1231 sender = getattr( main, srcEntry[ "host" ] )
1232 receiver = getattr( main, dstEntry[ "host" ] )
1233 main.Network.addRoute( str( srcEntry[ "host" ] ),
1234 str( routeData[ "group" ] ),
1235 str( srcEntry[ "interface" ] ),
1236 True if routeData[ "ipVersion" ] == 6 else False )
1237 # Build the packet
1238 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1239 if routeData[ "ipVersion" ] == 4:
1240 sender.buildIP( dst=str( routeData[ "group" ] ) )
1241 elif routeData[ "ipVersion" ] == 6:
1242 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1243 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1244 sIface = srcEntry[ "interface" ]
1245 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1246 pktFilter = srcEntry[ "filter" ]
1247 pkt = srcEntry[ "packet" ]
1248 # Send packet and check received packet
1249 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001250 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001251 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001252 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1253 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001254 if not trafficResult:
1255 result = main.FALSE
1256 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1257 dstEntry[ "host" ] ) )
1258 utilities.assert_equals( expect=main.TRUE,
1259 actual=result,
1260 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1261 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001262 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001263 Testcaselib.saveOnosDiagnostics( main )
1264 Testcaselib.cleanup( main, copyKarafLog=False )
1265 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001266
1267 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001268 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001269 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1270 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001271 """
1272 Verify reachability from each host in srcList to each host in dstList
1273 """
1274 from tests.dependencies.topology import Topology
1275 try:
1276 main.topo
1277 except ( NameError, AttributeError ):
1278 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001279 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001280 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001281 utilities.assert_equals( expect=main.TRUE,
1282 actual=pingResult,
1283 onpass="{}: Pass".format( stepMsg ),
1284 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001285 if not pingResult and skipOnFail:
1286 Testcaselib.saveOnosDiagnostics( main )
1287 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1288 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001289
1290 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001291 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001292 """
1293 Verify if the specified host is discovered by ONOS on the given locations
1294 Required:
You Wang85747762018-05-11 15:51:50 -07001295 locationDict: a dictionary that maps host names to expected locations.
1296 locations could be a string or a list.
1297 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001298 Returns:
1299 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1300 """
You Wang85747762018-05-11 15:51:50 -07001301 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1302 result = main.TRUE
1303 for hostName, locations in locationDict.items():
1304 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1305 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1306 if not hostIp:
1307 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1308 if not hostIp:
1309 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1310 result = main.FALSE
1311 continue
1312 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1313 main.FALSE,
1314 args=( hostIp, locations ),
1315 attempts=retry + 1,
1316 sleep=10 )
1317 if not locationResult:
1318 result = main.FALSE
1319 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001320 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001321 onpass="Location verification passed",
1322 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001323
1324 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001325 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001326 """
1327 Move specified host from srcSw to dstSw.
1328 If srcSw and dstSw are same, the host will be moved from current port to
1329 next available port.
1330 Required:
1331 hostName: name of the host. e.g., "h1"
1332 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1333 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1334 gw: ip address of the gateway of the new location
1335 Optional:
1336 macAddr: if specified, change MAC address of the host to the specified MAC address.
1337 prefixLen: prefix length
1338 cfg: port configuration as JSON string
1339 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001340 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001341 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001342 if not hasattr( main, 'Mininet1' ):
1343 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1344 return
1345
You Wang6e5b48e2018-07-23 16:17:38 -07001346 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1347 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1348 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001349 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001350 if cfg:
1351 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1352 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001353 # Wait for the host to get RA for setting up default gateway
1354 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001355
1356 main.Mininet1.discoverHosts( [ hostName, ] )
1357
1358 # Update expectedHost when MAC address is changed.
1359 if macAddr is not None:
1360 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1361 if ipAddr is not None:
1362 for hostName, ip in main.expectedHosts[ "onos" ].items():
1363 if ip == ipAddr:
1364 vlan = hostName.split( "/" )[ -1 ]
1365 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001366 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001367 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001368
1369 @staticmethod
1370 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001371 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001372 """
1373 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1374 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1375 to next available port.
1376 Required:
1377 hostName: name of the host. e.g., "h1"
1378 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1379 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1380 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1381 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1382 gw: ip address of the gateway of the new location
1383 Optional:
1384 macAddr: if specified, change MAC address of the host to the specified MAC address.
1385 prefixLen: prefix length
1386 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001387 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001388 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001389 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001390 if not hasattr( main, 'Mininet1' ):
1391 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1392 return
1393
You Wang6e5b48e2018-07-23 16:17:38 -07001394 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1395 srcSw, srcPairSw, dstSw, dstPairSw ) )
1396 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1397 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1398 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001399 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001400 if cfg:
1401 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1402 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001403 # Wait for the host to get RA for setting up default gateway
1404 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001405
1406 main.Mininet1.discoverHosts( [ hostName, ] )
1407
1408 # Update expectedHost when MAC address is changed.
1409 if macAddr is not None:
1410 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1411 if ipAddr is not None:
1412 for hostName, ip in main.expectedHosts[ "onos" ].items():
1413 if ip == ipAddr:
1414 vlan = hostName.split( "/" )[ -1 ]
1415 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001416 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip