blob: 22988d8c358d10feb2ebc0ab30c89d027a95d13d [file] [log] [blame]
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2016 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07003
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070011 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20"""
Jon Hall1efcb3f2016-08-23 13:42:15 -070021import os
Jon Hall1efcb3f2016-08-23 13:42:15 -070022import time
23import json
24import urllib
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -070025import re
Jon Hall1efcb3f2016-08-23 13:42:15 -070026from core import utilities
27
28
29class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070030
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070031 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070032
Jon Hall1efcb3f2016-08-23 13:42:15 -070033 @staticmethod
34 def initTest( main ):
35 """
36 - Construct tests variables
37 - GIT ( optional )
38 - Checkout ONOS master branch
39 - Pull latest ONOS code
40 - Building ONOS ( optional )
41 - Install ONOS package
42 - Build ONOS package
43 """
Devin Lim58046fa2017-07-05 16:55:00 -070044 try:
45 from tests.dependencies.ONOSSetup import ONOSSetup
46 main.testSetUp = ONOSSetup()
47 except ImportError:
48 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070049 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080050 from tests.dependencies.Network import Network
51 main.Network = Network()
Devin Lim0c972b72018-02-08 14:53:59 -080052 main.testSetUp.envSetupDescription( False )
Devin Lim58046fa2017-07-05 16:55:00 -070053 stepResult = main.FALSE
54 try:
Devin Lim58046fa2017-07-05 16:55:00 -070055 # Test variables
56 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
57 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070058 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080059 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
60 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
61 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080062 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
63 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
64 else:
65 main.useBmv2 = False
Devin Lim57221b02018-02-14 15:45:36 -080066 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070067 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080068 main.forJson = "json/"
69 main.forChart = "chart/"
70 main.forConfig = "conf/"
71 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080072 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080073 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070074 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070075 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080076 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
77 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080078 main.bmv2 = "bmv2.py"
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070079 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070080 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
You Wang5bf49592020-07-08 18:47:46 -070081 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ]
82 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070083
Devin Lim0c972b72018-02-08 14:53:59 -080084 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070085 except Exception as e:
86 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070087
Devin Lim58046fa2017-07-05 16:55:00 -070088 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070089
Jon Hall1efcb3f2016-08-23 13:42:15 -070090 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080091 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
92 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -070093 """
94 - Set up cell
95 - Create cell file
96 - Set cell file
97 - Verify cell file
98 - Kill ONOS process
99 - Uninstall ONOS cluster
100 - Verify ONOS start up
101 - Install ONOS cluster
102 - Connect to cli
103 """
104 # main.scale[ 0 ] determines the current number of ONOS controller
You Wangd87b2312018-01-30 12:47:17 -0800105 if not main.apps:
Jon Hall1efcb3f2016-08-23 13:42:15 -0700106 main.log.error( "App list is empty" )
Jon Hall3c910162018-03-07 14:42:16 -0800107 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
108 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700109 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800110 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800111 skipPack=skipPackage,
112 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800113 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700114 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700115 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800116 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700117 attempts=10 )
118 if ready:
119 ready = main.TRUE
120 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700121 onpass="ONOS summary command succeded",
122 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700123 if not ready:
124 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700125 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700126
You Wang5bf49592020-07-08 18:47:46 -0700127 # Install segmentrouting and t3 app
128 appInstallResult = main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
129 if main.t3Oar:
130 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
131 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
132 onpass="SR app installation succeded",
133 onfail="SR app installation failed" )
134 if not appInstallResult:
135 main.cleanAndExit()
136
Devin Lim142b5342017-07-20 15:22:39 -0700137 for ctrl in main.Cluster.active():
138 ctrl.CLI.logSet( "DEBUG", "org.onosproject.segmentrouting" )
You Wangf5f104f2018-03-30 17:09:10 -0700139 ctrl.CLI.logSet( "DEBUG", "org.onosproject.driver" )
Devin Lim142b5342017-07-20 15:22:39 -0700140 ctrl.CLI.logSet( "DEBUG", "org.onosproject.net.flowobjective.impl" )
You Wangf5f104f2018-03-30 17:09:10 -0700141 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.impl" )
142 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.store" )
143 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routing.fpm" )
Jon Hall9677ed32018-04-24 11:16:23 -0700144 ctrl.CLI.logSet( "TRACE", "org.onosproject.events" )
145 ctrl.CLI.logSet( "DEBUG", "org.onosproject.mcast" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700146
147 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800148 def loadCount( main ):
149 with open("%s/count/%s.count" % (main.configPath, main.cfgName)) as count:
You Wang5df1c6d2018-04-06 18:02:02 -0700150 main.count = json.load(count)
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800151
152 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800153 def loadJson( main ):
154 with open( "%s%s.json" % ( main.configPath + main.forJson,
155 main.cfgName ) ) as cfg:
156 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
157
158 @staticmethod
159 def loadChart( main ):
160 try:
161 with open( "%s%s.chart" % ( main.configPath + main.forChart,
162 main.cfgName ) ) as chart:
163 main.pingChart = json.load(chart)
164 except IOError:
165 main.log.warn( "No chart file found." )
166
167 @staticmethod
168 def loadHost( main ):
169 with open( "%s%s.host" % ( main.configPath + main.forHost,
170 main.cfgName ) ) as host:
171 main.expectedHosts = json.load( host )
172
173 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800174 def loadSwitchFailureChart( main ):
175 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
176 main.cfgName ) ) as sfc:
177 main.switchFailureChart = json.load( sfc )
178
179 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800180 def loadLinkFailureChart( main ):
181 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700182 main.cfgName ) ) as lfc:
183 main.linkFailureChart = json.load( lfc )
184
185 @staticmethod
186 def loadMulticastConfig( main ):
187 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
188 main.cfgName ) ) as cfg:
189 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800190
191 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700192 def startMininet( main, topology, args="" ):
You Wangd87b2312018-01-30 12:47:17 -0800193 copyResult = main.ONOSbench.scp( main.Mininet1,
194 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700195 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800196 direction="to" )
197 if main.topologyLib:
198 for lib in main.topologyLib.split(","):
199 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
200 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700201 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800202 direction="to" )
203 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700204 import re
205 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
206 index = 0
You Wangd87b2312018-01-30 12:47:17 -0800207 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700208 # Update zebra configurations with correct ONOS instance IP
209 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
210 ip = controllerIPs[ index ]
211 index = ( index + 1 ) % len( controllerIPs )
212 with open( main.configPath + main.forConfig + conf ) as f:
213 s = f.read()
214 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
215 with open( main.configPath + main.forConfig + conf, "w" ) as f:
216 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800217 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800218 main.configPath + main.forConfig + conf,
You Wangd87b2312018-01-30 12:47:17 -0800219 "~/",
220 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800221 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700222 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800223 main.Mininet1.home + "custom",
224 direction="to" )
You Wangd87b2312018-01-30 12:47:17 -0800225 stepResult = copyResult
226 utilities.assert_equals( expect=main.TRUE,
227 actual=stepResult,
228 onpass="Successfully copied topo files",
229 onfail="Failed to copy topo files" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700230 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700231 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700232 main.topology = topology
233 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700234 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700235 stepResult = topoResult
236 utilities.assert_equals( expect=main.TRUE,
237 actual=stepResult,
238 onpass="Successfully loaded topology",
239 onfail="Failed to load topology" )
240 # Exit if topology did not load properly
241 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700242 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700243
244 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700245 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800246 main.step( "Connecting to physical netowrk" )
247 topoResult = main.NetworkBench.connectToNet()
248 stepResult = topoResult
249 utilities.assert_equals( expect=main.TRUE,
250 actual=stepResult,
251 onpass="Successfully loaded topology",
252 onfail="Failed to load topology" )
253 # Exit if topology did not load properly
254 if not topoResult:
255 main.cleanAndExit()
256
257 main.step( "Assign switches to controllers." )
258 assignResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700259 switches = main.NetworkBench.getSwitches()
260 pool = []
261 for name in switches.keys():
262 thread = main.Thread( target=main.NetworkBench.assignSwController,
263 name="assignSwitchToController",
264 args=[ name, main.Cluster.getIps(), '6653' ] )
265 pool.append( thread )
266 thread.start()
267 for thread in pool:
268 thread.join( 300 )
269 if not thread.result:
270 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800271 utilities.assert_equals( expect=main.TRUE,
272 actual=stepResult,
273 onpass="Successfully assign switches to controllers",
274 onfail="Failed to assign switches to controllers" )
275
You Wang4cc61912018-08-28 10:10:58 -0700276 # Check devices
277 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
278 time.sleep( float( main.params[ "timers" ][ "connectToNetSleep" ] ) )
279 # Connecting to hosts that only have data plane connectivity
280 main.step( "Connecting inband hosts" )
281 stepResult = main.Network.connectInbandHosts()
282 utilities.assert_equals( expect=main.TRUE,
283 actual=stepResult,
284 onpass="Successfully connected inband hosts",
285 onfail="Failed to connect inband hosts" )
286
You Wang84f981d2018-01-12 16:11:50 -0800287 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700288 def saveOnosDiagnostics( main ):
289 """
290 Get onos-diags.tar.gz and save it to the log directory.
291 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
292 """
293 main.log.info( "Collecting onos-diags..." )
294 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
295 main.logdir,
296 "-CASE%d" % main.CurrentTestCaseNumber )
297
298 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700299 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700300 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700301
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700302 main.failures = int( main.params[ 'failures' ] )
303 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700304
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700305 if main.cfgName == '2x2':
306 spine = {}
307 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
308 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
309 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700310
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700311 spine = {}
312 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
313 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
314 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700315
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700316 elif main.cfgName == '4x4':
317 spine = {}
318 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
319 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
320 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700321
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700322 spine = {}
323 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
324 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
325 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700326
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700327 spine = {}
328 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
329 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
330 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700331
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700332 spine = {}
333 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
334 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
335 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700336
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700337 else:
Piera2a7e1b2016-10-04 11:51:43 -0700338 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700339 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800340
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800341 @staticmethod
342 def addStaticOnosRoute( main, subnet, intf):
343 """
344 Adds an ONOS static route with the use route-add command.
345 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800346 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
347
Piera2a7e1b2016-10-04 11:51:43 -0700348 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700349 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700350 """
351 Check number of groups for each subnet on device deviceId and matches
352 it with an expected value. subnetDict is a dictionarty containing values
353 of the type "10.0.1.0/24" : 5.
354 """
You Wangc02f3be2018-05-18 12:14:23 -0700355 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
356 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
357 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700358
You Wangc02f3be2018-05-18 12:14:23 -0700359 result = main.TRUE
360 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700361 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700362 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700363 # this will match the group id that this flow entry points to, for example :
364 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700365 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700366 count = 0
367 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700368 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700369 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700370 if count - 1 != numberInSelect:
371 result = main.FALSE
372 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 ) )
373 utilities.assert_equals( expect=main.TRUE, actual=result,
374 onpass="All bucket numbers are as expected",
375 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700376
377 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900378 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700379 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800380 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900381 if tag == "":
382 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700383 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700384 main.FALSE,
385 kwargs={ 'min': minFlowCount },
386 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800387 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800388 if count == main.FALSE:
389 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700390 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700391 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800392 actual=( count > minFlowCount ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700393 onpass="Flow count looks correct: " + str( count ),
394 onfail="Flow count looks wrong: " + str( count ) )
395
396 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700397 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700398 main.FALSE,
399 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800400 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800401 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700402 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700403 expect=main.TRUE,
404 actual=flowCheck,
405 onpass="Flow status is correct!",
406 onfail="Flow status is wrong!" )
407 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700408 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700409 "flows",
410 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900411 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700412 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700413 "groups",
414 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900415 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700416
417 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700418 def checkDevices( main, switches, tag="", sleep=10 ):
419 main.step(
420 "Check whether the switches count is equal to %s" % switches )
421 if tag == "":
422 tag = 'CASE%d' % main.CurrentTestCaseNumber
423 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
424 main.FALSE,
425 kwargs={ 'numoswitch': switches},
426 attempts=10,
427 sleep=sleep )
428 utilities.assert_equals( expect=main.TRUE, actual=result,
429 onpass="Device up successful",
430 onfail="Failed to boot up devices?" )
431
432 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800433 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
434 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800435 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
436 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
437 main.FALSE,
438 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800439 attempts=5,
440 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800441 if count == main.FALSE:
442 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800443 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800444 expect=True,
445 actual=( count > minFlowCount ),
446 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800447 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800448
449 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700450 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800451 main.step(
452 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
453 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
454 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700455 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800456 attempts=5,
457 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800458 if count == main.FALSE:
459 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800460 utilities.assertEquals(
461 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800462 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700463 onpass="Flow count looks correct: " + str( count ) ,
464 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800465
466 @staticmethod
467 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
468 main.step(
469 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
470 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
471 main.FALSE,
472 args=( dpid, groupCount, False, 1),
473 attempts=5,
474 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800475 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800476 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800477 utilities.assertEquals(
478 expect=True,
479 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700480 onpass="Group count looks correct: " + str( count ) ,
481 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800482
483 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700484 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800485
486 for dpid, values in main.count.items():
487 flowCount = values["flows"]
488 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700489 main.log.report( "Check flow count for dpid " + str( dpid ) +
490 ", should be " + str( flowCount ) )
491 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800492
Jon Hall9677ed32018-04-24 11:16:23 -0700493 main.log.report( "Check group count for dpid " + str( dpid ) +
494 ", should be " + str( groupCount ) )
495 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800496
497 return
498
499 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700500 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
501 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800502 '''
You Wangba231e72018-03-01 13:18:21 -0800503 Verify connectivity between hosts according to the ping chart
504 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800505 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800506 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800507 '''
You Wangba231e72018-03-01 13:18:21 -0800508 main.log.report( "Check host connectivity" )
509 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800510 if tag == "":
511 tag = 'CASE%d' % main.CurrentTestCaseNumber
512 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800513 main.log.debug( "Entry in ping chart: %s" % entry )
514 expect = entry[ 'expect' ]
515 if expect == "Unidirectional":
516 # Verify ping from each src host to each dst host
517 src = entry[ 'src' ]
518 dst = entry[ 'dst' ]
519 expect = main.TRUE
520 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
521 if basedOnIp:
522 if ("v4" in src[0]):
523 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
524 utilities.assert_equals( expect=expect, actual=pa,
525 onpass="IPv4 connectivity successfully tested",
526 onfail="IPv4 connectivity failed" )
527 if ("v6" in src[0]):
528 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
529 utilities.assert_equals( expect=expect, actual=pa,
530 onpass="IPv6 connectivity successfully tested",
531 onfail="IPv6 connectivity failed" )
532 else:
533 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
534 utilities.assert_equals( expect=expect, actual=pa,
535 onpass="IP connectivity successfully tested",
536 onfail="IP connectivity failed" )
537 else:
538 # Verify ping between each host pair
539 hosts = entry[ 'hosts' ]
540 try:
541 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
542 except:
543 expect = main.FALSE
544 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
545 if basedOnIp:
546 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800547 pa = utilities.retry( main.Network.pingallHosts,
548 main.FALSE if expect else main.TRUE,
549 args=(hosts,),
550 attempts=retryAttempts,
551 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800552 utilities.assert_equals( expect=expect, actual=pa,
553 onpass="IPv4 connectivity successfully tested",
554 onfail="IPv4 connectivity failed" )
555 if ("v6" in hosts[0]):
556 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
557 utilities.assert_equals( expect=expect, actual=pa,
558 onpass="IPv6 connectivity successfully tested",
559 onfail="IPv6 connectivity failed" )
560 else:
You Wangf19d9f42018-02-23 16:34:19 -0800561 pa = main.Network.pingallHosts( hosts )
562 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800563 onpass="IP connectivity successfully tested",
564 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700565 if skipOnFail and pa != expect:
566 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700567 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700568 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800569
570 if dumpflows:
571 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
572 "flows",
573 main.logdir,
574 tag + "_FlowsOn" )
575 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
576 "groups",
577 main.logdir,
578 tag + "_GroupsOn" )
579
580 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700581 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700582 """
583 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
584 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
585 Kill a link and verify ONOS can see the proper link change
586 """
Jon Halla604fd42018-05-04 14:27:27 -0700587 if sleep is None:
588 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
589 else:
590 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700591 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700592 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
593 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
594 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700595 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700596 "Waiting %s seconds for link down to be discovered" % sleep )
597 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700598 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700599 main.FALSE,
600 kwargs={ 'numoswitch': switches,
601 'numolink': links },
602 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700603 sleep=sleep )
604 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700605 utilities.assert_equals( expect=main.TRUE, actual=result,
606 onpass="Link down successful",
607 onfail="Failed to turn off link?" )
608
609 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700610 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800611 """
612 links = list of links (src, dst) to bring down.
613 """
614
615 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700616 if sleep is None:
617 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
618 else:
619 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800620
621 for end1, end2 in links:
622 main.Network.link( END1=end1, END2=end2, OPTION="down")
623 main.Network.link( END1=end2, END2=end1, OPTION="down")
624
Jon Halla604fd42018-05-04 14:27:27 -0700625 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800626 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700627 "Waiting %s seconds for links down to be discovered" % sleep )
628 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800629
630 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
631 main.FALSE,
632 kwargs={ 'numoswitch': switches,
633 'numolink': linksAfter },
634 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700635 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800636
You Wang2854bce2018-03-30 10:15:32 -0700637 utilities.assert_equals( expect=main.TRUE, actual=topology,
638 onpass="Link batch down successful",
639 onfail="Link batch down failed" )
640
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800641 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700642 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800643 """
644 links = list of link (src, dst) to bring up again.
645 """
646
647 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700648 if sleep is None:
649 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
650 else:
651 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800652
653 for end1, end2 in links:
654 main.Network.link( END1=end1, END2=end2, OPTION="up")
655 main.Network.link( END1=end2, END2=end1, OPTION="up")
656
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800657 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700658 "Waiting %s seconds for links up to be discovered" % sleep )
659 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800660
661 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
662 main.FALSE,
663 kwargs={ 'numoswitch': switches,
664 'numolink': linksAfter },
665 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700666 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800667
You Wang2854bce2018-03-30 10:15:32 -0700668 utilities.assert_equals( expect=main.TRUE, actual=topology,
669 onpass="Link batch up successful",
670 onfail="Link batch up failed" )
671
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800672 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700673 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
674 """
675 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
676 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
677 switches, links: number of expected switches and links after link change, ex.: '4', '6'
678 """
679 if sleep is None:
680 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
681 else:
682 sleep = float( sleep )
683 main.step( "Disable a batch of ports" )
684 for dpid, port in ports:
685 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
686 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
687 time.sleep( sleep )
688 if switches and links:
689 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
690 numolink=links )
691 utilities.assert_equals( expect=main.TRUE, actual=result,
692 onpass="Port down successful",
693 onfail="Port down failed" )
694
695 @staticmethod
696 def enablePortBatch( main, ports, switches, links, sleep=None ):
697 """
698 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
699 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
700 switches, links: number of expected switches and links after link change, ex.: '4', '6'
701 """
702 if sleep is None:
703 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
704 else:
705 sleep = float( sleep )
706 main.step( "Enable a batch of ports" )
707 for dpid, port in ports:
708 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
709 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
710 time.sleep( sleep )
711 if switches and links:
712 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
713 numolink=links )
714 utilities.assert_equals( expect=main.TRUE, actual=result,
715 onpass="Port up successful",
716 onfail="Port up failed" )
717
718 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700719 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700720 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700721 """
722 Params:
723 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700724 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700725 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
726 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
727 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
728 Kill a link and verify ONOS can see the proper link change
729 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700730 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700731 if sleep is None:
732 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
733 else:
734 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700735 result = False
736 count = 0
737 while True:
738 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700739 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800740 main.Network.link( END1=end1, END2=end2, OPTION="up" )
741 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700742 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700743 "Waiting %s seconds for link up to be discovered" % sleep )
744 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700745
You Wangc02d8352018-04-17 16:42:10 -0700746 if portUp:
747 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
748 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700749 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700750
Jon Halla604fd42018-05-04 14:27:27 -0700751 result = ctrl.CLI.checkStatus( numoswitch=switches,
752 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700753 if count > 5 or result:
754 break
755 utilities.assert_equals( expect=main.TRUE, actual=result,
756 onpass="Link up successful",
757 onfail="Failed to bring link up" )
758
759 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700760 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700761 """
762 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
763 Completely kill a switch and verify ONOS can see the proper change
764 """
Jon Halla604fd42018-05-04 14:27:27 -0700765 if sleep is None:
766 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
767 else:
768 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700769 switch = switch if isinstance( switch, list ) else [ switch ]
770 main.step( "Kill " + str( switch ) )
771 for s in switch:
772 main.log.info( "Stopping " + s )
773 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700774 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700775
776 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700777 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700778 sleep ) )
779 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700780 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700781 main.FALSE,
782 kwargs={ 'numoswitch': switches,
783 'numolink': links },
784 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700785 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700786 utilities.assert_equals( expect=main.TRUE, actual=topology,
787 onpass="Kill switch successful",
788 onfail="Failed to kill switch?" )
789
790 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700791 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700792 """
793 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
794 Recover a switch and verify ONOS can see the proper change
795 """
Jon Halla604fd42018-05-04 14:27:27 -0700796 if sleep is None:
797 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
798 else:
799 sleep = float( sleep )
800 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700801 switch = switch if isinstance( switch, list ) else [ switch ]
802 main.step( "Recovering " + str( switch ) )
803 for s in switch:
804 main.log.info( "Starting " + s )
805 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700806 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700807 sleep ) )
808 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700809 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700810 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700811 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700812 sleep ) )
813 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700814
Devin Lim142b5342017-07-20 15:22:39 -0700815 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700816 main.FALSE,
817 kwargs={ 'numoswitch': switches,
818 'numolink': links },
819 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700820 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700821 utilities.assert_equals( expect=main.TRUE, actual=topology,
822 onpass="Switch recovery successful",
823 onfail="Failed to recover switch?" )
824
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700825 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700826 def killRouter( main, router, sleep=None ):
827 """
828 Kill bgpd process on a quagga router
829 router: name of the router to be killed. E.g. "bgp1"
830 """
831 sleep = float( sleep )
832 main.step( "Kill " + str( router ) )
833 if hasattr( main, 'Mininet1' ):
834 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
835 main.Mininet1.handle.expect( "mininet>" )
836 else:
837 # TODO: support killing router in physical network
838 pass
839 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
840 time.sleep( sleep )
841
842 @staticmethod
843 def recoverRouter( main, router, sleep=None ):
844 """
845 Restart bgpd process on a quagga router
846 router: name of the router to be recovered. E.g. "bgp1"
847 """
848 sleep = float( sleep )
849 main.step( "Recovering " + str( router ) )
850 if hasattr( main, 'Mininet1' ):
851 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
852 main.Mininet1.handle.expect( "mininet>" )
853 else:
854 # TODO: support recovering router in physical network
855 pass
856 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
857 time.sleep( sleep )
858
859 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700860 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700861 """
862 Stop Onos-cluster.
863 Stops Mininet
864 Copies ONOS log
865 """
You Wang4cc61912018-08-28 10:10:58 -0700866 from tests.dependencies.utils import Utils
867 main.utils = Utils()
868 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700869 if hasattr( main, "scapyHosts" ):
870 scapyResult = main.TRUE
871 for host in main.scapyHosts:
872 scapyResult = host.stopScapy() and scapyResult
873 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
874 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700875 if hasattr( main, 'Mininet1' ):
876 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
877 else:
878 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700879 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
880 main.scapyHosts = []
881
You Wang5da39c82018-04-26 22:55:08 -0700882 if removeHostComponent:
883 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
884 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700885 if hasattr( main, 'Mininet1' ):
886 pass
887 else:
888 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700889 main.Network.removeHostComponent( host )
890
You Wang5df1c6d2018-04-06 18:02:02 -0700891 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700892 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700893 else:
894 main.Network.disconnectInbandHosts()
895 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700896
You Wang5df1c6d2018-04-06 18:02:02 -0700897 if copyKarafLog:
898 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700899
Devin Lim142b5342017-07-20 15:22:39 -0700900 for ctrl in main.Cluster.active():
901 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700902
903 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700904 def verifyNodes( main ):
905 """
906 Verifies Each active node in the cluster has an accurate view of other node's and their status
907
908 Params:
909 nodes, integer array with position of the ONOS nodes in the CLIs array
910 """
911 nodeResults = utilities.retry( main.Cluster.nodesCheck,
912 False,
913 attempts=10,
914 sleep=10 )
915 utilities.assert_equals( expect=True, actual=nodeResults,
916 onpass="Nodes check successful",
917 onfail="Nodes check NOT successful" )
918
919 if not nodeResults:
920 for ctrl in main.Cluster.runningNodes:
921 main.log.debug( "{} components not ACTIVE: \n{}".format(
922 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -0800923 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -0800924 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -0700925 main.cleanAndExit()
926
927 @staticmethod
928 def verifyTopology( main, switches, links, expNodes ):
929 """
930 Verifies that the ONOS cluster has an acuurate view of the topology
931
932 Params:
933 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
934 """
935 main.step( "Check number of topology elements" )
936 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
937 main.FALSE,
938 kwargs={ 'numoswitch': switches,
939 'numolink': links,
940 'numoctrl': expNodes },
941 attempts=10,
942 sleep=12 )
943 utilities.assert_equals( expect=main.TRUE, actual=topology,
944 onpass="Number of topology elements are correct",
945 onfail="Unexpected number of links, switches, and/or controllers" )
946
947 @staticmethod
948 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700949 """
950 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
951 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
952 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
953 """
Jon Halla604fd42018-05-04 14:27:27 -0700954 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800955 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700956 if sleep is None:
957 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
958 else:
959 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700960
Jon Hall1efcb3f2016-08-23 13:42:15 -0700961 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700962 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700963 utilities.assert_equals( expect=main.TRUE, actual=killResult,
964 onpass="ONOS instance Killed",
965 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700966 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700967 main.Cluster.reset()
968 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700969
Devin Lim142b5342017-07-20 15:22:39 -0700970 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700971 Testcaselib.verifyNodes( main )
972 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700973
974 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700975 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700976 """
977 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
978 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
979 Recover an ONOS instance and verify the ONOS cluster can see the proper change
980 """
Jon Hall3c910162018-03-07 14:42:16 -0800981 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700982 if sleep is None:
983 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
984 else:
985 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700986 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700987 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700988 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700989 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700990 utilities.assert_equals( expect=main.TRUE, actual=isUp,
991 onpass="ONOS service is ready",
992 onfail="ONOS service did not start properly" )
993 for i in nodes:
994 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -0700995 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900996 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -0700997 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
998 commandlineTimeout=60,
999 onosStartTimeout=100 )
1000 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001001 utilities.assert_equals( expect=main.TRUE,
1002 actual=cliResult,
1003 onpass="ONOS CLI is ready",
1004 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001005
Jon Halla604fd42018-05-04 14:27:27 -07001006 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001007 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001008 Testcaselib.verifyNodes( main )
1009 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001010
Devin Lim142b5342017-07-20 15:22:39 -07001011 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001012 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001013 attempts=10,
1014 sleep=12 )
1015 if ready:
1016 ready = main.TRUE
1017 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001018 onpass="ONOS summary command succeded",
1019 onfail="ONOS summary command failed" )
1020 if not ready:
1021 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001022 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001023
1024 @staticmethod
1025 def addHostCfg( main ):
1026 """
1027 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001028 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001029 """
1030 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001031 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001032 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001033 hostCfg = json.load( template )
1034 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1035 main.step( "Pushing new configuration" )
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.setNetCfg( cfg[ 'basic' ],
1038 subjectClass="hosts",
1039 subjectKey=urllib.quote( mac,
1040 safe='' ),
1041 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001042 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1043 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001044 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001045 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1046 subjectClass="hosts",
1047 subjectKey=urllib.quote( mac,
1048 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001049 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001050 main.pingChart.update( { 'vlan1': { "expect": "True",
1051 "hosts": [ "olt1", "vsg1" ] } } )
1052 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1053 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001054 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001055 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001056 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1057 subjectClass="apps",
1058 subjectKey="org.onosproject.segmentrouting",
1059 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001060
1061 @staticmethod
1062 def delHostCfg( main ):
1063 """
1064 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001065 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001066 """
1067 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001068 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001069 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001070 hostCfg = json.load( template )
1071 main.step( "Removing host configuration" )
1072 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001073 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001074 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1075 subjectKey=urllib.quote(
1076 mac,
1077 safe='' ),
1078 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001079 main.step( "Removing configuration" )
1080 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001081 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001082 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1083 subjectKey=urllib.quote(
1084 mac,
1085 safe='' ),
1086 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001087 main.step( "Removing vlan configuration" )
1088 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001089 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1090 subjectKey="org.onosproject.segmentrouting",
1091 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001092
1093 @staticmethod
1094 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1095 """
1096 Verifies IP address assignment from the hosts
1097 """
1098 main.step( "Verify IP address assignment from hosts" )
1099 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001100 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001101 # Find out names of disconnected hosts
1102 disconnectedHosts = []
1103 if hasattr( main, "disconnectedIpv4Hosts" ):
1104 for host in main.disconnectedIpv4Hosts:
1105 disconnectedHosts.append( host )
1106 if hasattr( main, "disconnectedIpv6Hosts" ):
1107 for host in main.disconnectedIpv6Hosts:
1108 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001109 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001110 # Exclude disconnected hosts
1111 if hostName in disconnectedHosts:
1112 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1113 continue
You Wang53dba1e2018-02-02 17:45:44 -08001114 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1115 main.FALSE,
1116 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001117 'prefix': ip,
1118 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001119 attempts=attempts,
1120 sleep=sleep )
1121 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1122 onpass="Verify network host IP succeded",
1123 onfail="Verify network host IP failed" )
1124
1125 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001126 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001127 """
1128 Verifies host IP address assignment from ONOS
1129 """
1130 main.step( "Verify host IP address assignment in ONOS" )
1131 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001132 # Find out IPs of disconnected hosts
1133 disconnectedIps = []
1134 if hasattr( main, "disconnectedIpv4Hosts" ):
1135 for host in main.disconnectedIpv4Hosts:
1136 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1137 if hasattr( main, "disconnectedIpv6Hosts" ):
1138 for host in main.disconnectedIpv6Hosts:
1139 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001140 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001141 # Exclude disconnected hosts
1142 if ip in disconnectedIps:
1143 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1144 continue
You Wang53dba1e2018-02-02 17:45:44 -08001145 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1146 main.FALSE,
1147 kwargs={ 'hostList': [ hostName ],
1148 'prefix': ip },
1149 attempts=attempts,
1150 sleep=sleep )
1151 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1152 onpass="Verify ONOS host IP succeded",
1153 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001154 if not ipResult and skipOnFail:
1155 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001156 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001157 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001158
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001159 @staticmethod
1160 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1161 """
1162 Description:
1163 Updates interface configuration in ONOS, with given IP and vlan parameters
1164 Required:
1165 * connectPoint: connect point to update configuration
1166 Optional:
1167 * ips: list of IP addresses, combined with '/xx' subnet representation,
1168 corresponding to 'ips' field in the configuration
1169 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1170 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1171 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1172 """
1173 cfg = dict()
1174 cfg[ "ports" ] = dict()
1175 cfg[ "ports" ][ connectPoint ] = dict()
1176 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1177 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1178 if untagged > 0:
1179 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1180 else:
1181 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1182 if native > 0:
1183 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1184
1185 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001186
1187 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001188 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001189 """
1190 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001191 scapyNames: list of names that will be used as component names for scapy hosts
1192 mininetNames: used when scapy host names are different from the host names
1193 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1194 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001195 """
1196 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001197 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1198 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001199 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001200 if hasattr( main, 'Mininet1' ):
1201 main.Scapy.createHostComponent( scapyName )
1202 scapyHandle = getattr( main, scapyName )
1203 if mininetNames:
1204 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1205 else:
1206 mininetName = None
1207 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001208 else:
You Wang0fc21702018-11-02 17:49:18 -07001209 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001210 scapyHandle = getattr( main, scapyName )
1211 scapyHandle.connectInband()
1212 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001213 scapyHandle.startScapy()
1214 scapyHandle.updateSelf()
1215 main.log.debug( scapyHandle.name )
1216 main.log.debug( scapyHandle.hostIp )
1217 main.log.debug( scapyHandle.hostMac )
1218
1219 @staticmethod
1220 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1221 """
1222 Verify unicast traffic by pinging from source hosts to the destination IP
1223 and capturing the packets at the destination host using Scapy.
1224 srcHosts: List of host names to send the ping packets
1225 dstIp: destination IP of the ping packets
1226 dstHost: host that runs Scapy to capture the packets
1227 dstIntf: name of the interface on the destination host
1228 expect: use True if the ping is expected to be captured at destination;
1229 Otherwise False
1230 skipOnFail: skip the rest of this test case if result is not expected
1231 maxRetry: number of retries allowed
1232 """
1233 from tests.dependencies.topology import Topology
1234 try:
1235 main.topo
1236 except ( NameError, AttributeError ):
1237 main.topo = Topology()
1238 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1239 result = main.TRUE
1240 for srcHost in srcHosts:
1241 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1242 expect, maxRetry, True )
1243 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001244 result = main.FALSE
1245 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1246 utilities.assert_equals( expect=main.TRUE,
1247 actual=result,
1248 onpass="Verify traffic to {}: Pass".format( dstIp ),
1249 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1250 if skipOnFail and result != main.TRUE:
1251 Testcaselib.saveOnosDiagnostics( main )
1252 Testcaselib.cleanup( main, copyKarafLog=False )
1253 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001254
1255 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001256 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001257 """
1258 Verify multicast traffic using scapy
1259 """
You Wangc564c6f2018-05-01 15:24:57 -07001260 from tests.dependencies.topology import Topology
1261 try:
1262 main.topo
1263 except ( NameError, AttributeError ):
1264 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001265 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001266 routeData = main.multicastConfig[ routeName ]
1267 srcs = main.mcastRoutes[ routeName ][ "src" ]
1268 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1269 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1270 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001271 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001272 for src in srcs:
1273 srcEntry = routeData[ "src" ][ src ]
1274 for dst in dsts:
1275 dstEntry = routeData[ "dst" ][ dst ]
1276 sender = getattr( main, srcEntry[ "host" ] )
1277 receiver = getattr( main, dstEntry[ "host" ] )
1278 main.Network.addRoute( str( srcEntry[ "host" ] ),
1279 str( routeData[ "group" ] ),
1280 str( srcEntry[ "interface" ] ),
1281 True if routeData[ "ipVersion" ] == 6 else False )
1282 # Build the packet
1283 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1284 if routeData[ "ipVersion" ] == 4:
1285 sender.buildIP( dst=str( routeData[ "group" ] ) )
1286 elif routeData[ "ipVersion" ] == 6:
1287 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1288 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1289 sIface = srcEntry[ "interface" ]
1290 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1291 pktFilter = srcEntry[ "filter" ]
1292 pkt = srcEntry[ "packet" ]
1293 # Send packet and check received packet
1294 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001295 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001296 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001297 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1298 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001299 if not trafficResult:
1300 result = main.FALSE
1301 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1302 dstEntry[ "host" ] ) )
1303 utilities.assert_equals( expect=main.TRUE,
1304 actual=result,
1305 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1306 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001307 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001308 Testcaselib.saveOnosDiagnostics( main )
1309 Testcaselib.cleanup( main, copyKarafLog=False )
1310 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001311
1312 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001313 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001314 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1315 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001316 """
1317 Verify reachability from each host in srcList to each host in dstList
1318 """
1319 from tests.dependencies.topology import Topology
1320 try:
1321 main.topo
1322 except ( NameError, AttributeError ):
1323 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001324 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001325 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001326 utilities.assert_equals( expect=main.TRUE,
1327 actual=pingResult,
1328 onpass="{}: Pass".format( stepMsg ),
1329 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001330 if not pingResult and skipOnFail:
1331 Testcaselib.saveOnosDiagnostics( main )
1332 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1333 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001334
1335 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001336 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001337 """
1338 Verify if the specified host is discovered by ONOS on the given locations
1339 Required:
You Wang85747762018-05-11 15:51:50 -07001340 locationDict: a dictionary that maps host names to expected locations.
1341 locations could be a string or a list.
1342 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001343 Returns:
1344 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1345 """
You Wang85747762018-05-11 15:51:50 -07001346 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1347 result = main.TRUE
1348 for hostName, locations in locationDict.items():
1349 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1350 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1351 if not hostIp:
1352 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1353 if not hostIp:
1354 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1355 result = main.FALSE
1356 continue
1357 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1358 main.FALSE,
1359 args=( hostIp, locations ),
1360 attempts=retry + 1,
1361 sleep=10 )
1362 if not locationResult:
1363 result = main.FALSE
1364 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001365 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001366 onpass="Location verification passed",
1367 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001368
1369 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001370 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001371 """
1372 Move specified host from srcSw to dstSw.
1373 If srcSw and dstSw are same, the host will be moved from current port to
1374 next available port.
1375 Required:
1376 hostName: name of the host. e.g., "h1"
1377 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1378 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1379 gw: ip address of the gateway of the new location
1380 Optional:
1381 macAddr: if specified, change MAC address of the host to the specified MAC address.
1382 prefixLen: prefix length
1383 cfg: port configuration as JSON string
1384 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001385 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001386 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001387 if not hasattr( main, 'Mininet1' ):
1388 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1389 return
1390
You Wang6e5b48e2018-07-23 16:17:38 -07001391 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1392 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1393 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001394 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001395 if cfg:
1396 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1397 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001398 # Wait for the host to get RA for setting up default gateway
1399 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001400
1401 main.Mininet1.discoverHosts( [ hostName, ] )
1402
1403 # Update expectedHost when MAC address is changed.
1404 if macAddr is not None:
1405 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1406 if ipAddr is not None:
1407 for hostName, ip in main.expectedHosts[ "onos" ].items():
1408 if ip == ipAddr:
1409 vlan = hostName.split( "/" )[ -1 ]
1410 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001411 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001412 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001413
1414 @staticmethod
1415 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001416 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001417 """
1418 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1419 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1420 to next available port.
1421 Required:
1422 hostName: name of the host. e.g., "h1"
1423 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1424 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1425 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1426 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1427 gw: ip address of the gateway of the new location
1428 Optional:
1429 macAddr: if specified, change MAC address of the host to the specified MAC address.
1430 prefixLen: prefix length
1431 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001432 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001433 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001434 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001435 if not hasattr( main, 'Mininet1' ):
1436 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1437 return
1438
You Wang6e5b48e2018-07-23 16:17:38 -07001439 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1440 srcSw, srcPairSw, dstSw, dstPairSw ) )
1441 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1442 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1443 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001444 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001445 if cfg:
1446 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1447 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001448 # Wait for the host to get RA for setting up default gateway
1449 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001450
1451 main.Mininet1.discoverHosts( [ hostName, ] )
1452
1453 # Update expectedHost when MAC address is changed.
1454 if macAddr is not None:
1455 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1456 if ipAddr is not None:
1457 for hostName, ip in main.expectedHosts[ "onos" ].items():
1458 if ip == ipAddr:
1459 vlan = hostName.split( "/" )[ -1 ]
1460 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001461 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip