blob: 15c09d516216207ae498fdf85d0c95aa450dc79f [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 Hallf6aeda22020-07-28 09:12:56 -070026import pexpect
Jon Hall1efcb3f2016-08-23 13:42:15 -070027from core import utilities
28
29
30class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070031
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070032 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070033
Jon Hall1efcb3f2016-08-23 13:42:15 -070034 @staticmethod
35 def initTest( main ):
36 """
37 - Construct tests variables
38 - GIT ( optional )
39 - Checkout ONOS master branch
40 - Pull latest ONOS code
41 - Building ONOS ( optional )
42 - Install ONOS package
43 - Build ONOS package
44 """
Devin Lim58046fa2017-07-05 16:55:00 -070045 try:
46 from tests.dependencies.ONOSSetup import ONOSSetup
47 main.testSetUp = ONOSSetup()
48 except ImportError:
49 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070050 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080051 from tests.dependencies.Network import Network
52 main.Network = Network()
Jon Hall43060f62020-06-23 13:13:33 -070053 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080054 main.testSetUp.envSetupDescription( False )
Jon Hall39570262020-11-17 12:18:19 -080055 main.logdirBase = main.logdir
Devin Lim58046fa2017-07-05 16:55:00 -070056 stepResult = main.FALSE
57 try:
Devin Lim58046fa2017-07-05 16:55:00 -070058 # Test variables
59 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
60 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070061 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080062 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
63 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
64 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080065 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
66 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
67 else:
68 main.useBmv2 = False
Jon Hall43060f62020-06-23 13:13:33 -070069 if main.useBmv2:
70 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
71 else:
72 main.switchType = "ovs"
73
Devin Lim57221b02018-02-14 15:45:36 -080074 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070075 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080076 main.forJson = "json/"
77 main.forChart = "chart/"
78 main.forConfig = "conf/"
79 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080080 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080081 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070082 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070083 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080084 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
85 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080086 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070087 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070088 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070089 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070090 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070091 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070092
Devin Lim0c972b72018-02-08 14:53:59 -080093 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070094 except Exception as e:
95 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070096
Jon Hallaa1d9b82020-07-30 13:49:42 -070097 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070098
Jon Hall1efcb3f2016-08-23 13:42:15 -070099 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800100 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
101 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700102 """
103 - Set up cell
104 - Create cell file
105 - Set cell file
106 - Verify cell file
107 - Kill ONOS process
108 - Uninstall ONOS cluster
109 - Verify ONOS start up
110 - Install ONOS cluster
111 - Connect to cli
112 """
113 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700114 try:
115 if main.params.get( 'EXTERNAL_APPS' ):
116 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800117 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700118 main.ONOSbench.onosFetchApp( url )
119 if not main.apps:
120 main.log.error( "App list is empty" )
121 except Exception as e:
122 main.log.debug( e )
123 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800124 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
125 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700126 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800127 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800128 skipPack=skipPackage,
129 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800130 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700131 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700132 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800133 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700134 attempts=10 )
135 if ready:
136 ready = main.TRUE
137 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700138 onpass="ONOS summary command succeded",
139 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700140 if not ready:
141 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700142 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700143
You Wang5bf49592020-07-08 18:47:46 -0700144 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700145 appInstallResult = main.TRUE
146 if main.trellisOar:
147 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700148 if main.t3Oar:
149 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
150 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
151 onpass="SR app installation succeded",
152 onfail="SR app installation failed" )
153 if not appInstallResult:
154 main.cleanAndExit()
155
Jon Hall43060f62020-06-23 13:13:33 -0700156 # FIXME: move to somewhere else?
157 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
158 # TODO: Support other pipeconfs/making this configurable
159 if switchPrefix == "tofino":
160 # It seems to take some time for the pipeconfs to be loaded
161 ctrl = main.Cluster.next()
162 for i in range( 120 ):
163 try:
164 main.log.debug( "Checking to see if pipeconfs are loaded" )
165 output = ctrl.CLI.sendline( "pipeconfs" )
166 if "tofino" in output:
167 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
168 break
169 time.sleep( 1 )
170 except Exception as e:
171 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700172
Jon Hall43060f62020-06-23 13:13:33 -0700173 Testcaselib.setOnosLogLevels( main )
174 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700175
Jon Hall1efcb3f2016-08-23 13:42:15 -0700176 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800177 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700178 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
179 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800180
181 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700182 def loadJson( main, suffix='' ):
183 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
184 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800185 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
186
187 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700188 def loadXconnects( main, suffix='' ):
189 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
190 main.cfgName, suffix ) ) as cfg:
191 for xconnect in json.load( cfg ).get('xconnects'):
192 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
193
194 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800195 def loadChart( main ):
196 try:
197 with open( "%s%s.chart" % ( main.configPath + main.forChart,
198 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700199 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800200 except IOError:
201 main.log.warn( "No chart file found." )
202
203 @staticmethod
204 def loadHost( main ):
205 with open( "%s%s.host" % ( main.configPath + main.forHost,
206 main.cfgName ) ) as host:
207 main.expectedHosts = json.load( host )
208
209 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800210 def loadSwitchFailureChart( main ):
211 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
212 main.cfgName ) ) as sfc:
213 main.switchFailureChart = json.load( sfc )
214
215 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800216 def loadLinkFailureChart( main ):
217 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700218 main.cfgName ) ) as lfc:
219 main.linkFailureChart = json.load( lfc )
220
221 @staticmethod
222 def loadMulticastConfig( main ):
223 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
224 main.cfgName ) ) as cfg:
225 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800226
227 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700228 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700229 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800230 copyResult = main.ONOSbench.scp( main.Mininet1,
231 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700232 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800233 direction="to" )
234 if main.topologyLib:
235 for lib in main.topologyLib.split(","):
236 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
237 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700238 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800239 direction="to" )
240 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700241 import re
242 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
243 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700244 destDir = "~/"
245 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
246 destDir = "/tmp/mn_conf/"
247 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800248 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700249 # Update zebra configurations with correct ONOS instance IP
250 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
251 ip = controllerIPs[ index ]
252 index = ( index + 1 ) % len( controllerIPs )
253 with open( main.configPath + main.forConfig + conf ) as f:
254 s = f.read()
255 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
256 with open( main.configPath + main.forConfig + conf, "w" ) as f:
257 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800258 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800259 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700260 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800261 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800262 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700263 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800264 main.Mininet1.home + "custom",
265 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700266
267 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
268 # move the config files into home
269 main.Mininet1.handle.sendline( "cp config/* . " )
270 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
271 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
272 main.Mininet1.handle.sendline( "ls -al " )
273 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
274 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
275
You Wangd87b2312018-01-30 12:47:17 -0800276 stepResult = copyResult
277 utilities.assert_equals( expect=main.TRUE,
278 actual=stepResult,
279 onpass="Successfully copied topo files",
280 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700281 if main.stratumRoot:
282 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700283 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700284 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700285 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700286 main.topology = topology
287 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700288 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700289 stepResult = topoResult
290 utilities.assert_equals( expect=main.TRUE,
291 actual=stepResult,
292 onpass="Successfully loaded topology",
293 onfail="Failed to load topology" )
294 # Exit if topology did not load properly
295 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700296 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700297 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700298 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700299 # Upload the net-cfg file created for each switch
300 filename = "onos-netcfg.json"
301 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700302 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700303 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
304 path = "/tmp/mn-stratum/%s/" % switch
305 dstPath = "/tmp/"
306 dstFileName = "%s-onos-netcfg.json" % switch
307 main.ONOSbench1.scp( main.Mininet1,
308 "%s%s" % ( path, filename ),
309 "%s%s" % ( dstPath, dstFileName ),
310 "from" )
311 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700312 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700313 # Configure managementAddress
314 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
315 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
316 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
317 # Configure device id
318 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
319 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
320 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
321 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800322 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s:%s\",' %s%s" % ( switchPrefix, switch, dstPath, dstFileName ) )
Jon Hall43060f62020-06-23 13:13:33 -0700323 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
324 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700325 node = main.Cluster.active(0)
326 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
327 dstPath,
328 dstFileName,
329 user=node.REST.user_name,
330 password=node.REST.pwd )
331 # Stop test if we fail to push switch netcfg
332 utilities.assert_equals( expect=main.TRUE,
333 actual=switchNetCfg,
334 onpass="Successfully pushed switch netcfg",
335 onfail="Failed to configure switches in onos" )
336 if not switchNetCfg:
337 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700338 # Make sure hosts make some noise
339 Testcaselib.discoverHosts( main )
340
341 @staticmethod
342 def discoverHosts( main ):
343 # TODO add option to only select specific hosts
344 if hasattr( main, "Mininet1" ):
345 network = main.Mininet1
346 elif hasattr( main, "NetworkBench" ):
347 network = main.NetworkBench
348 else:
349 main.log.warn( "Could not find component for test network, skipping host discovery" )
350 return
351 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700352
353 @staticmethod
You Wang4cc61912018-08-28 10:10:58 -0700354 def connectToPhysicalNetwork( main ):
You Wang84f981d2018-01-12 16:11:50 -0800355 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700356 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800357 topoResult = main.NetworkBench.connectToNet()
358 stepResult = topoResult
359 utilities.assert_equals( expect=main.TRUE,
360 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700361 onpass="Successfully connected to topology",
362 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800363 # Exit if topology did not load properly
364 if not topoResult:
365 main.cleanAndExit()
366
Jon Hall43060f62020-06-23 13:13:33 -0700367 # Perform any optional setup
368 for switch in main.NetworkBench.switches:
369 if hasattr( switch, "setup" ):
370 switch.setup() # We might not need this
371
You Wang84f981d2018-01-12 16:11:50 -0800372 main.step( "Assign switches to controllers." )
Jon Hall43060f62020-06-23 13:13:33 -0700373 stepResult = main.TRUE
You Wang4cc61912018-08-28 10:10:58 -0700374 switches = main.NetworkBench.getSwitches()
375 pool = []
376 for name in switches.keys():
Jon Hall43060f62020-06-23 13:13:33 -0700377 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
378 # e.g. push onos net-cfg for stratum switches
You Wang4cc61912018-08-28 10:10:58 -0700379 thread = main.Thread( target=main.NetworkBench.assignSwController,
380 name="assignSwitchToController",
381 args=[ name, main.Cluster.getIps(), '6653' ] )
382 pool.append( thread )
383 thread.start()
384 for thread in pool:
385 thread.join( 300 )
386 if not thread.result:
387 stepResult = main.FALSE
You Wang84f981d2018-01-12 16:11:50 -0800388 utilities.assert_equals( expect=main.TRUE,
389 actual=stepResult,
390 onpass="Successfully assign switches to controllers",
391 onfail="Failed to assign switches to controllers" )
392
You Wang4cc61912018-08-28 10:10:58 -0700393 # Check devices
394 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700395 # Connecting to hosts that only have data plane connectivity
396 main.step( "Connecting inband hosts" )
397 stepResult = main.Network.connectInbandHosts()
398 utilities.assert_equals( expect=main.TRUE,
399 actual=stepResult,
400 onpass="Successfully connected inband hosts",
401 onfail="Failed to connect inband hosts" )
Jon Hall43060f62020-06-23 13:13:33 -0700402 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700403
You Wang84f981d2018-01-12 16:11:50 -0800404 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700405 def saveOnosDiagnostics( main ):
406 """
407 Get onos-diags.tar.gz and save it to the log directory.
408 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
409 """
410 main.log.info( "Collecting onos-diags..." )
411 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
412 main.logdir,
413 "-CASE%d" % main.CurrentTestCaseNumber )
414
415 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700416 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700417 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700418
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700419 main.failures = int( main.params[ 'failures' ] )
420 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700421
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700422 if main.cfgName == '2x2':
423 spine = {}
424 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
425 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
426 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700427
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700428 spine = {}
429 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
430 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
431 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700432
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700433 elif main.cfgName == '4x4':
434 spine = {}
435 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
436 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
437 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700438
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700439 spine = {}
440 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
441 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
442 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700443
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700444 spine = {}
445 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
446 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
447 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700448
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700449 spine = {}
450 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
451 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
452 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700453
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700454 else:
Piera2a7e1b2016-10-04 11:51:43 -0700455 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700456 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800457
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800458 @staticmethod
459 def addStaticOnosRoute( main, subnet, intf):
460 """
461 Adds an ONOS static route with the use route-add command.
462 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800463 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
464
Piera2a7e1b2016-10-04 11:51:43 -0700465 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700466 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700467 """
468 Check number of groups for each subnet on device deviceId and matches
469 it with an expected value. subnetDict is a dictionarty containing values
470 of the type "10.0.1.0/24" : 5.
471 """
You Wangc02f3be2018-05-18 12:14:23 -0700472 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
473 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
474 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700475
You Wangc02f3be2018-05-18 12:14:23 -0700476 result = main.TRUE
477 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700478 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700479 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700480 # this will match the group id that this flow entry points to, for example :
481 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700482 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700483 count = 0
484 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700485 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700486 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700487 if count - 1 != numberInSelect:
488 result = main.FALSE
489 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 ) )
490 utilities.assert_equals( expect=main.TRUE, actual=result,
491 onpass="All bucket numbers are as expected",
492 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700493
494 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900495 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700496 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800497 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900498 if tag == "":
499 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700500 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700501 main.FALSE,
502 kwargs={ 'min': minFlowCount },
503 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800504 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800505 if count == main.FALSE:
506 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700507 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700508 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800509 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700510 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
511 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700512
513 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700514 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700515 main.FALSE,
516 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800517 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800518 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700519 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700520 expect=main.TRUE,
521 actual=flowCheck,
522 onpass="Flow status is correct!",
523 onfail="Flow status is wrong!" )
524 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700525 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700526 "flows",
527 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900528 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700529 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700530 "groups",
531 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900532 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700533
534 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700535 def checkDevices( main, switches, tag="", sleep=10 ):
536 main.step(
537 "Check whether the switches count is equal to %s" % switches )
538 if tag == "":
539 tag = 'CASE%d' % main.CurrentTestCaseNumber
540 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
541 main.FALSE,
542 kwargs={ 'numoswitch': switches},
543 attempts=10,
544 sleep=sleep )
545 utilities.assert_equals( expect=main.TRUE, actual=result,
546 onpass="Device up successful",
547 onfail="Failed to boot up devices?" )
548
549 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800550 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
551 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800552 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800553 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
554 main.FALSE,
555 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800556 attempts=5,
557 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800558 if count == main.FALSE:
559 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800560 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800561 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800562 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800563 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800564 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800565
566 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700567 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800568 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700569 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800570 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
571 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700572 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800573 attempts=5,
574 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800575 if count == main.FALSE:
576 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800577 utilities.assertEquals(
578 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800579 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700580 onpass="Flow count looks correct: " + str( count ) ,
581 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800582
583 @staticmethod
584 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
585 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700586 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800587 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
588 main.FALSE,
589 args=( dpid, groupCount, False, 1),
590 attempts=5,
591 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800592 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800593 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800594 utilities.assertEquals(
595 expect=True,
596 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700597 onpass="Group count looks correct: " + str( count ) ,
598 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800599
600 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700601 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800602
603 for dpid, values in main.count.items():
604 flowCount = values["flows"]
605 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700606 main.log.report( "Check flow count for dpid " + str( dpid ) +
607 ", should be " + str( flowCount ) )
608 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800609
Jon Hall9677ed32018-04-24 11:16:23 -0700610 main.log.report( "Check group count for dpid " + str( dpid ) +
611 ", should be " + str( groupCount ) )
612 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800613
614 return
615
616 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700617 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
618 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800619 '''
You Wangba231e72018-03-01 13:18:21 -0800620 Verify connectivity between hosts according to the ping chart
621 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800622 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800623 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800624 '''
You Wangba231e72018-03-01 13:18:21 -0800625 main.log.report( "Check host connectivity" )
626 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800627 if tag == "":
628 tag = 'CASE%d' % main.CurrentTestCaseNumber
629 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800630 main.log.debug( "Entry in ping chart: %s" % entry )
631 expect = entry[ 'expect' ]
632 if expect == "Unidirectional":
633 # Verify ping from each src host to each dst host
634 src = entry[ 'src' ]
635 dst = entry[ 'dst' ]
636 expect = main.TRUE
637 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
638 if basedOnIp:
639 if ("v4" in src[0]):
640 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
641 utilities.assert_equals( expect=expect, actual=pa,
642 onpass="IPv4 connectivity successfully tested",
643 onfail="IPv4 connectivity failed" )
644 if ("v6" in src[0]):
645 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
646 utilities.assert_equals( expect=expect, actual=pa,
647 onpass="IPv6 connectivity successfully tested",
648 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700649 elif main.physicalNet:
650 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
651 utilities.assert_equals( expect=expect, actual=pa,
652 onpass="IP connectivity successfully tested",
653 onfail="IP connectivity failed" )
654
You Wangba231e72018-03-01 13:18:21 -0800655 else:
656 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
657 utilities.assert_equals( expect=expect, actual=pa,
658 onpass="IP connectivity successfully tested",
659 onfail="IP connectivity failed" )
660 else:
661 # Verify ping between each host pair
662 hosts = entry[ 'hosts' ]
663 try:
664 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
665 except:
666 expect = main.FALSE
667 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
668 if basedOnIp:
669 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800670 pa = utilities.retry( main.Network.pingallHosts,
671 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700672 args=(hosts, ),
673 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800674 attempts=retryAttempts,
675 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800676 utilities.assert_equals( expect=expect, actual=pa,
677 onpass="IPv4 connectivity successfully tested",
678 onfail="IPv4 connectivity failed" )
679 if ("v6" in hosts[0]):
680 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
681 utilities.assert_equals( expect=expect, actual=pa,
682 onpass="IPv6 connectivity successfully tested",
683 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700684 elif main.physicalNet:
685 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=True )
686 utilities.assert_equals( expect=expect, actual=pa,
687 onpass="IP connectivity successfully tested",
688 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800689 else:
You Wangf19d9f42018-02-23 16:34:19 -0800690 pa = main.Network.pingallHosts( hosts )
691 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800692 onpass="IP connectivity successfully tested",
693 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700694 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700695 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700696 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700697 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700698 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800699
700 if dumpflows:
701 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
702 "flows",
703 main.logdir,
704 tag + "_FlowsOn" )
705 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
706 "groups",
707 main.logdir,
708 tag + "_GroupsOn" )
709
710 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700711 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700712 """
713 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
714 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
715 Kill a link and verify ONOS can see the proper link change
716 """
Jon Halla604fd42018-05-04 14:27:27 -0700717 if sleep is None:
718 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
719 else:
720 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700721 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700722 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
723 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700724 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
725 onpass="Link down successful",
726 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700727 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700728 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700729 "Waiting %s seconds for link down to be discovered" % sleep )
730 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700731 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700732 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700733 main.FALSE,
734 kwargs={ 'numoswitch': switches,
735 'numolink': links },
736 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700737 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700738 utilities.assert_equals( expect=main.TRUE, actual=topology,
739 onpass="Topology after link down is correct",
740 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700741
742 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700743 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800744 """
745 links = list of links (src, dst) to bring down.
746 """
747
748 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700749 if sleep is None:
750 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
751 else:
752 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800753
754 for end1, end2 in links:
755 main.Network.link( END1=end1, END2=end2, OPTION="down")
756 main.Network.link( END1=end2, END2=end1, OPTION="down")
757
Jon Halla604fd42018-05-04 14:27:27 -0700758 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800759 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700760 "Waiting %s seconds for links down to be discovered" % sleep )
761 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800762
763 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
764 main.FALSE,
765 kwargs={ 'numoswitch': switches,
766 'numolink': linksAfter },
767 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700768 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800769
You Wang2854bce2018-03-30 10:15:32 -0700770 utilities.assert_equals( expect=main.TRUE, actual=topology,
771 onpass="Link batch down successful",
772 onfail="Link batch down failed" )
773
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800774 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700775 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800776 """
777 links = list of link (src, dst) to bring up again.
778 """
779
780 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700781 if sleep is None:
782 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
783 else:
784 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800785
786 for end1, end2 in links:
787 main.Network.link( END1=end1, END2=end2, OPTION="up")
788 main.Network.link( END1=end2, END2=end1, OPTION="up")
789
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800790 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700791 "Waiting %s seconds for links up to be discovered" % sleep )
792 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800793
794 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
795 main.FALSE,
796 kwargs={ 'numoswitch': switches,
797 'numolink': linksAfter },
798 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700799 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800800
You Wang2854bce2018-03-30 10:15:32 -0700801 utilities.assert_equals( expect=main.TRUE, actual=topology,
802 onpass="Link batch up successful",
803 onfail="Link batch up failed" )
804
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800805 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700806 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
807 """
808 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
809 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
810 switches, links: number of expected switches and links after link change, ex.: '4', '6'
811 """
812 if sleep is None:
813 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
814 else:
815 sleep = float( sleep )
816 main.step( "Disable a batch of ports" )
817 for dpid, port in ports:
818 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
819 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
820 time.sleep( sleep )
821 if switches and links:
822 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
823 numolink=links )
824 utilities.assert_equals( expect=main.TRUE, actual=result,
825 onpass="Port down successful",
826 onfail="Port down failed" )
827
828 @staticmethod
829 def enablePortBatch( main, ports, switches, links, sleep=None ):
830 """
831 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
832 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
833 switches, links: number of expected switches and links after link change, ex.: '4', '6'
834 """
835 if sleep is None:
836 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
837 else:
838 sleep = float( sleep )
839 main.step( "Enable a batch of ports" )
840 for dpid, port in ports:
841 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
842 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
843 time.sleep( sleep )
844 if switches and links:
845 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
846 numolink=links )
847 utilities.assert_equals( expect=main.TRUE, actual=result,
848 onpass="Port up successful",
849 onfail="Port up failed" )
850
851 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700852 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700853 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700854 """
855 Params:
856 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700857 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700858 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
859 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
860 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
861 Kill a link and verify ONOS can see the proper link change
862 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700863 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700864 if sleep is None:
865 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
866 else:
867 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700868 result = False
869 count = 0
870 while True:
871 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700872 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800873 main.Network.link( END1=end1, END2=end2, OPTION="up" )
874 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700875 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700876 "Waiting %s seconds for link up to be discovered" % sleep )
877 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700878
You Wangc02d8352018-04-17 16:42:10 -0700879 if portUp:
880 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
881 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700882 main.log.info(
883 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700884 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700885
Jon Halla604fd42018-05-04 14:27:27 -0700886 result = ctrl.CLI.checkStatus( numoswitch=switches,
887 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700888 if count > 5 or result:
889 break
890 utilities.assert_equals( expect=main.TRUE, actual=result,
891 onpass="Link up successful",
892 onfail="Failed to bring link up" )
893
894 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700895 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700896 """
897 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
898 Completely kill a switch and verify ONOS can see the proper change
899 """
Jon Halla604fd42018-05-04 14:27:27 -0700900 if sleep is None:
901 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
902 else:
903 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700904 switch = switch if isinstance( switch, list ) else [ switch ]
905 main.step( "Kill " + str( switch ) )
906 for s in switch:
907 main.log.info( "Stopping " + s )
908 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700909 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700910
911 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700912 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700913 sleep ) )
914 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700915 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700916 main.FALSE,
917 kwargs={ 'numoswitch': switches,
918 'numolink': links },
919 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700920 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700921 utilities.assert_equals( expect=main.TRUE, actual=topology,
922 onpass="Kill switch successful",
923 onfail="Failed to kill switch?" )
924
925 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700926 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700927 """
928 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
929 Recover a switch and verify ONOS can see the proper change
930 """
Jon Halla604fd42018-05-04 14:27:27 -0700931 if sleep is None:
932 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
933 else:
934 sleep = float( sleep )
935 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700936 switch = switch if isinstance( switch, list ) else [ switch ]
937 main.step( "Recovering " + str( switch ) )
938 for s in switch:
939 main.log.info( "Starting " + s )
940 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700941 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700942 sleep ) )
943 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700944 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700945 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700946 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700947 sleep ) )
948 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700949
Devin Lim142b5342017-07-20 15:22:39 -0700950 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700951 main.FALSE,
952 kwargs={ 'numoswitch': switches,
953 'numolink': links },
954 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700955 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700956 utilities.assert_equals( expect=main.TRUE, actual=topology,
957 onpass="Switch recovery successful",
958 onfail="Failed to recover switch?" )
959
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700960 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700961 def killRouter( main, router, sleep=None ):
962 """
963 Kill bgpd process on a quagga router
964 router: name of the router to be killed. E.g. "bgp1"
965 """
966 sleep = float( sleep )
967 main.step( "Kill " + str( router ) )
968 if hasattr( main, 'Mininet1' ):
969 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
970 main.Mininet1.handle.expect( "mininet>" )
971 else:
972 # TODO: support killing router in physical network
973 pass
974 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
975 time.sleep( sleep )
976
977 @staticmethod
978 def recoverRouter( main, router, sleep=None ):
979 """
980 Restart bgpd process on a quagga router
981 router: name of the router to be recovered. E.g. "bgp1"
982 """
983 sleep = float( sleep )
984 main.step( "Recovering " + str( router ) )
985 if hasattr( main, 'Mininet1' ):
986 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
987 main.Mininet1.handle.expect( "mininet>" )
988 else:
989 # TODO: support recovering router in physical network
990 pass
991 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
992 time.sleep( sleep )
993
994 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -0700995 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700996 """
997 Stop Onos-cluster.
998 Stops Mininet
999 Copies ONOS log
1000 """
You Wang4cc61912018-08-28 10:10:58 -07001001 from tests.dependencies.utils import Utils
1002 main.utils = Utils()
Jon Halldac3eae2020-06-05 12:04:06 -07001003 for ctrl in main.Cluster.active():
1004 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001005 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001006 if hasattr( main, "scapyHosts" ):
1007 scapyResult = main.TRUE
1008 for host in main.scapyHosts:
1009 scapyResult = host.stopScapy() and scapyResult
1010 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1011 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001012 if hasattr( main, 'Mininet1' ):
1013 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1014 else:
1015 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001016 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1017 main.scapyHosts = []
1018
You Wang5da39c82018-04-26 22:55:08 -07001019 if removeHostComponent:
1020 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1021 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001022 if hasattr( main, 'Mininet1' ):
1023 pass
1024 else:
1025 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001026 main.Network.removeHostComponent( host )
1027
You Wang5df1c6d2018-04-06 18:02:02 -07001028 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001029 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001030 else:
1031 main.Network.disconnectInbandHosts()
1032 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001033
You Wang5df1c6d2018-04-06 18:02:02 -07001034 if copyKarafLog:
1035 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001036
Devin Lim142b5342017-07-20 15:22:39 -07001037 for ctrl in main.Cluster.active():
1038 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001039 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001040
1041 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001042 def verifyNodes( main ):
1043 """
1044 Verifies Each active node in the cluster has an accurate view of other node's and their status
1045
1046 Params:
1047 nodes, integer array with position of the ONOS nodes in the CLIs array
1048 """
1049 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1050 False,
1051 attempts=10,
1052 sleep=10 )
1053 utilities.assert_equals( expect=True, actual=nodeResults,
1054 onpass="Nodes check successful",
1055 onfail="Nodes check NOT successful" )
1056
1057 if not nodeResults:
1058 for ctrl in main.Cluster.runningNodes:
1059 main.log.debug( "{} components not ACTIVE: \n{}".format(
1060 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001061 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001062 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001063 main.cleanAndExit()
1064
1065 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001066 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001067 """
1068 Verifies that the ONOS cluster has an acuurate view of the topology
1069
1070 Params:
1071 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
Jon Hall39570262020-11-17 12:18:19 -08001072 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001073 """
1074 main.step( "Check number of topology elements" )
1075 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1076 main.FALSE,
1077 kwargs={ 'numoswitch': switches,
1078 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001079 'numoctrl': expNodes,
1080 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001081 attempts=10,
1082 sleep=12 )
1083 utilities.assert_equals( expect=main.TRUE, actual=topology,
1084 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001085 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001086
1087 @staticmethod
1088 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001089 """
1090 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1091 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1092 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1093 """
Jon Halla604fd42018-05-04 14:27:27 -07001094 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001095 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001096 if sleep is None:
1097 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1098 else:
1099 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001100
Jon Hall214f88b2020-09-21 10:21:42 -07001101 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001102 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001103 node = main.Cluster.runningNodes[ i ]
1104 if node.inDocker:
1105 killResult = node.server.dockerStop( node.name )
1106 else:
1107 killResult = main.ONOSbench.onosDie( node.ipAddress )
1108 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001109 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001110 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1111 onpass="ONOS instance Killed",
1112 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001113 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001114 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001115 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001116
Devin Lim142b5342017-07-20 15:22:39 -07001117 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001118 Testcaselib.verifyNodes( main )
1119 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001120
1121 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001122 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001123 """
1124 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1125 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1126 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1127 """
Jon Hall3c910162018-03-07 14:42:16 -08001128 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001129 if sleep is None:
1130 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1131 else:
1132 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001133 for i in nodes:
1134 node = main.Cluster.runningNodes[ i ]
1135 if node.inDocker:
1136 main.Cluster.startONOSDockerNode( i )
1137 else:
1138 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001139 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001140 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001141 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001142 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001143 if node.inDocker:
1144 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1145 isUp = isUp and node.CLI.prepareForCLI()
1146 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1147 else:
1148 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001149 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1150 onpass="ONOS service is ready",
1151 onfail="ONOS service did not start properly" )
1152 for i in nodes:
1153 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001154 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001155 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001156 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1157 commandlineTimeout=60,
1158 onosStartTimeout=100 )
1159 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001160 utilities.assert_equals( expect=main.TRUE,
1161 actual=cliResult,
1162 onpass="ONOS CLI is ready",
1163 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001164
Jon Halla604fd42018-05-04 14:27:27 -07001165 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001166 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001167 Testcaselib.verifyNodes( main )
1168 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001169
Devin Lim142b5342017-07-20 15:22:39 -07001170 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001171 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001172 attempts=10,
1173 sleep=12 )
1174 if ready:
1175 ready = main.TRUE
1176 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001177 onpass="ONOS summary command succeded",
1178 onfail="ONOS summary command failed" )
1179 if not ready:
1180 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001181 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001182
1183 @staticmethod
1184 def addHostCfg( main ):
1185 """
1186 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001187 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001188 """
1189 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001190 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001191 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001192 hostCfg = json.load( template )
1193 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1194 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001195 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001196 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1197 subjectClass="hosts",
1198 subjectKey=urllib.quote( mac,
1199 safe='' ),
1200 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001201 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1202 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001203 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001204 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1205 subjectClass="hosts",
1206 subjectKey=urllib.quote( mac,
1207 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001208 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001209 main.pingChart.update( { 'vlan1': { "expect": "True",
1210 "hosts": [ "olt1", "vsg1" ] } } )
1211 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1212 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001213 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1214 vlanId=1,
1215 port1=5,
1216 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001217
1218 @staticmethod
1219 def delHostCfg( main ):
1220 """
1221 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001222 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001223 """
1224 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001225 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001226 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001227 hostCfg = json.load( template )
1228 main.step( "Removing host configuration" )
1229 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001230 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001231 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1232 subjectKey=urllib.quote(
1233 mac,
1234 safe='' ),
1235 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001236 main.step( "Removing configuration" )
1237 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001238 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001239 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1240 subjectKey=urllib.quote(
1241 mac,
1242 safe='' ),
1243 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001244 main.step( "Removing vlan configuration" )
1245 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001246 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1247 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001248
1249 @staticmethod
1250 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1251 """
1252 Verifies IP address assignment from the hosts
1253 """
1254 main.step( "Verify IP address assignment from hosts" )
1255 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001256 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001257 # Find out names of disconnected hosts
1258 disconnectedHosts = []
1259 if hasattr( main, "disconnectedIpv4Hosts" ):
1260 for host in main.disconnectedIpv4Hosts:
1261 disconnectedHosts.append( host )
1262 if hasattr( main, "disconnectedIpv6Hosts" ):
1263 for host in main.disconnectedIpv6Hosts:
1264 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001265 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001266 # Exclude disconnected hosts
1267 if hostName in disconnectedHosts:
1268 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1269 continue
You Wang53dba1e2018-02-02 17:45:44 -08001270 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1271 main.FALSE,
1272 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001273 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001274 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001275 attempts=attempts,
1276 sleep=sleep )
1277 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1278 onpass="Verify network host IP succeded",
1279 onfail="Verify network host IP failed" )
1280
1281 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001282 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001283 """
1284 Verifies host IP address assignment from ONOS
1285 """
1286 main.step( "Verify host IP address assignment in ONOS" )
1287 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001288 # Find out IPs of disconnected hosts
1289 disconnectedIps = []
1290 if hasattr( main, "disconnectedIpv4Hosts" ):
1291 for host in main.disconnectedIpv4Hosts:
1292 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1293 if hasattr( main, "disconnectedIpv6Hosts" ):
1294 for host in main.disconnectedIpv6Hosts:
1295 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001296 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001297 # Exclude disconnected hosts
1298 if ip in disconnectedIps:
1299 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1300 continue
You Wang53dba1e2018-02-02 17:45:44 -08001301 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1302 main.FALSE,
1303 kwargs={ 'hostList': [ hostName ],
1304 'prefix': ip },
1305 attempts=attempts,
1306 sleep=sleep )
1307 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1308 onpass="Verify ONOS host IP succeded",
1309 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001310 if not ipResult and skipOnFail:
1311 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001312 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001313 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001314
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001315 @staticmethod
1316 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1317 """
1318 Description:
1319 Updates interface configuration in ONOS, with given IP and vlan parameters
1320 Required:
1321 * connectPoint: connect point to update configuration
1322 Optional:
1323 * ips: list of IP addresses, combined with '/xx' subnet representation,
1324 corresponding to 'ips' field in the configuration
1325 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1326 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1327 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1328 """
1329 cfg = dict()
1330 cfg[ "ports" ] = dict()
1331 cfg[ "ports" ][ connectPoint ] = dict()
1332 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1333 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1334 if untagged > 0:
1335 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1336 else:
1337 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1338 if native > 0:
1339 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1340
1341 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001342
1343 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001344 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001345 """
1346 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001347 scapyNames: list of names that will be used as component names for scapy hosts
1348 mininetNames: used when scapy host names are different from the host names
1349 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1350 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001351 """
1352 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001353 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1354 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001355 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001356 if hasattr( main, 'Mininet1' ):
1357 main.Scapy.createHostComponent( scapyName )
1358 scapyHandle = getattr( main, scapyName )
1359 if mininetNames:
1360 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1361 else:
1362 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001363 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1364 scapyHandle.mExecDir = "/tmp"
1365 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1366 main.log.debug( "start mn host component in docker" )
1367 scapyHandle.startHostCli( mininetName,
1368 execDir="/tmp",
1369 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1370 else:
1371 main.log.debug( "start mn host component" )
1372 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001373 else:
You Wang0fc21702018-11-02 17:49:18 -07001374 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001375 scapyHandle = getattr( main, scapyName )
1376 scapyHandle.connectInband()
1377 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001378 scapyHandle.startScapy()
1379 scapyHandle.updateSelf()
1380 main.log.debug( scapyHandle.name )
1381 main.log.debug( scapyHandle.hostIp )
1382 main.log.debug( scapyHandle.hostMac )
1383
1384 @staticmethod
1385 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1386 """
1387 Verify unicast traffic by pinging from source hosts to the destination IP
1388 and capturing the packets at the destination host using Scapy.
1389 srcHosts: List of host names to send the ping packets
1390 dstIp: destination IP of the ping packets
1391 dstHost: host that runs Scapy to capture the packets
1392 dstIntf: name of the interface on the destination host
1393 expect: use True if the ping is expected to be captured at destination;
1394 Otherwise False
1395 skipOnFail: skip the rest of this test case if result is not expected
1396 maxRetry: number of retries allowed
1397 """
1398 from tests.dependencies.topology import Topology
1399 try:
1400 main.topo
1401 except ( NameError, AttributeError ):
1402 main.topo = Topology()
1403 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1404 result = main.TRUE
1405 for srcHost in srcHosts:
1406 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1407 expect, maxRetry, True )
1408 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001409 result = main.FALSE
1410 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1411 utilities.assert_equals( expect=main.TRUE,
1412 actual=result,
1413 onpass="Verify traffic to {}: Pass".format( dstIp ),
1414 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1415 if skipOnFail and result != main.TRUE:
1416 Testcaselib.saveOnosDiagnostics( main )
1417 Testcaselib.cleanup( main, copyKarafLog=False )
1418 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001419
1420 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001421 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001422 """
1423 Verify multicast traffic using scapy
1424 """
You Wangc564c6f2018-05-01 15:24:57 -07001425 from tests.dependencies.topology import Topology
1426 try:
1427 main.topo
1428 except ( NameError, AttributeError ):
1429 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001430 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001431 routeData = main.multicastConfig[ routeName ]
1432 srcs = main.mcastRoutes[ routeName ][ "src" ]
1433 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1434 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1435 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001436 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001437 for src in srcs:
1438 srcEntry = routeData[ "src" ][ src ]
1439 for dst in dsts:
1440 dstEntry = routeData[ "dst" ][ dst ]
1441 sender = getattr( main, srcEntry[ "host" ] )
1442 receiver = getattr( main, dstEntry[ "host" ] )
1443 main.Network.addRoute( str( srcEntry[ "host" ] ),
1444 str( routeData[ "group" ] ),
1445 str( srcEntry[ "interface" ] ),
1446 True if routeData[ "ipVersion" ] == 6 else False )
1447 # Build the packet
1448 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1449 if routeData[ "ipVersion" ] == 4:
1450 sender.buildIP( dst=str( routeData[ "group" ] ) )
1451 elif routeData[ "ipVersion" ] == 6:
1452 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1453 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1454 sIface = srcEntry[ "interface" ]
1455 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1456 pktFilter = srcEntry[ "filter" ]
1457 pkt = srcEntry[ "packet" ]
1458 # Send packet and check received packet
1459 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001460 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001461 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001462 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1463 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001464 if not trafficResult:
1465 result = main.FALSE
1466 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1467 dstEntry[ "host" ] ) )
1468 utilities.assert_equals( expect=main.TRUE,
1469 actual=result,
1470 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1471 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001472 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001473 Testcaselib.saveOnosDiagnostics( main )
1474 Testcaselib.cleanup( main, copyKarafLog=False )
1475 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001476
1477 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001478 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001479 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1480 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001481 """
1482 Verify reachability from each host in srcList to each host in dstList
1483 """
1484 from tests.dependencies.topology import Topology
1485 try:
1486 main.topo
1487 except ( NameError, AttributeError ):
1488 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001489 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001490 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001491 utilities.assert_equals( expect=main.TRUE,
1492 actual=pingResult,
1493 onpass="{}: Pass".format( stepMsg ),
1494 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001495 if not pingResult and skipOnFail:
1496 Testcaselib.saveOnosDiagnostics( main )
1497 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1498 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001499
1500 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001501 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001502 """
1503 Verify if the specified host is discovered by ONOS on the given locations
1504 Required:
You Wang85747762018-05-11 15:51:50 -07001505 locationDict: a dictionary that maps host names to expected locations.
1506 locations could be a string or a list.
1507 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001508 Returns:
1509 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1510 """
You Wang85747762018-05-11 15:51:50 -07001511 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1512 result = main.TRUE
1513 for hostName, locations in locationDict.items():
1514 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1515 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1516 if not hostIp:
1517 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1518 if not hostIp:
1519 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1520 result = main.FALSE
1521 continue
1522 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1523 main.FALSE,
1524 args=( hostIp, locations ),
1525 attempts=retry + 1,
1526 sleep=10 )
1527 if not locationResult:
1528 result = main.FALSE
1529 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001530 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001531 onpass="Location verification passed",
1532 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001533
1534 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001535 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001536 """
1537 Move specified host from srcSw to dstSw.
1538 If srcSw and dstSw are same, the host will be moved from current port to
1539 next available port.
1540 Required:
1541 hostName: name of the host. e.g., "h1"
1542 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1543 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1544 gw: ip address of the gateway of the new location
1545 Optional:
1546 macAddr: if specified, change MAC address of the host to the specified MAC address.
1547 prefixLen: prefix length
1548 cfg: port configuration as JSON string
1549 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001550 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001551 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001552 if not hasattr( main, 'Mininet1' ):
1553 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1554 return
1555
You Wang6e5b48e2018-07-23 16:17:38 -07001556 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1557 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1558 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001559 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001560 if cfg:
1561 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1562 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001563 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001564 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001565 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001566
1567 main.Mininet1.discoverHosts( [ hostName, ] )
1568
1569 # Update expectedHost when MAC address is changed.
1570 if macAddr is not None:
1571 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1572 if ipAddr is not None:
1573 for hostName, ip in main.expectedHosts[ "onos" ].items():
1574 if ip == ipAddr:
1575 vlan = hostName.split( "/" )[ -1 ]
1576 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001577 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001578 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001579
1580 @staticmethod
1581 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001582 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001583 """
1584 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1585 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1586 to next available port.
1587 Required:
1588 hostName: name of the host. e.g., "h1"
1589 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1590 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1591 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1592 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1593 gw: ip address of the gateway of the new location
1594 Optional:
1595 macAddr: if specified, change MAC address of the host to the specified MAC address.
1596 prefixLen: prefix length
1597 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001598 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001599 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001600 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001601 if not hasattr( main, 'Mininet1' ):
1602 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1603 return
1604
You Wang6e5b48e2018-07-23 16:17:38 -07001605 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1606 srcSw, srcPairSw, dstSw, dstPairSw ) )
1607 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1608 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1609 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001610 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001611 if cfg:
1612 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1613 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001614 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001615 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001616 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001617
1618 main.Mininet1.discoverHosts( [ hostName, ] )
1619
1620 # Update expectedHost when MAC address is changed.
1621 if macAddr is not None:
1622 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1623 if ipAddr is not None:
1624 for hostName, ip in main.expectedHosts[ "onos" ].items():
1625 if ip == ipAddr:
1626 vlan = hostName.split( "/" )[ -1 ]
1627 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001628 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001629
1630 @staticmethod
1631 def mnDockerSetup( main ):
1632 """
1633 Optionally start and setup docker image for mininet
1634 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001635 try:
1636 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001637
Jon Hall9b0de1f2020-08-24 15:38:04 -07001638 main.log.info( "Creating Mininet Docker" )
1639 handle = main.Mininet1.handle
1640 # build docker image
1641 dockerFilePath = "%s/../dependencies/" % main.testDir
1642 dockerName = "trellis_mininet"
1643 # Stop any leftover container
1644 main.Mininet1.dockerStop( dockerName )
1645 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001646 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001647
Jon Hall9b0de1f2020-08-24 15:38:04 -07001648 confDir = "/tmp/mn_conf/"
1649 # Try to ensure the destination exists
1650 main.log.info( "Create folder for network config files" )
1651 handle.sendline( "rm -rf %s" % confDir )
1652 handle.expect( main.Mininet1.Prompt() )
1653 main.log.debug( handle.before + handle.after )
1654 handle.sendline( "mkdir -p %s" % confDir )
1655 handle.expect( main.Mininet1.Prompt() )
1656 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001657 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1658 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001659 # Make sure permissions are correct
1660 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1661 handle.expect( main.Mininet1.Prompt() )
1662 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1663 handle.expect( main.Mininet1.Prompt() )
1664 main.log.debug( handle.before + handle.after )
1665 # Start docker container
1666 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1667 dockerName,
1668 main.params[ 'MN_DOCKER' ][ 'args' ] )
1669 if runResponse == main.FALSE:
1670 main.log.error( "Docker container already running, aborting test" )
1671 main.cleanup()
1672 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001673
Jon Hall9b0de1f2020-08-24 15:38:04 -07001674 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1675 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001676
Jon Hall9b0de1f2020-08-24 15:38:04 -07001677 # Fow when we create component handles
1678 main.Mininet1.mExecDir = "/tmp"
1679 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1680 main.Mininet1.hostPrompt = "/home/root#"
1681
1682 # For some reason docker isn't doing this
1683 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1684 main.Mininet1.handle.expect( "etc/hosts" )
1685 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1686 except Exception as e:
1687 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001688 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001689
1690 @staticmethod
1691 def mnDockerTeardown( main ):
1692 """
1693 Optionally stop and cleanup docker image for mininet
1694 """
1695
1696 if hasattr( main, 'Mininet1' ):
1697 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001698 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001699
1700 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001701 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001702 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001703 main.Mininet1.sudoRequired = True
1704 except Exception as e:
1705 main.log.error( e )
1706
Jon Hall39570262020-11-17 12:18:19 -08001707 # Save docker logs
1708 copyResult = main.ONOSbench.scp( main.Mininet1,
1709 "/tmp/mn-stratum/*",
1710 main.logdir,
1711 direction="from",
1712 options="-rp" )
1713
1714
Jon Hall43060f62020-06-23 13:13:33 -07001715 @staticmethod
1716 def setOnosConfig( main ):
1717 """
1718 Read and Set onos configurations from the params file
1719 """
1720 main.step( "Set ONOS configurations" )
1721 config = main.params.get( 'ONOS_Configuration' )
1722 if config:
1723 main.log.debug( config )
1724 checkResult = main.TRUE
1725 for component in config:
1726 for setting in config[ component ]:
1727 value = config[ component ][ setting ]
1728 check = main.Cluster.next().setCfg( component, setting, value )
1729 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1730 checkResult = check and checkResult
1731 utilities.assert_equals( expect=main.TRUE,
1732 actual=checkResult,
1733 onpass="Successfully set config",
1734 onfail="Failed to set config" )
1735 else:
1736 main.log.warn( "No configurations were specified to be changed after startup" )
1737
1738 @staticmethod
1739 def setOnosLogLevels( main ):
1740 """
1741 Read and Set onos log levels from the params file
1742 """
1743 main.step( 'Set logging levels' )
1744 logging = True
1745 try:
1746 logs = main.params.get( 'ONOS_Logging', False )
1747 if logs:
1748 for namespace, level in logs.items():
1749 for ctrl in main.Cluster.active():
1750 ctrl.CLI.logSet( level, namespace )
1751 except AttributeError:
1752 logging = False
1753 utilities.assert_equals( expect=True, actual=logging,
1754 onpass="Set log levels",
1755 onfail="Failed to set log levels" )