blob: 6f9c0ed970853260195f75867ca75b68a28b5119 [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 Hallc7d3bc12020-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"
Jon Halla2e24d32020-06-05 12:04:06 -070079 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070080 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070081 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall1efcb3f2016-08-23 13:42:15 -070082
Devin Lim0c972b72018-02-08 14:53:59 -080083 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070084 except Exception as e:
85 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070086
Devin Lim58046fa2017-07-05 16:55:00 -070087 main.testSetUp.evnSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070088
Jon Hall1efcb3f2016-08-23 13:42:15 -070089 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -080090 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
91 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -070092 """
93 - Set up cell
94 - Create cell file
95 - Set cell file
96 - Verify cell file
97 - Kill ONOS process
98 - Uninstall ONOS cluster
99 - Verify ONOS start up
100 - Install ONOS cluster
101 - Connect to cli
102 """
103 # main.scale[ 0 ] determines the current number of ONOS controller
You Wangd87b2312018-01-30 12:47:17 -0800104 if not main.apps:
Jon Hall1efcb3f2016-08-23 13:42:15 -0700105 main.log.error( "App list is empty" )
Jon Hall3c910162018-03-07 14:42:16 -0800106 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
107 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700108 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800109 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800110 skipPack=skipPackage,
111 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800112 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700113 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
114 main.FALSE,
You Wang1cdc5f52017-12-19 16:47:51 -0800115 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700116 attempts=10 )
117 if ready:
118 ready = main.TRUE
119 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700120 onpass="ONOS summary command succeded",
121 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700122 if not ready:
123 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700124 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700125
Devin Lim142b5342017-07-20 15:22:39 -0700126 for ctrl in main.Cluster.active():
127 ctrl.CLI.logSet( "DEBUG", "org.onosproject.segmentrouting" )
You Wangf5f104f2018-03-30 17:09:10 -0700128 ctrl.CLI.logSet( "DEBUG", "org.onosproject.driver" )
Devin Lim142b5342017-07-20 15:22:39 -0700129 ctrl.CLI.logSet( "DEBUG", "org.onosproject.net.flowobjective.impl" )
You Wangf5f104f2018-03-30 17:09:10 -0700130 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.impl" )
131 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routeservice.store" )
132 ctrl.CLI.logSet( "DEBUG", "org.onosproject.routing.fpm" )
Jon Halla2e24d32020-06-05 12:04:06 -0700133 ctrl.CLI.logSet( "DEBUG", "org.onosproject.fpm" )
Jon Hall9677ed32018-04-24 11:16:23 -0700134 ctrl.CLI.logSet( "TRACE", "org.onosproject.events" )
135 ctrl.CLI.logSet( "DEBUG", "org.onosproject.mcast" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700136
Jon Halla2e24d32020-06-05 12:04:06 -0700137 ctrl.CLI.logSet( "TRACE", "org.onosproject.p4runtime" )
138 ctrl.CLI.logSet( "TRACE", "org.onosproject.protocols.p4runtime" )
139 ctrl.CLI.logSet( "TRACE", "org.onosproject.drivers.p4runtime" )
140 ctrl.CLI.logSet( "TRACE", "org.onosproject.protocols.grpc" )
141 ctrl.CLI.logSet( "TRACE", "org.onosproject.protocols.gnmi" )
142 ctrl.CLI.logSet( "TRACE", "org.onosproject.protocols.gnoi" )
143 ctrl.CLI.logSet( "TRACE", "org.onosproject.drivers.gnoi" )
144 ctrl.CLI.logSet( "TRACE", "org.onosproject.drivers.gmni" )
145 ctrl.CLI.logSet( "TRACE", "org.onosproject.drivers.stratum" )
146 ctrl.CLI.logSet( "TRACE", "org.onosproject.bmv2" )
147
Jon Hall1efcb3f2016-08-23 13:42:15 -0700148 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800149 def loadCount( main ):
150 with open("%s/count/%s.count" % (main.configPath, main.cfgName)) as count:
You Wang5df1c6d2018-04-06 18:02:02 -0700151 main.count = json.load(count)
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800152
153 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800154 def loadJson( main ):
155 with open( "%s%s.json" % ( main.configPath + main.forJson,
156 main.cfgName ) ) as cfg:
157 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
158
159 @staticmethod
160 def loadChart( main ):
161 try:
162 with open( "%s%s.chart" % ( main.configPath + main.forChart,
163 main.cfgName ) ) as chart:
164 main.pingChart = json.load(chart)
165 except IOError:
166 main.log.warn( "No chart file found." )
167
168 @staticmethod
169 def loadHost( main ):
170 with open( "%s%s.host" % ( main.configPath + main.forHost,
171 main.cfgName ) ) as host:
172 main.expectedHosts = json.load( host )
173
174 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800175 def loadSwitchFailureChart( main ):
176 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
177 main.cfgName ) ) as sfc:
178 main.switchFailureChart = json.load( sfc )
179
180 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800181 def loadLinkFailureChart( main ):
182 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700183 main.cfgName ) ) as lfc:
184 main.linkFailureChart = json.load( lfc )
185
186 @staticmethod
187 def loadMulticastConfig( main ):
188 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
189 main.cfgName ) ) as cfg:
190 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800191
192 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700193 def startMininet( main, topology, args="" ):
You Wangd87b2312018-01-30 12:47:17 -0800194 copyResult = main.ONOSbench.scp( main.Mininet1,
195 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700196 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800197 direction="to" )
198 if main.topologyLib:
199 for lib in main.topologyLib.split(","):
200 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
201 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700202 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800203 direction="to" )
204 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700205 import re
206 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
207 index = 0
You Wangd87b2312018-01-30 12:47:17 -0800208 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700209 # Update zebra configurations with correct ONOS instance IP
210 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
211 ip = controllerIPs[ index ]
212 index = ( index + 1 ) % len( controllerIPs )
213 with open( main.configPath + main.forConfig + conf ) as f:
214 s = f.read()
215 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
216 with open( main.configPath + main.forConfig + conf, "w" ) as f:
217 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800218 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800219 main.configPath + main.forConfig + conf,
You Wangd87b2312018-01-30 12:47:17 -0800220 "~/",
221 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800222 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallc7d3bc12020-05-27 09:29:30 -0700223 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800224 main.Mininet1.home + "custom",
225 direction="to" )
You Wangd87b2312018-01-30 12:47:17 -0800226 stepResult = copyResult
227 utilities.assert_equals( expect=main.TRUE,
228 actual=stepResult,
229 onpass="Successfully copied topo files",
230 onfail="Failed to copy topo files" )
Jon Halla2e24d32020-06-05 12:04:06 -0700231 if main.stratumRoot:
232 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
233 main.Mininet1.handle.expect( main.Mininet1.prompt )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700234 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700235 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700236 main.topology = topology
Jon Halla2e24d32020-06-05 12:04:06 -0700237 #switchType = " --switch=stratum"
238 #arg += switchType
Jon Hall1efcb3f2016-08-23 13:42:15 -0700239 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700240 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700241 stepResult = topoResult
242 utilities.assert_equals( expect=main.TRUE,
243 actual=stepResult,
244 onpass="Successfully loaded topology",
245 onfail="Failed to load topology" )
246 # Exit if topology did not load properly
247 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700248 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700249
250 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700251 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800252 main.step( "Connecting to physical netowrk" )
253 topoResult = main.NetworkBench.connectToNet()
254 stepResult = topoResult
255 utilities.assert_equals( expect=main.TRUE,
256 actual=stepResult,
257 onpass="Successfully loaded topology",
258 onfail="Failed to load topology" )
259 # Exit if topology did not load properly
260 if not topoResult:
261 main.cleanAndExit()
262
263 main.step( "Assign switches to controllers." )
264 assignResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700265 switches = main.NetworkBench.getSwitches()
266 pool = []
267 for name in switches.keys():
268 thread = main.Thread( target=main.NetworkBench.assignSwController,
269 name="assignSwitchToController",
270 args=[ name, main.Cluster.getIps(), '6653' ] )
271 pool.append( thread )
272 thread.start()
273 for thread in pool:
274 thread.join( 300 )
275 if not thread.result:
276 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800277 utilities.assert_equals( expect=main.TRUE,
278 actual=stepResult,
279 onpass="Successfully assign switches to controllers",
280 onfail="Failed to assign switches to controllers" )
281
You Wang4cc61912018-08-28 10:10:58 -0700282 # Check devices
283 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
284 time.sleep( float( main.params[ "timers" ][ "connectToNetSleep" ] ) )
285 # Connecting to hosts that only have data plane connectivity
286 main.step( "Connecting inband hosts" )
287 stepResult = main.Network.connectInbandHosts()
288 utilities.assert_equals( expect=main.TRUE,
289 actual=stepResult,
290 onpass="Successfully connected inband hosts",
291 onfail="Failed to connect inband hosts" )
292
You Wang84f981d2018-01-12 16:11:50 -0800293 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700294 def saveOnosDiagnostics( main ):
295 """
296 Get onos-diags.tar.gz and save it to the log directory.
297 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
298 """
299 main.log.info( "Collecting onos-diags..." )
300 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
301 main.logdir,
302 "-CASE%d" % main.CurrentTestCaseNumber )
303
304 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700305 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700306 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700307
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700308 main.failures = int( main.params[ 'failures' ] )
309 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700310
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700311 if main.cfgName == '2x2':
312 spine = {}
313 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
314 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
315 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700316
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700317 spine = {}
318 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
319 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
320 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700321
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700322 elif main.cfgName == '4x4':
323 spine = {}
324 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
325 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
326 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700327
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700328 spine = {}
329 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
330 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
331 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700332
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700333 spine = {}
334 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
335 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
336 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700337
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700338 spine = {}
339 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
340 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
341 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700342
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700343 else:
Piera2a7e1b2016-10-04 11:51:43 -0700344 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700345 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800346
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800347 @staticmethod
348 def addStaticOnosRoute( main, subnet, intf):
349 """
350 Adds an ONOS static route with the use route-add command.
351 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800352 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
353
Piera2a7e1b2016-10-04 11:51:43 -0700354 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700355 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700356 """
357 Check number of groups for each subnet on device deviceId and matches
358 it with an expected value. subnetDict is a dictionarty containing values
359 of the type "10.0.1.0/24" : 5.
360 """
You Wangc02f3be2018-05-18 12:14:23 -0700361 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
362 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
363 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700364
You Wangc02f3be2018-05-18 12:14:23 -0700365 result = main.TRUE
366 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700367 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700368 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700369 # this will match the group id that this flow entry points to, for example :
370 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700371 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700372 count = 0
373 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700374 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700375 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700376 if count - 1 != numberInSelect:
377 result = main.FALSE
378 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 ) )
379 utilities.assert_equals( expect=main.TRUE, actual=result,
380 onpass="All bucket numbers are as expected",
381 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700382
383 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900384 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700385 main.step(
Jon Hall3c910162018-03-07 14:42:16 -0800386 "Check whether the flow count is bigger than %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900387 if tag == "":
388 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700389 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700390 main.FALSE,
391 kwargs={ 'min': minFlowCount },
392 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800393 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800394 if count == main.FALSE:
395 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700396 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700397 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800398 actual=( count > minFlowCount ),
Jon Hall1efcb3f2016-08-23 13:42:15 -0700399 onpass="Flow count looks correct: " + str( count ),
400 onfail="Flow count looks wrong: " + str( count ) )
401
402 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700403 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700404 main.FALSE,
405 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800406 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800407 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700408 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700409 expect=main.TRUE,
410 actual=flowCheck,
411 onpass="Flow status is correct!",
412 onfail="Flow status is wrong!" )
413 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700414 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700415 "flows",
416 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900417 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700418 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700419 "groups",
420 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900421 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700422
423 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700424 def checkDevices( main, switches, tag="", sleep=10 ):
425 main.step(
426 "Check whether the switches count is equal to %s" % switches )
427 if tag == "":
428 tag = 'CASE%d' % main.CurrentTestCaseNumber
429 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
430 main.FALSE,
431 kwargs={ 'numoswitch': switches},
432 attempts=10,
433 sleep=sleep )
434 utilities.assert_equals( expect=main.TRUE, actual=result,
435 onpass="Device up successful",
436 onfail="Failed to boot up devices?" )
437
438 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800439 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
440 main.step(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800441 " Check whether the flow count of device %s is bigger than %s" % ( dpid, minFlowCount ) )
442 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
443 main.FALSE,
444 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800445 attempts=5,
446 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800447 if count == main.FALSE:
448 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800449 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800450 expect=True,
451 actual=( count > minFlowCount ),
452 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800453 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800454
455 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700456 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800457 main.step(
458 " Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
459 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
460 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700461 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800462 attempts=5,
463 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800464 if count == main.FALSE:
465 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800466 utilities.assertEquals(
467 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800468 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700469 onpass="Flow count looks correct: " + str( count ) ,
470 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800471
472 @staticmethod
473 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
474 main.step(
475 " Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
476 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
477 main.FALSE,
478 args=( dpid, groupCount, False, 1),
479 attempts=5,
480 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800481 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800482 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800483 utilities.assertEquals(
484 expect=True,
485 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700486 onpass="Group count looks correct: " + str( count ) ,
487 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800488
489 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700490 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800491
492 for dpid, values in main.count.items():
493 flowCount = values["flows"]
494 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700495 main.log.report( "Check flow count for dpid " + str( dpid ) +
496 ", should be " + str( flowCount ) )
497 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800498
Jon Hall9677ed32018-04-24 11:16:23 -0700499 main.log.report( "Check group count for dpid " + str( dpid ) +
500 ", should be " + str( groupCount ) )
501 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800502
503 return
504
505 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700506 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
507 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800508 '''
You Wangba231e72018-03-01 13:18:21 -0800509 Verify connectivity between hosts according to the ping chart
510 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800511 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800512 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800513 '''
You Wangba231e72018-03-01 13:18:21 -0800514 main.log.report( "Check host connectivity" )
515 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800516 if tag == "":
517 tag = 'CASE%d' % main.CurrentTestCaseNumber
518 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800519 main.log.debug( "Entry in ping chart: %s" % entry )
520 expect = entry[ 'expect' ]
521 if expect == "Unidirectional":
522 # Verify ping from each src host to each dst host
523 src = entry[ 'src' ]
524 dst = entry[ 'dst' ]
525 expect = main.TRUE
526 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
527 if basedOnIp:
528 if ("v4" in src[0]):
529 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
530 utilities.assert_equals( expect=expect, actual=pa,
531 onpass="IPv4 connectivity successfully tested",
532 onfail="IPv4 connectivity failed" )
533 if ("v6" in src[0]):
534 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
535 utilities.assert_equals( expect=expect, actual=pa,
536 onpass="IPv6 connectivity successfully tested",
537 onfail="IPv6 connectivity failed" )
538 else:
539 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
540 utilities.assert_equals( expect=expect, actual=pa,
541 onpass="IP connectivity successfully tested",
542 onfail="IP connectivity failed" )
543 else:
544 # Verify ping between each host pair
545 hosts = entry[ 'hosts' ]
546 try:
547 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
548 except:
549 expect = main.FALSE
550 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
551 if basedOnIp:
552 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800553 pa = utilities.retry( main.Network.pingallHosts,
554 main.FALSE if expect else main.TRUE,
555 args=(hosts,),
556 attempts=retryAttempts,
557 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800558 utilities.assert_equals( expect=expect, actual=pa,
559 onpass="IPv4 connectivity successfully tested",
560 onfail="IPv4 connectivity failed" )
561 if ("v6" in hosts[0]):
562 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
563 utilities.assert_equals( expect=expect, actual=pa,
564 onpass="IPv6 connectivity successfully tested",
565 onfail="IPv6 connectivity failed" )
566 else:
You Wangf19d9f42018-02-23 16:34:19 -0800567 pa = main.Network.pingallHosts( hosts )
568 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800569 onpass="IP connectivity successfully tested",
570 onfail="IP connectivity failed" )
You Wang5df1c6d2018-04-06 18:02:02 -0700571 if skipOnFail and pa != expect:
572 Testcaselib.saveOnosDiagnostics( main )
You Wang24ad2f52018-04-10 10:47:12 -0700573 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700574 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800575
576 if dumpflows:
577 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
578 "flows",
579 main.logdir,
580 tag + "_FlowsOn" )
581 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
582 "groups",
583 main.logdir,
584 tag + "_GroupsOn" )
585
586 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700587 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700588 """
589 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
590 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
591 Kill a link and verify ONOS can see the proper link change
592 """
Jon Halla604fd42018-05-04 14:27:27 -0700593 if sleep is None:
594 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
595 else:
596 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700597 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700598 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
599 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
600 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700601 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700602 "Waiting %s seconds for link down to be discovered" % sleep )
603 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700604 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700605 main.FALSE,
606 kwargs={ 'numoswitch': switches,
607 'numolink': links },
608 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700609 sleep=sleep )
610 result = topology and linkDown
Jon Hall1efcb3f2016-08-23 13:42:15 -0700611 utilities.assert_equals( expect=main.TRUE, actual=result,
612 onpass="Link down successful",
613 onfail="Failed to turn off link?" )
614
615 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700616 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800617 """
618 links = list of links (src, dst) to bring down.
619 """
620
621 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700622 if sleep is None:
623 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
624 else:
625 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800626
627 for end1, end2 in links:
628 main.Network.link( END1=end1, END2=end2, OPTION="down")
629 main.Network.link( END1=end2, END2=end1, OPTION="down")
630
Jon Halla604fd42018-05-04 14:27:27 -0700631 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800632 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700633 "Waiting %s seconds for links down to be discovered" % sleep )
634 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800635
636 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
637 main.FALSE,
638 kwargs={ 'numoswitch': switches,
639 'numolink': linksAfter },
640 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700641 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800642
You Wang2854bce2018-03-30 10:15:32 -0700643 utilities.assert_equals( expect=main.TRUE, actual=topology,
644 onpass="Link batch down successful",
645 onfail="Link batch down failed" )
646
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800647 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700648 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800649 """
650 links = list of link (src, dst) to bring up again.
651 """
652
653 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700654 if sleep is None:
655 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
656 else:
657 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800658
659 for end1, end2 in links:
660 main.Network.link( END1=end1, END2=end2, OPTION="up")
661 main.Network.link( END1=end2, END2=end1, OPTION="up")
662
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800663 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700664 "Waiting %s seconds for links up to be discovered" % sleep )
665 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800666
667 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
668 main.FALSE,
669 kwargs={ 'numoswitch': switches,
670 'numolink': linksAfter },
671 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700672 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800673
You Wang2854bce2018-03-30 10:15:32 -0700674 utilities.assert_equals( expect=main.TRUE, actual=topology,
675 onpass="Link batch up successful",
676 onfail="Link batch up failed" )
677
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800678 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700679 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
680 """
681 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
682 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
683 switches, links: number of expected switches and links after link change, ex.: '4', '6'
684 """
685 if sleep is None:
686 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
687 else:
688 sleep = float( sleep )
689 main.step( "Disable a batch of ports" )
690 for dpid, port in ports:
691 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
692 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
693 time.sleep( sleep )
694 if switches and links:
695 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
696 numolink=links )
697 utilities.assert_equals( expect=main.TRUE, actual=result,
698 onpass="Port down successful",
699 onfail="Port down failed" )
700
701 @staticmethod
702 def enablePortBatch( main, ports, switches, links, sleep=None ):
703 """
704 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
705 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
706 switches, links: number of expected switches and links after link change, ex.: '4', '6'
707 """
708 if sleep is None:
709 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
710 else:
711 sleep = float( sleep )
712 main.step( "Enable a batch of ports" )
713 for dpid, port in ports:
714 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
715 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
716 time.sleep( sleep )
717 if switches and links:
718 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
719 numolink=links )
720 utilities.assert_equals( expect=main.TRUE, actual=result,
721 onpass="Port up successful",
722 onfail="Port up failed" )
723
724 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700725 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700726 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700727 """
728 Params:
729 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700730 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700731 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
732 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
733 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
734 Kill a link and verify ONOS can see the proper link change
735 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700736 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700737 if sleep is None:
738 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
739 else:
740 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700741 result = False
742 count = 0
743 while True:
744 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700745 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800746 main.Network.link( END1=end1, END2=end2, OPTION="up" )
747 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700748 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700749 "Waiting %s seconds for link up to be discovered" % sleep )
750 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700751
You Wangc02d8352018-04-17 16:42:10 -0700752 if portUp:
753 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
754 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Halla604fd42018-05-04 14:27:27 -0700755 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700756
Jon Halla604fd42018-05-04 14:27:27 -0700757 result = ctrl.CLI.checkStatus( numoswitch=switches,
758 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700759 if count > 5 or result:
760 break
761 utilities.assert_equals( expect=main.TRUE, actual=result,
762 onpass="Link up successful",
763 onfail="Failed to bring link up" )
764
765 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700766 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700767 """
768 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
769 Completely kill a switch and verify ONOS can see the proper change
770 """
Jon Halla604fd42018-05-04 14:27:27 -0700771 if sleep is None:
772 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
773 else:
774 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700775 switch = switch if isinstance( switch, list ) else [ switch ]
776 main.step( "Kill " + str( switch ) )
777 for s in switch:
778 main.log.info( "Stopping " + s )
779 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700780 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700781
782 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700783 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700784 sleep ) )
785 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700786 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700787 main.FALSE,
788 kwargs={ 'numoswitch': switches,
789 'numolink': links },
790 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700791 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700792 utilities.assert_equals( expect=main.TRUE, actual=topology,
793 onpass="Kill switch successful",
794 onfail="Failed to kill switch?" )
795
796 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700797 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700798 """
799 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
800 Recover a switch and verify ONOS can see the proper change
801 """
Jon Halla604fd42018-05-04 14:27:27 -0700802 if sleep is None:
803 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
804 else:
805 sleep = float( sleep )
806 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700807 switch = switch if isinstance( switch, list ) else [ switch ]
808 main.step( "Recovering " + str( switch ) )
809 for s in switch:
810 main.log.info( "Starting " + s )
811 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700812 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700813 sleep ) )
814 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700815 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700816 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700817 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700818 sleep ) )
819 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700820
Devin Lim142b5342017-07-20 15:22:39 -0700821 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700822 main.FALSE,
823 kwargs={ 'numoswitch': switches,
824 'numolink': links },
825 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700826 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700827 utilities.assert_equals( expect=main.TRUE, actual=topology,
828 onpass="Switch recovery successful",
829 onfail="Failed to recover switch?" )
830
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700831 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700832 def killRouter( main, router, sleep=None ):
833 """
834 Kill bgpd process on a quagga router
835 router: name of the router to be killed. E.g. "bgp1"
836 """
837 sleep = float( sleep )
838 main.step( "Kill " + str( router ) )
839 if hasattr( main, 'Mininet1' ):
840 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
841 main.Mininet1.handle.expect( "mininet>" )
842 else:
843 # TODO: support killing router in physical network
844 pass
845 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
846 time.sleep( sleep )
847
848 @staticmethod
849 def recoverRouter( main, router, sleep=None ):
850 """
851 Restart bgpd process on a quagga router
852 router: name of the router to be recovered. E.g. "bgp1"
853 """
854 sleep = float( sleep )
855 main.step( "Recovering " + str( router ) )
856 if hasattr( main, 'Mininet1' ):
857 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
858 main.Mininet1.handle.expect( "mininet>" )
859 else:
860 # TODO: support recovering router in physical network
861 pass
862 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
863 time.sleep( sleep )
864
865 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700866 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700867 """
868 Stop Onos-cluster.
869 Stops Mininet
870 Copies ONOS log
871 """
You Wang4cc61912018-08-28 10:10:58 -0700872 from tests.dependencies.utils import Utils
873 main.utils = Utils()
Jon Halla2e24d32020-06-05 12:04:06 -0700874 for ctrl in main.Cluster.active():
875 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -0700876 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -0700877 if hasattr( main, "scapyHosts" ):
878 scapyResult = main.TRUE
879 for host in main.scapyHosts:
880 scapyResult = host.stopScapy() and scapyResult
881 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
882 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -0700883 if hasattr( main, 'Mininet1' ):
884 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
885 else:
886 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -0700887 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
888 main.scapyHosts = []
889
You Wang5da39c82018-04-26 22:55:08 -0700890 if removeHostComponent:
891 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
892 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -0700893 if hasattr( main, 'Mininet1' ):
894 pass
895 else:
896 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -0700897 main.Network.removeHostComponent( host )
898
You Wang5df1c6d2018-04-06 18:02:02 -0700899 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -0700900 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -0700901 else:
902 main.Network.disconnectInbandHosts()
903 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -0700904
You Wang5df1c6d2018-04-06 18:02:02 -0700905 if copyKarafLog:
906 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -0700907
Devin Lim142b5342017-07-20 15:22:39 -0700908 for ctrl in main.Cluster.active():
909 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700910
911 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700912 def verifyNodes( main ):
913 """
914 Verifies Each active node in the cluster has an accurate view of other node's and their status
915
916 Params:
917 nodes, integer array with position of the ONOS nodes in the CLIs array
918 """
919 nodeResults = utilities.retry( main.Cluster.nodesCheck,
920 False,
921 attempts=10,
922 sleep=10 )
923 utilities.assert_equals( expect=True, actual=nodeResults,
924 onpass="Nodes check successful",
925 onfail="Nodes check NOT successful" )
926
927 if not nodeResults:
928 for ctrl in main.Cluster.runningNodes:
929 main.log.debug( "{} components not ACTIVE: \n{}".format(
930 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -0800931 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -0800932 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -0700933 main.cleanAndExit()
934
935 @staticmethod
936 def verifyTopology( main, switches, links, expNodes ):
937 """
938 Verifies that the ONOS cluster has an acuurate view of the topology
939
940 Params:
941 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
942 """
943 main.step( "Check number of topology elements" )
944 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
945 main.FALSE,
946 kwargs={ 'numoswitch': switches,
947 'numolink': links,
948 'numoctrl': expNodes },
949 attempts=10,
950 sleep=12 )
951 utilities.assert_equals( expect=main.TRUE, actual=topology,
952 onpass="Number of topology elements are correct",
953 onfail="Unexpected number of links, switches, and/or controllers" )
954
955 @staticmethod
956 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700957 """
958 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
959 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
960 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
961 """
Jon Halla604fd42018-05-04 14:27:27 -0700962 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -0800963 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700964 if sleep is None:
965 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
966 else:
967 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -0700968
Jon Hall1efcb3f2016-08-23 13:42:15 -0700969 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700970 killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700971 utilities.assert_equals( expect=main.TRUE, actual=killResult,
972 onpass="ONOS instance Killed",
973 onfail="Error killing ONOS instance" )
Devin Lim142b5342017-07-20 15:22:39 -0700974 main.Cluster.runningNodes[ i ].active = False
Jon Halla604fd42018-05-04 14:27:27 -0700975 main.Cluster.reset()
976 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -0700977
Devin Lim142b5342017-07-20 15:22:39 -0700978 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -0700979 Testcaselib.verifyNodes( main )
980 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700981
982 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700983 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700984 """
985 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
986 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
987 Recover an ONOS instance and verify the ONOS cluster can see the proper change
988 """
Jon Hall3c910162018-03-07 14:42:16 -0800989 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -0700990 if sleep is None:
991 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
992 else:
993 sleep = float( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700994 [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
Jon Halla604fd42018-05-04 14:27:27 -0700995 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700996 for i in nodes:
Devin Lim142b5342017-07-20 15:22:39 -0700997 isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700998 utilities.assert_equals( expect=main.TRUE, actual=isUp,
999 onpass="ONOS service is ready",
1000 onfail="ONOS service did not start properly" )
1001 for i in nodes:
1002 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001003 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001004 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001005 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1006 commandlineTimeout=60,
1007 onosStartTimeout=100 )
1008 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001009 utilities.assert_equals( expect=main.TRUE,
1010 actual=cliResult,
1011 onpass="ONOS CLI is ready",
1012 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001013
Jon Halla604fd42018-05-04 14:27:27 -07001014 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001015 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001016 Testcaselib.verifyNodes( main )
1017 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001018
Devin Lim142b5342017-07-20 15:22:39 -07001019 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
1020 main.FALSE,
1021 attempts=10,
1022 sleep=12 )
1023 if ready:
1024 ready = main.TRUE
1025 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001026 onpass="ONOS summary command succeded",
1027 onfail="ONOS summary command failed" )
1028 if not ready:
1029 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001030 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001031
1032 @staticmethod
1033 def addHostCfg( main ):
1034 """
1035 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001036 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001037 """
1038 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001039 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001040 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001041 hostCfg = json.load( template )
1042 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
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='' ),
1049 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001050 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1051 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001052 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001053 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1054 subjectClass="hosts",
1055 subjectKey=urllib.quote( mac,
1056 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001057 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001058 main.pingChart.update( { 'vlan1': { "expect": "True",
1059 "hosts": [ "olt1", "vsg1" ] } } )
1060 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1061 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001062 ports = "[%s,%s]" % ( 5, 6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001063 cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
Devin Lim142b5342017-07-20 15:22:39 -07001064 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1065 subjectClass="apps",
1066 subjectKey="org.onosproject.segmentrouting",
1067 configKey="xconnect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001068
1069 @staticmethod
1070 def delHostCfg( main ):
1071 """
1072 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001073 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001074 """
1075 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001076 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001077 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001078 hostCfg = json.load( template )
1079 main.step( "Removing host 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 configuration" )
1088 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001089 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001090 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1091 subjectKey=urllib.quote(
1092 mac,
1093 safe='' ),
1094 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001095 main.step( "Removing vlan configuration" )
1096 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Devin Lim142b5342017-07-20 15:22:39 -07001097 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
1098 subjectKey="org.onosproject.segmentrouting",
1099 configKey="xconnect" )
You Wang53dba1e2018-02-02 17:45:44 -08001100
1101 @staticmethod
1102 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1103 """
1104 Verifies IP address assignment from the hosts
1105 """
1106 main.step( "Verify IP address assignment from hosts" )
1107 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001108 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001109 # Find out names of disconnected hosts
1110 disconnectedHosts = []
1111 if hasattr( main, "disconnectedIpv4Hosts" ):
1112 for host in main.disconnectedIpv4Hosts:
1113 disconnectedHosts.append( host )
1114 if hasattr( main, "disconnectedIpv6Hosts" ):
1115 for host in main.disconnectedIpv6Hosts:
1116 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001117 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001118 # Exclude disconnected hosts
1119 if hostName in disconnectedHosts:
1120 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1121 continue
You Wang53dba1e2018-02-02 17:45:44 -08001122 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1123 main.FALSE,
1124 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001125 'prefix': ip,
1126 'update': False },
You Wang53dba1e2018-02-02 17:45:44 -08001127 attempts=attempts,
1128 sleep=sleep )
1129 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1130 onpass="Verify network host IP succeded",
1131 onfail="Verify network host IP failed" )
1132
1133 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001134 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001135 """
1136 Verifies host IP address assignment from ONOS
1137 """
1138 main.step( "Verify host IP address assignment in ONOS" )
1139 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001140 # Find out IPs of disconnected hosts
1141 disconnectedIps = []
1142 if hasattr( main, "disconnectedIpv4Hosts" ):
1143 for host in main.disconnectedIpv4Hosts:
1144 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1145 if hasattr( main, "disconnectedIpv6Hosts" ):
1146 for host in main.disconnectedIpv6Hosts:
1147 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001148 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001149 # Exclude disconnected hosts
1150 if ip in disconnectedIps:
1151 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1152 continue
You Wang53dba1e2018-02-02 17:45:44 -08001153 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1154 main.FALSE,
1155 kwargs={ 'hostList': [ hostName ],
1156 'prefix': ip },
1157 attempts=attempts,
1158 sleep=sleep )
1159 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1160 onpass="Verify ONOS host IP succeded",
1161 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001162 if not ipResult and skipOnFail:
1163 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001164 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001165 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001166
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001167 @staticmethod
1168 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1169 """
1170 Description:
1171 Updates interface configuration in ONOS, with given IP and vlan parameters
1172 Required:
1173 * connectPoint: connect point to update configuration
1174 Optional:
1175 * ips: list of IP addresses, combined with '/xx' subnet representation,
1176 corresponding to 'ips' field in the configuration
1177 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1178 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1179 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1180 """
1181 cfg = dict()
1182 cfg[ "ports" ] = dict()
1183 cfg[ "ports" ][ connectPoint ] = dict()
1184 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1185 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1186 if untagged > 0:
1187 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1188 else:
1189 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1190 if native > 0:
1191 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1192
1193 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001194
1195 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001196 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001197 """
1198 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001199 scapyNames: list of names that will be used as component names for scapy hosts
1200 mininetNames: used when scapy host names are different from the host names
1201 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1202 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001203 """
1204 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001205 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1206 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001207 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001208 if hasattr( main, 'Mininet1' ):
1209 main.Scapy.createHostComponent( scapyName )
1210 scapyHandle = getattr( main, scapyName )
1211 if mininetNames:
1212 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1213 else:
1214 mininetName = None
1215 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001216 else:
You Wang0fc21702018-11-02 17:49:18 -07001217 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001218 scapyHandle = getattr( main, scapyName )
1219 scapyHandle.connectInband()
1220 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001221 scapyHandle.startScapy()
1222 scapyHandle.updateSelf()
1223 main.log.debug( scapyHandle.name )
1224 main.log.debug( scapyHandle.hostIp )
1225 main.log.debug( scapyHandle.hostMac )
1226
1227 @staticmethod
1228 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1229 """
1230 Verify unicast traffic by pinging from source hosts to the destination IP
1231 and capturing the packets at the destination host using Scapy.
1232 srcHosts: List of host names to send the ping packets
1233 dstIp: destination IP of the ping packets
1234 dstHost: host that runs Scapy to capture the packets
1235 dstIntf: name of the interface on the destination host
1236 expect: use True if the ping is expected to be captured at destination;
1237 Otherwise False
1238 skipOnFail: skip the rest of this test case if result is not expected
1239 maxRetry: number of retries allowed
1240 """
1241 from tests.dependencies.topology import Topology
1242 try:
1243 main.topo
1244 except ( NameError, AttributeError ):
1245 main.topo = Topology()
1246 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1247 result = main.TRUE
1248 for srcHost in srcHosts:
1249 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1250 expect, maxRetry, True )
1251 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001252 result = main.FALSE
1253 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1254 utilities.assert_equals( expect=main.TRUE,
1255 actual=result,
1256 onpass="Verify traffic to {}: Pass".format( dstIp ),
1257 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1258 if skipOnFail and result != main.TRUE:
1259 Testcaselib.saveOnosDiagnostics( main )
1260 Testcaselib.cleanup( main, copyKarafLog=False )
1261 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001262
1263 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001264 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001265 """
1266 Verify multicast traffic using scapy
1267 """
You Wangc564c6f2018-05-01 15:24:57 -07001268 from tests.dependencies.topology import Topology
1269 try:
1270 main.topo
1271 except ( NameError, AttributeError ):
1272 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001273 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001274 routeData = main.multicastConfig[ routeName ]
1275 srcs = main.mcastRoutes[ routeName ][ "src" ]
1276 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1277 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1278 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001279 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001280 for src in srcs:
1281 srcEntry = routeData[ "src" ][ src ]
1282 for dst in dsts:
1283 dstEntry = routeData[ "dst" ][ dst ]
1284 sender = getattr( main, srcEntry[ "host" ] )
1285 receiver = getattr( main, dstEntry[ "host" ] )
1286 main.Network.addRoute( str( srcEntry[ "host" ] ),
1287 str( routeData[ "group" ] ),
1288 str( srcEntry[ "interface" ] ),
1289 True if routeData[ "ipVersion" ] == 6 else False )
1290 # Build the packet
1291 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1292 if routeData[ "ipVersion" ] == 4:
1293 sender.buildIP( dst=str( routeData[ "group" ] ) )
1294 elif routeData[ "ipVersion" ] == 6:
1295 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1296 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1297 sIface = srcEntry[ "interface" ]
1298 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1299 pktFilter = srcEntry[ "filter" ]
1300 pkt = srcEntry[ "packet" ]
1301 # Send packet and check received packet
1302 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001303 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001304 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001305 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1306 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001307 if not trafficResult:
1308 result = main.FALSE
1309 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1310 dstEntry[ "host" ] ) )
1311 utilities.assert_equals( expect=main.TRUE,
1312 actual=result,
1313 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1314 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001315 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001316 Testcaselib.saveOnosDiagnostics( main )
1317 Testcaselib.cleanup( main, copyKarafLog=False )
1318 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001319
1320 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001321 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001322 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1323 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001324 """
1325 Verify reachability from each host in srcList to each host in dstList
1326 """
1327 from tests.dependencies.topology import Topology
1328 try:
1329 main.topo
1330 except ( NameError, AttributeError ):
1331 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001332 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001333 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001334 utilities.assert_equals( expect=main.TRUE,
1335 actual=pingResult,
1336 onpass="{}: Pass".format( stepMsg ),
1337 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001338 if not pingResult and skipOnFail:
1339 Testcaselib.saveOnosDiagnostics( main )
1340 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1341 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001342
1343 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001344 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001345 """
1346 Verify if the specified host is discovered by ONOS on the given locations
1347 Required:
You Wang85747762018-05-11 15:51:50 -07001348 locationDict: a dictionary that maps host names to expected locations.
1349 locations could be a string or a list.
1350 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001351 Returns:
1352 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1353 """
You Wang85747762018-05-11 15:51:50 -07001354 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1355 result = main.TRUE
1356 for hostName, locations in locationDict.items():
1357 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1358 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1359 if not hostIp:
1360 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1361 if not hostIp:
1362 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1363 result = main.FALSE
1364 continue
1365 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1366 main.FALSE,
1367 args=( hostIp, locations ),
1368 attempts=retry + 1,
1369 sleep=10 )
1370 if not locationResult:
1371 result = main.FALSE
1372 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001373 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001374 onpass="Location verification passed",
1375 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001376
1377 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001378 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001379 """
1380 Move specified host from srcSw to dstSw.
1381 If srcSw and dstSw are same, the host will be moved from current port to
1382 next available port.
1383 Required:
1384 hostName: name of the host. e.g., "h1"
1385 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1386 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1387 gw: ip address of the gateway of the new location
1388 Optional:
1389 macAddr: if specified, change MAC address of the host to the specified MAC address.
1390 prefixLen: prefix length
1391 cfg: port configuration as JSON string
1392 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001393 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001394 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001395 if not hasattr( main, 'Mininet1' ):
1396 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1397 return
1398
You Wang6e5b48e2018-07-23 16:17:38 -07001399 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1400 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1401 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001402 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001403 if cfg:
1404 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1405 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001406 # Wait for the host to get RA for setting up default gateway
1407 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001408
1409 main.Mininet1.discoverHosts( [ hostName, ] )
1410
1411 # Update expectedHost when MAC address is changed.
1412 if macAddr is not None:
1413 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1414 if ipAddr is not None:
1415 for hostName, ip in main.expectedHosts[ "onos" ].items():
1416 if ip == ipAddr:
1417 vlan = hostName.split( "/" )[ -1 ]
1418 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001419 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001420 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001421
1422 @staticmethod
1423 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001424 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001425 """
1426 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1427 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1428 to next available port.
1429 Required:
1430 hostName: name of the host. e.g., "h1"
1431 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1432 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1433 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1434 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1435 gw: ip address of the gateway of the new location
1436 Optional:
1437 macAddr: if specified, change MAC address of the host to the specified MAC address.
1438 prefixLen: prefix length
1439 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001440 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001441 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001442 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001443 if not hasattr( main, 'Mininet1' ):
1444 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1445 return
1446
You Wang6e5b48e2018-07-23 16:17:38 -07001447 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1448 srcSw, srcPairSw, dstSw, dstPairSw ) )
1449 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1450 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1451 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001452 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001453 if cfg:
1454 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1455 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001456 # Wait for the host to get RA for setting up default gateway
1457 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001458
1459 main.Mininet1.discoverHosts( [ hostName, ] )
1460
1461 # Update expectedHost when MAC address is changed.
1462 if macAddr is not None:
1463 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1464 if ipAddr is not None:
1465 for hostName, ip in main.expectedHosts[ "onos" ].items():
1466 if ip == ipAddr:
1467 vlan = hostName.split( "/" )[ -1 ]
1468 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001469 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip