blob: e9bb8fe62bb35c7cf7b0a66041e2ee6ee8b5581a [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 Wang5da39c82018-04-26 22:55:08 -0700784 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700785 """
786 Stop Onos-cluster.
787 Stops Mininet
788 Copies ONOS log
789 """
Devin Lim58046fa2017-07-05 16:55:00 -0700790 try:
791 from tests.dependencies.utils import Utils
792 except ImportError:
793 main.log.error( "Utils not found exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -0700794 main.cleanAndExit()
Devin Lim58046fa2017-07-05 16:55:00 -0700795 try:
Devin Lim142b5342017-07-20 15:22:39 -0700796 main.utils
Devin Lim58046fa2017-07-05 16:55:00 -0700797 except ( NameError, AttributeError ):
Devin Lim142b5342017-07-20 15:22:39 -0700798 main.utils = Utils()
Devin Lim58046fa2017-07-05 16:55:00 -0700799
You Wange24d6272018-03-27 21:18:50 -0700800 if hasattr( main, "scapyHosts" ):
801 scapyResult = main.TRUE
802 for host in main.scapyHosts:
803 scapyResult = host.stopScapy() and scapyResult
804 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
805 for host in main.scapyHosts:
806 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
807 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
808 main.scapyHosts = []
809
You Wang5da39c82018-04-26 22:55:08 -0700810 if removeHostComponent:
811 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
812 if hasattr( main, host ):
813 main.Network.removeHostComponent( host )
814
You Wang5df1c6d2018-04-06 18:02:02 -0700815 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700816 main.utils.mininetCleanup( main.Mininet1 )
Devin Lim58046fa2017-07-05 16:55:00 -0700817
You Wang5df1c6d2018-04-06 18:02:02 -0700818 if copyKarafLog:
819 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700820
Devin Lim142b5342017-07-20 15:22:39 -0700821 for ctrl in main.Cluster.active():
822 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700823
824 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700825 def verifyNodes( main ):
826 """
827 Verifies Each active node in the cluster has an accurate view of other node's and their status
828
829 Params:
830 nodes, integer array with position of the ONOS nodes in the CLIs array
831 """
832 nodeResults = utilities.retry( main.Cluster.nodesCheck,
833 False,
834 attempts=10,
835 sleep=10 )
836 utilities.assert_equals( expect=True, actual=nodeResults,
837 onpass="Nodes check successful",
838 onfail="Nodes check NOT successful" )
839
840 if not nodeResults:
841 for ctrl in main.Cluster.runningNodes:
842 main.log.debug( "{} components not ACTIVE: \n{}".format(
843 ctrl.name,
844 ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
845 main.log.error( "Failed to kill ONOS, stopping test" )
846 main.cleanAndExit()
847
848 @staticmethod
849 def verifyTopology( main, switches, links, expNodes ):
850 """
851 Verifies that the ONOS cluster has an acuurate view of the topology
852
853 Params:
854 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
855 """
856 main.step( "Check number of topology elements" )
857 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
858 main.FALSE,
859 kwargs={ 'numoswitch': switches,
860 'numolink': links,
861 'numoctrl': expNodes },
862 attempts=10,
863 sleep=12 )
864 utilities.assert_equals( expect=main.TRUE, actual=topology,
865 onpass="Number of topology elements are correct",
866 onfail="Unexpected number of links, switches, and/or controllers" )
867
868 @staticmethod
869 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700870 """
871 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
872 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
873 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
874 """
Jon Halla604fd42018-05-04 14:27:27 -0700875 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800876 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700877 if sleep is None:
878 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
879 else:
880 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700881
Jon Hall1efcb3f2016-08-23 13:42:15 -0700882 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700883 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700884 utilities.assert_equals( expect=main.TRUE, actual=killResult,
885 onpass="ONOS instance Killed",
886 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700887 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700888 main.Cluster.reset()
889 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700890
Devin Lim142b5342017-07-20 15:22:39 -0700891 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700892 Testcaselib.verifyNodes( main )
893 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700894
895 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700896 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700897 """
898 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
899 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
900 Recover an ONOS instance and verify the ONOS cluster can see the proper change
901 """
Jon Hall3c910162018-03-07 14:42:16 -0800902 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700903 if sleep is None:
904 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
905 else:
906 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700907 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700908 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700909 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700910 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700911 utilities.assert_equals( expect=main.TRUE, actual=isUp,
912 onpass="ONOS service is ready",
913 onfail="ONOS service did not start properly" )
914 for i in nodes:
915 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700916 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900917 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700918 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
919 commandlineTimeout=60,
920 onosStartTimeout=100 )
921 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -0700922 utilities.assert_equals( expect=main.TRUE,
923 actual=cliResult,
924 onpass="ONOS CLI is ready",
925 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700926
Jon Halla604fd42018-05-04 14:27:27 -0700927 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -0700928 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -0700929 Testcaselib.verifyNodes( main )
930 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -0700931
Devin Lim142b5342017-07-20 15:22:39 -0700932 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
933 main.FALSE,
934 attempts=10,
935 sleep=12 )
936 if ready:
937 ready = main.TRUE
938 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700939 onpass="ONOS summary command succeded",
940 onfail="ONOS summary command failed" )
941 if not ready:
942 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700943 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700944
945 @staticmethod
946 def addHostCfg( main ):
947 """
948 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700949 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700950 """
951 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700952 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -0800953 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -0700954 hostCfg = json.load( template )
955 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
956 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700957 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -0700958 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
959 subjectClass="hosts",
960 subjectKey=urllib.quote( mac,
961 safe='' ),
962 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700963 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
964 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700965 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -0700966 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
967 subjectClass="hosts",
968 subjectKey=urllib.quote( mac,
969 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700970 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700971 main.pingChart.update( { 'vlan1': { "expect": "True",
972 "hosts": [ "olt1", "vsg1" ] } } )
973 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
974 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700975 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700976 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -0700977 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
978 subjectClass="apps",
979 subjectKey="org.onosproject.segmentrouting",
980 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700981
982 @staticmethod
983 def delHostCfg( main ):
984 """
985 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700986 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700987 """
988 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700989 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -0800990 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -0700991 hostCfg = json.load( template )
992 main.step( "Removing host configuration" )
993 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700994 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -0700995 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
996 subjectKey=urllib.quote(
997 mac,
998 safe='' ),
999 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001000 main.step( "Removing configuration" )
1001 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001002 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001003 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1004 subjectKey=urllib.quote(
1005 mac,
1006 safe='' ),
1007 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001008 main.step( "Removing vlan configuration" )
1009 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001010 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1011 subjectKey="org.onosproject.segmentrouting",
1012 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001013
1014 @staticmethod
1015 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1016 """
1017 Verifies IP address assignment from the hosts
1018 """
1019 main.step( "Verify IP address assignment from hosts" )
1020 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001021 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001022 # Find out names of disconnected hosts
1023 disconnectedHosts = []
1024 if hasattr( main, "disconnectedIpv4Hosts" ):
1025 for host in main.disconnectedIpv4Hosts:
1026 disconnectedHosts.append( host )
1027 if hasattr( main, "disconnectedIpv6Hosts" ):
1028 for host in main.disconnectedIpv6Hosts:
1029 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001030 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001031 # Exclude disconnected hosts
1032 if hostName in disconnectedHosts:
1033 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1034 continue
You Wang53dba1e2018-02-02 17:45:44 -08001035 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1036 main.FALSE,
1037 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001038 'prefix': ip,
1039 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001040 attempts=attempts,
1041 sleep=sleep )
1042 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1043 onpass="Verify network host IP succeded",
1044 onfail="Verify network host IP failed" )
1045
1046 @staticmethod
1047 def verifyOnosHostIp( main, attempts=10, sleep=10 ):
1048 """
1049 Verifies host IP address assignment from ONOS
1050 """
1051 main.step( "Verify host IP address assignment in ONOS" )
1052 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001053 # Find out IPs of disconnected hosts
1054 disconnectedIps = []
1055 if hasattr( main, "disconnectedIpv4Hosts" ):
1056 for host in main.disconnectedIpv4Hosts:
1057 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1058 if hasattr( main, "disconnectedIpv6Hosts" ):
1059 for host in main.disconnectedIpv6Hosts:
1060 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001061 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001062 # Exclude disconnected hosts
1063 if ip in disconnectedIps:
1064 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1065 continue
You Wang53dba1e2018-02-02 17:45:44 -08001066 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1067 main.FALSE,
1068 kwargs={ 'hostList': [ hostName ],
1069 'prefix': ip },
1070 attempts=attempts,
1071 sleep=sleep )
1072 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1073 onpass="Verify ONOS host IP succeded",
1074 onfail="Verify ONOS host IP failed" )
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001075
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001076 @staticmethod
1077 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1078 """
1079 Description:
1080 Updates interface configuration in ONOS, with given IP and vlan parameters
1081 Required:
1082 * connectPoint: connect point to update configuration
1083 Optional:
1084 * ips: list of IP addresses, combined with '/xx' subnet representation,
1085 corresponding to 'ips' field in the configuration
1086 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1087 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1088 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1089 """
1090 cfg = dict()
1091 cfg[ "ports" ] = dict()
1092 cfg[ "ports" ][ connectPoint ] = dict()
1093 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1094 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1095 if untagged > 0:
1096 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1097 else:
1098 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1099 if native > 0:
1100 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1101
1102 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001103
1104 @staticmethod
1105 def startScapyHosts( main ):
1106 """
1107 Create host components and start Scapy CLIs
1108 """
1109 main.step( "Start Scapy CLIs" )
1110 main.scapyHostNames = main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1111 main.scapyHosts = []
1112 for hostName in main.scapyHostNames:
1113 main.Scapy.createHostComponent( hostName )
1114 main.scapyHosts.append( getattr( main, hostName ) )
1115 for host in main.scapyHosts:
1116 host.startHostCli()
1117 host.startScapy()
1118 host.updateSelf()
1119 main.log.debug( host.name )
1120 main.log.debug( host.hostIp )
1121 main.log.debug( host.hostMac )
1122
1123 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001124 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001125 """
1126 Verify multicast traffic using scapy
1127 """
You Wangc564c6f2018-05-01 15:24:57 -07001128 from tests.dependencies.topology import Topology
1129 try:
1130 main.topo
1131 except ( NameError, AttributeError ):
1132 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001133 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001134 routeData = main.multicastConfig[ routeName ]
1135 srcs = main.mcastRoutes[ routeName ][ "src" ]
1136 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1137 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1138 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001139 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001140 for src in srcs:
1141 srcEntry = routeData[ "src" ][ src ]
1142 for dst in dsts:
1143 dstEntry = routeData[ "dst" ][ dst ]
1144 sender = getattr( main, srcEntry[ "host" ] )
1145 receiver = getattr( main, dstEntry[ "host" ] )
1146 main.Network.addRoute( str( srcEntry[ "host" ] ),
1147 str( routeData[ "group" ] ),
1148 str( srcEntry[ "interface" ] ),
1149 True if routeData[ "ipVersion" ] == 6 else False )
1150 # Build the packet
1151 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1152 if routeData[ "ipVersion" ] == 4:
1153 sender.buildIP( dst=str( routeData[ "group" ] ) )
1154 elif routeData[ "ipVersion" ] == 6:
1155 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1156 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1157 sIface = srcEntry[ "interface" ]
1158 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1159 pktFilter = srcEntry[ "filter" ]
1160 pkt = srcEntry[ "packet" ]
1161 # Send packet and check received packet
1162 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001163 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001164 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001165 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1166 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001167 if not trafficResult:
1168 result = main.FALSE
1169 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1170 dstEntry[ "host" ] ) )
1171 utilities.assert_equals( expect=main.TRUE,
1172 actual=result,
1173 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1174 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001175 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001176 Testcaselib.saveOnosDiagnostics( main )
1177 Testcaselib.cleanup( main, copyKarafLog=False )
1178 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001179
1180 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001181 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
1182 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping" ):
You Wang5da39c82018-04-26 22:55:08 -07001183 """
1184 Verify reachability from each host in srcList to each host in dstList
1185 """
1186 from tests.dependencies.topology import Topology
1187 try:
1188 main.topo
1189 except ( NameError, AttributeError ):
1190 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001191 main.step( stepMsg )
You Wang0fa76e72018-05-18 11:33:25 -07001192 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, True )
You Wang85747762018-05-11 15:51:50 -07001193 utilities.assert_equals( expect=main.TRUE,
1194 actual=pingResult,
1195 onpass="{}: Pass".format( stepMsg ),
1196 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001197 if not pingResult and skipOnFail:
1198 Testcaselib.saveOnosDiagnostics( main )
1199 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1200 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001201
1202 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001203 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001204 """
1205 Verify if the specified host is discovered by ONOS on the given locations
1206 Required:
You Wang85747762018-05-11 15:51:50 -07001207 locationDict: a dictionary that maps host names to expected locations.
1208 locations could be a string or a list.
1209 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001210 Returns:
1211 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1212 """
You Wang85747762018-05-11 15:51:50 -07001213 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1214 result = main.TRUE
1215 for hostName, locations in locationDict.items():
1216 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1217 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1218 if not hostIp:
1219 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1220 if not hostIp:
1221 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1222 result = main.FALSE
1223 continue
1224 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1225 main.FALSE,
1226 args=( hostIp, locations ),
1227 attempts=retry + 1,
1228 sleep=10 )
1229 if not locationResult:
1230 result = main.FALSE
1231 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001232 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001233 onpass="Location verification passed",
1234 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001235
1236 @staticmethod
1237 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False ):
1238 """
1239 Move specified host from srcSw to dstSw.
1240 If srcSw and dstSw are same, the host will be moved from current port to
1241 next available port.
1242 Required:
1243 hostName: name of the host. e.g., "h1"
1244 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1245 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1246 gw: ip address of the gateway of the new location
1247 Optional:
1248 macAddr: if specified, change MAC address of the host to the specified MAC address.
1249 prefixLen: prefix length
1250 cfg: port configuration as JSON string
1251 ipv6: Use True to move IPv6 host
1252 """
1253
1254 if not hasattr( main, 'Mininet1' ):
1255 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1256 return
1257
1258 if ipv6:
1259 main.Mininet1.moveHostv6( hostName, srcSw, dstSw, macAddr )
1260 else:
1261 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen )
1262
1263 main.Mininet1.changeDefaultGateway( hostName, gw )
1264 if cfg:
1265 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1266 subjectClass="ports" )
1267
1268 main.Mininet1.discoverHosts( [ hostName, ] )
1269
1270 # Update expectedHost when MAC address is changed.
1271 if macAddr is not None:
1272 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1273 if ipAddr is not None:
1274 for hostName, ip in main.expectedHosts[ "onos" ].items():
1275 if ip == ipAddr:
1276 vlan = hostName.split( "/" )[ -1 ]
1277 del main.expectedHosts[ "onos" ][ hostName ]
1278 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr, vlan ) ] = ip
1279 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001280
1281 @staticmethod
1282 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
1283 macAddr=None, prefixLen=24, cfg='', ipv6=False ):
1284 """
1285 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1286 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1287 to next available port.
1288 Required:
1289 hostName: name of the host. e.g., "h1"
1290 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1291 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1292 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1293 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1294 gw: ip address of the gateway of the new location
1295 Optional:
1296 macAddr: if specified, change MAC address of the host to the specified MAC address.
1297 prefixLen: prefix length
1298 cfg: port configurations as JSON string
1299 ipv6: Use True to move IPv6 host (IPv6 is not supported now.)
1300 """
1301 # TODO: support IPv6 hosts and vlan-tagged hosts.
1302 if not hasattr( main, 'Mininet1' ):
1303 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1304 return
1305
1306 if ipv6:
1307 main.log.warn( "Moving IPv6 host is not implemented yet." )
1308 return
1309
1310 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1311 macAddr=macAddr, prefixLen=prefixLen )
1312
1313 main.Mininet1.changeDefaultGateway( hostName, gw )
1314
1315 if cfg:
1316 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1317 subjectClass="ports" )
1318
1319 main.Mininet1.discoverHosts( [ hostName, ] )
1320
1321 # Update expectedHost when MAC address is changed.
1322 if macAddr is not None:
1323 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1324 if ipAddr is not None:
1325 for hostName, ip in main.expectedHosts[ "onos" ].items():
1326 if ip == ipAddr:
1327 vlan = hostName.split( "/" )[ -1 ]
1328 del main.expectedHosts[ "onos" ][ hostName ]
1329 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr, vlan ) ] = ip