blob: c8d83ef886d70d9255d4d5b4f1570f86a8199cfa [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
Jon Hall627b1572020-12-01 12:01:15 -080052 main.persistentSetup = main.params.get( "persistent_setup" )
You Wangd5873482018-01-24 12:30:00 -080053 main.Network = Network()
Jon Hall43060f62020-06-23 13:13:33 -070054 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080055 main.testSetUp.envSetupDescription( False )
Jon Hall39570262020-11-17 12:18:19 -080056 main.logdirBase = main.logdir
Devin Lim58046fa2017-07-05 16:55:00 -070057 stepResult = main.FALSE
58 try:
Devin Lim58046fa2017-07-05 16:55:00 -070059 # Test variables
60 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
61 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070062 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080063 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
64 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
65 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080066 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
67 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
68 else:
69 main.useBmv2 = False
Jon Hall43060f62020-06-23 13:13:33 -070070 if main.useBmv2:
71 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
72 else:
73 main.switchType = "ovs"
74
Devin Lim57221b02018-02-14 15:45:36 -080075 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070076 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080077 main.forJson = "json/"
78 main.forChart = "chart/"
79 main.forConfig = "conf/"
80 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080081 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080082 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070083 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070084 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080085 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
86 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080087 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070088 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070089 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070090 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070091 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070092 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070093
Devin Lim0c972b72018-02-08 14:53:59 -080094 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070095 except Exception as e:
96 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070097
Jon Hallaa1d9b82020-07-30 13:49:42 -070098 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall1efcb3f2016-08-23 13:42:15 -070099
Jon Hall1efcb3f2016-08-23 13:42:15 -0700100 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800101 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
102 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700103 """
104 - Set up cell
105 - Create cell file
106 - Set cell file
107 - Verify cell file
108 - Kill ONOS process
109 - Uninstall ONOS cluster
110 - Verify ONOS start up
111 - Install ONOS cluster
112 - Connect to cli
113 """
Siddesh13492972021-03-12 21:09:32 +0000114 # Check params file for local repos on external apps. cd to repos, run the build command, potentially move o/p file to a different location
115
Jon Hall1efcb3f2016-08-23 13:42:15 -0700116 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700117 try:
Jon Hall627b1572020-12-01 12:01:15 -0800118 if not main.persistentSetup and main.params.get( 'EXTERNAL_APPS' ):
Jon Hall43060f62020-06-23 13:13:33 -0700119 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800120 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700121 main.ONOSbench.onosFetchApp( url )
122 if not main.apps:
123 main.log.error( "App list is empty" )
124 except Exception as e:
125 main.log.debug( e )
126 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800127 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
128 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700129 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800130 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800131 skipPack=skipPackage,
132 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800133 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700134 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700135 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800136 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700137 attempts=10 )
138 if ready:
139 ready = main.TRUE
140 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700141 onpass="ONOS summary command succeded",
142 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700143 if not ready:
144 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700145 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700146
You Wang5bf49592020-07-08 18:47:46 -0700147 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700148 appInstallResult = main.TRUE
149 if main.trellisOar:
150 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700151 if main.t3Oar:
152 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
153 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
154 onpass="SR app installation succeded",
155 onfail="SR app installation failed" )
156 if not appInstallResult:
157 main.cleanAndExit()
158
Jon Hall43060f62020-06-23 13:13:33 -0700159 # FIXME: move to somewhere else?
160 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
161 # TODO: Support other pipeconfs/making this configurable
162 if switchPrefix == "tofino":
163 # It seems to take some time for the pipeconfs to be loaded
164 ctrl = main.Cluster.next()
165 for i in range( 120 ):
166 try:
167 main.log.debug( "Checking to see if pipeconfs are loaded" )
168 output = ctrl.CLI.sendline( "pipeconfs" )
169 if "tofino" in output:
170 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
171 break
172 time.sleep( 1 )
173 except Exception as e:
174 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700175
Jon Hall627b1572020-12-01 12:01:15 -0800176 # Install segmentrouting and t3 app
177 appInstallResult = main.TRUE
178 if not main.persistentSetup:
179 if main.trellisOar:
180 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
181 if main.t3Oar:
182 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
183 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
184 onpass="SR app installation succeded",
185 onfail="SR app installation failed" )
186 if not appInstallResult:
187 main.cleanAndExit()
188
Jon Hall43060f62020-06-23 13:13:33 -0700189 Testcaselib.setOnosLogLevels( main )
190 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700191
Jon Hall1efcb3f2016-08-23 13:42:15 -0700192 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800193 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700194 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
195 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800196
197 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700198 def loadJson( main, suffix='' ):
199 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
200 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800201 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
202
203 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700204 def loadXconnects( main, suffix='' ):
205 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
206 main.cfgName, suffix ) ) as cfg:
207 for xconnect in json.load( cfg ).get('xconnects'):
208 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
209
210 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800211 def loadChart( main ):
212 try:
213 with open( "%s%s.chart" % ( main.configPath + main.forChart,
214 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700215 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800216 except IOError:
217 main.log.warn( "No chart file found." )
218
219 @staticmethod
220 def loadHost( main ):
221 with open( "%s%s.host" % ( main.configPath + main.forHost,
222 main.cfgName ) ) as host:
223 main.expectedHosts = json.load( host )
224
225 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800226 def loadSwitchFailureChart( main ):
227 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
228 main.cfgName ) ) as sfc:
229 main.switchFailureChart = json.load( sfc )
230
231 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800232 def loadLinkFailureChart( main ):
233 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700234 main.cfgName ) ) as lfc:
235 main.linkFailureChart = json.load( lfc )
236
237 @staticmethod
238 def loadMulticastConfig( main ):
239 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
240 main.cfgName ) ) as cfg:
241 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800242
243 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700244 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700245 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800246 copyResult = main.ONOSbench.scp( main.Mininet1,
247 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700248 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800249 direction="to" )
250 if main.topologyLib:
251 for lib in main.topologyLib.split(","):
252 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
253 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700254 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800255 direction="to" )
256 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700257 import re
258 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
259 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700260 destDir = "~/"
261 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
262 destDir = "/tmp/mn_conf/"
263 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800264 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700265 # Update zebra configurations with correct ONOS instance IP
266 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
267 ip = controllerIPs[ index ]
268 index = ( index + 1 ) % len( controllerIPs )
269 with open( main.configPath + main.forConfig + conf ) as f:
270 s = f.read()
271 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
272 with open( main.configPath + main.forConfig + conf, "w" ) as f:
273 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800274 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800275 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700276 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800277 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800278 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700279 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800280 main.Mininet1.home + "custom",
281 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700282
283 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
284 # move the config files into home
285 main.Mininet1.handle.sendline( "cp config/* . " )
286 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
287 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
288 main.Mininet1.handle.sendline( "ls -al " )
289 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
290 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
291
You Wangd87b2312018-01-30 12:47:17 -0800292 stepResult = copyResult
293 utilities.assert_equals( expect=main.TRUE,
294 actual=stepResult,
295 onpass="Successfully copied topo files",
296 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700297 if main.stratumRoot:
298 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700299 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700300 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700301 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700302 main.topology = topology
303 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700304 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700305 stepResult = topoResult
306 utilities.assert_equals( expect=main.TRUE,
307 actual=stepResult,
308 onpass="Successfully loaded topology",
309 onfail="Failed to load topology" )
310 # Exit if topology did not load properly
311 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700312 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700313 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700314 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700315 # Upload the net-cfg file created for each switch
316 filename = "onos-netcfg.json"
317 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700318 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700319 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
320 path = "/tmp/mn-stratum/%s/" % switch
321 dstPath = "/tmp/"
322 dstFileName = "%s-onos-netcfg.json" % switch
323 main.ONOSbench1.scp( main.Mininet1,
324 "%s%s" % ( path, filename ),
325 "%s%s" % ( dstPath, dstFileName ),
326 "from" )
327 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 -0700328 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700329 # Configure managementAddress
330 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
331 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
332 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
333 # Configure device id
334 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
335 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
336 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
337 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800338 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 -0700339 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
340 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700341 node = main.Cluster.active(0)
342 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
343 dstPath,
344 dstFileName,
345 user=node.REST.user_name,
346 password=node.REST.pwd )
347 # Stop test if we fail to push switch netcfg
348 utilities.assert_equals( expect=main.TRUE,
349 actual=switchNetCfg,
350 onpass="Successfully pushed switch netcfg",
351 onfail="Failed to configure switches in onos" )
352 if not switchNetCfg:
353 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700354 # Make sure hosts make some noise
355 Testcaselib.discoverHosts( main )
356
357 @staticmethod
358 def discoverHosts( main ):
359 # TODO add option to only select specific hosts
360 if hasattr( main, "Mininet1" ):
361 network = main.Mininet1
362 elif hasattr( main, "NetworkBench" ):
363 network = main.NetworkBench
364 else:
365 main.log.warn( "Could not find component for test network, skipping host discovery" )
366 return
367 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700368
369 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800370 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800371 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700372 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800373 topoResult = main.NetworkBench.connectToNet()
374 stepResult = topoResult
375 utilities.assert_equals( expect=main.TRUE,
376 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700377 onpass="Successfully connected to topology",
378 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800379 # Exit if topology did not load properly
380 if not topoResult:
381 main.cleanAndExit()
382
Jon Hall627b1572020-12-01 12:01:15 -0800383 if not main.persistentSetup:
384 # Perform any optional setup
385 for switch in main.NetworkBench.switches:
386 if hasattr( switch, "setup" ):
387 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700388
Jon Hall627b1572020-12-01 12:01:15 -0800389 main.step( "Assign switches to controllers." )
390 stepResult = main.TRUE
391 switches = main.NetworkBench.getSwitches()
392 pool = []
393 for name in switches.keys():
394 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
395 # e.g. push onos net-cfg for stratum switches
396 thread = main.Thread( target=main.NetworkBench.assignSwController,
397 name="assignSwitchToController",
398 args=[ name, main.Cluster.getIps(), '6653' ] )
399 pool.append( thread )
400 thread.start()
401 for thread in pool:
402 thread.join( 300 )
403 if not thread.result:
404 stepResult = main.FALSE
405 utilities.assert_equals( expect=main.TRUE,
406 actual=stepResult,
407 onpass="Successfully assign switches to controllers",
408 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800409
You Wang4cc61912018-08-28 10:10:58 -0700410 # Check devices
411 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700412 # Connecting to hosts that only have data plane connectivity
413 main.step( "Connecting inband hosts" )
414 stepResult = main.Network.connectInbandHosts()
415 utilities.assert_equals( expect=main.TRUE,
416 actual=stepResult,
417 onpass="Successfully connected inband hosts",
418 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800419 if hostDiscovery:
420 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700421
You Wang84f981d2018-01-12 16:11:50 -0800422 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700423 def saveOnosDiagnostics( main ):
424 """
425 Get onos-diags.tar.gz and save it to the log directory.
426 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
427 """
428 main.log.info( "Collecting onos-diags..." )
429 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
430 main.logdir,
431 "-CASE%d" % main.CurrentTestCaseNumber )
432
433 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700434 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700435 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700436
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700437 main.failures = int( main.params[ 'failures' ] )
438 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700439
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700440 if main.cfgName == '2x2':
441 spine = {}
442 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
443 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
444 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700445
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700446 spine = {}
447 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
448 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
449 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700450
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700451 elif main.cfgName == '4x4':
452 spine = {}
453 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
454 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
455 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700456
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700457 spine = {}
458 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
459 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
460 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700461
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700462 spine = {}
463 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
464 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
465 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700466
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700467 spine = {}
468 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
469 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
470 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700471
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700472 else:
Piera2a7e1b2016-10-04 11:51:43 -0700473 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700474 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800475
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800476 @staticmethod
477 def addStaticOnosRoute( main, subnet, intf):
478 """
479 Adds an ONOS static route with the use route-add command.
480 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800481 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
482
Piera2a7e1b2016-10-04 11:51:43 -0700483 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700484 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700485 """
486 Check number of groups for each subnet on device deviceId and matches
487 it with an expected value. subnetDict is a dictionarty containing values
488 of the type "10.0.1.0/24" : 5.
489 """
You Wangc02f3be2018-05-18 12:14:23 -0700490 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
491 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
492 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700493
You Wangc02f3be2018-05-18 12:14:23 -0700494 result = main.TRUE
495 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700496 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700497 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700498 # this will match the group id that this flow entry points to, for example :
499 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700500 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700501 count = 0
502 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700503 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700504 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700505 if count - 1 != numberInSelect:
506 result = main.FALSE
507 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 ) )
508 utilities.assert_equals( expect=main.TRUE, actual=result,
509 onpass="All bucket numbers are as expected",
510 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700511
512 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900513 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700514 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800515 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900516 if tag == "":
517 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700518 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700519 main.FALSE,
520 kwargs={ 'min': minFlowCount },
521 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800522 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800523 if count == main.FALSE:
524 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700525 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700526 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800527 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700528 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
529 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700530
531 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700532 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700533 main.FALSE,
534 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800535 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800536 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700537 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700538 expect=main.TRUE,
539 actual=flowCheck,
540 onpass="Flow status is correct!",
541 onfail="Flow status is wrong!" )
542 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700543 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700544 "flows",
545 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800546 tag + "_FlowsBefore",
547 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700548 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700549 "groups",
550 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800551 tag + "_GroupsBefore",
552 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700553
554 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700555 def checkDevices( main, switches, tag="", sleep=10 ):
556 main.step(
557 "Check whether the switches count is equal to %s" % switches )
558 if tag == "":
559 tag = 'CASE%d' % main.CurrentTestCaseNumber
560 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
561 main.FALSE,
562 kwargs={ 'numoswitch': switches},
563 attempts=10,
564 sleep=sleep )
565 utilities.assert_equals( expect=main.TRUE, actual=result,
566 onpass="Device up successful",
567 onfail="Failed to boot up devices?" )
568
569 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800570 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
571 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800572 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800573 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
574 main.FALSE,
575 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800576 attempts=5,
577 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800578 if count == main.FALSE:
579 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800580 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800581 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800582 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800583 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800584 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800585
586 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700587 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800588 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700589 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800590 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
591 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700592 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800593 attempts=5,
594 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800595 if count == main.FALSE:
596 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800597 utilities.assertEquals(
598 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800599 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700600 onpass="Flow count looks correct: " + str( count ) ,
601 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800602
603 @staticmethod
604 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
605 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700606 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800607 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
608 main.FALSE,
609 args=( dpid, groupCount, False, 1),
610 attempts=5,
611 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800612 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800613 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800614 utilities.assertEquals(
615 expect=True,
616 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700617 onpass="Group count looks correct: " + str( count ) ,
618 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800619
620 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700621 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800622
623 for dpid, values in main.count.items():
624 flowCount = values["flows"]
625 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700626 main.log.report( "Check flow count for dpid " + str( dpid ) +
627 ", should be " + str( flowCount ) )
628 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800629
Jon Hall9677ed32018-04-24 11:16:23 -0700630 main.log.report( "Check group count for dpid " + str( dpid ) +
631 ", should be " + str( groupCount ) )
632 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800633
634 return
635
636 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700637 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800638 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800639 '''
You Wangba231e72018-03-01 13:18:21 -0800640 Verify connectivity between hosts according to the ping chart
641 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800642 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800643 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800644 '''
You Wangba231e72018-03-01 13:18:21 -0800645 main.log.report( "Check host connectivity" )
646 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800647 if tag == "":
648 tag = 'CASE%d' % main.CurrentTestCaseNumber
649 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800650 main.log.debug( "Entry in ping chart: %s" % entry )
651 expect = entry[ 'expect' ]
652 if expect == "Unidirectional":
653 # Verify ping from each src host to each dst host
654 src = entry[ 'src' ]
655 dst = entry[ 'dst' ]
656 expect = main.TRUE
657 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
658 if basedOnIp:
659 if ("v4" in src[0]):
660 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
661 utilities.assert_equals( expect=expect, actual=pa,
662 onpass="IPv4 connectivity successfully tested",
663 onfail="IPv4 connectivity failed" )
664 if ("v6" in src[0]):
665 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
666 utilities.assert_equals( expect=expect, actual=pa,
667 onpass="IPv6 connectivity successfully tested",
668 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700669 elif main.physicalNet:
670 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
671 utilities.assert_equals( expect=expect, actual=pa,
672 onpass="IP connectivity successfully tested",
673 onfail="IP connectivity failed" )
674
You Wangba231e72018-03-01 13:18:21 -0800675 else:
676 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
677 utilities.assert_equals( expect=expect, actual=pa,
678 onpass="IP connectivity successfully tested",
679 onfail="IP connectivity failed" )
680 else:
681 # Verify ping between each host pair
682 hosts = entry[ 'hosts' ]
683 try:
684 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
685 except:
686 expect = main.FALSE
687 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
688 if basedOnIp:
689 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800690 pa = utilities.retry( main.Network.pingallHosts,
691 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700692 args=(hosts, ),
693 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800694 attempts=retryAttempts,
695 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800696 utilities.assert_equals( expect=expect, actual=pa,
697 onpass="IPv4 connectivity successfully tested",
698 onfail="IPv4 connectivity failed" )
699 if ("v6" in hosts[0]):
700 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
701 utilities.assert_equals( expect=expect, actual=pa,
702 onpass="IPv6 connectivity successfully tested",
703 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700704 elif main.physicalNet:
Jon Hall06fd0df2021-01-25 15:50:06 -0800705 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy )
Jon Hall43060f62020-06-23 13:13:33 -0700706 utilities.assert_equals( expect=expect, actual=pa,
707 onpass="IP connectivity successfully tested",
708 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800709 else:
You Wangf19d9f42018-02-23 16:34:19 -0800710 pa = main.Network.pingallHosts( hosts )
711 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800712 onpass="IP connectivity successfully tested",
713 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700714 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700715 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700716 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700717 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700718 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800719
720 if dumpflows:
721 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
722 "flows",
723 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800724 tag + "_FlowsOn",
725 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800726 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
727 "groups",
728 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800729 tag + "_GroupsOn",
730 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800731
732 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700733 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700734 """
735 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
736 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
737 Kill a link and verify ONOS can see the proper link change
738 """
Jon Halla604fd42018-05-04 14:27:27 -0700739 if sleep is None:
740 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
741 else:
742 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700743 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700744 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
745 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700746 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
747 onpass="Link down successful",
748 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700749 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700750 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700751 "Waiting %s seconds for link down to be discovered" % sleep )
752 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700753 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700754 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700755 main.FALSE,
756 kwargs={ 'numoswitch': switches,
757 'numolink': links },
758 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700759 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700760 utilities.assert_equals( expect=main.TRUE, actual=topology,
761 onpass="Topology after link down is correct",
762 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700763
764 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700765 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800766 """
767 links = list of links (src, dst) to bring down.
768 """
769
770 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700771 if sleep is None:
772 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
773 else:
774 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800775
776 for end1, end2 in links:
777 main.Network.link( END1=end1, END2=end2, OPTION="down")
778 main.Network.link( END1=end2, END2=end1, OPTION="down")
779
Jon Halla604fd42018-05-04 14:27:27 -0700780 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800781 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700782 "Waiting %s seconds for links down to be discovered" % sleep )
783 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800784
785 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
786 main.FALSE,
787 kwargs={ 'numoswitch': switches,
788 'numolink': linksAfter },
789 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700790 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800791
You Wang2854bce2018-03-30 10:15:32 -0700792 utilities.assert_equals( expect=main.TRUE, actual=topology,
793 onpass="Link batch down successful",
794 onfail="Link batch down failed" )
795
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800796 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700797 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800798 """
799 links = list of link (src, dst) to bring up again.
800 """
801
802 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700803 if sleep is None:
804 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
805 else:
806 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800807
808 for end1, end2 in links:
809 main.Network.link( END1=end1, END2=end2, OPTION="up")
810 main.Network.link( END1=end2, END2=end1, OPTION="up")
811
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800812 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700813 "Waiting %s seconds for links up to be discovered" % sleep )
814 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800815
816 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
817 main.FALSE,
818 kwargs={ 'numoswitch': switches,
819 'numolink': linksAfter },
820 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700821 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800822
You Wang2854bce2018-03-30 10:15:32 -0700823 utilities.assert_equals( expect=main.TRUE, actual=topology,
824 onpass="Link batch up successful",
825 onfail="Link batch up failed" )
826
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800827 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700828 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
829 """
830 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
831 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
832 switches, links: number of expected switches and links after link change, ex.: '4', '6'
833 """
834 if sleep is None:
835 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
836 else:
837 sleep = float( sleep )
838 main.step( "Disable a batch of ports" )
839 for dpid, port in ports:
840 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
841 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
842 time.sleep( sleep )
843 if switches and links:
844 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
845 numolink=links )
846 utilities.assert_equals( expect=main.TRUE, actual=result,
847 onpass="Port down successful",
848 onfail="Port down failed" )
849
850 @staticmethod
851 def enablePortBatch( main, ports, switches, links, sleep=None ):
852 """
853 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
854 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
855 switches, links: number of expected switches and links after link change, ex.: '4', '6'
856 """
857 if sleep is None:
858 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
859 else:
860 sleep = float( sleep )
861 main.step( "Enable a batch of ports" )
862 for dpid, port in ports:
863 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
864 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
865 time.sleep( sleep )
866 if switches and links:
867 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
868 numolink=links )
869 utilities.assert_equals( expect=main.TRUE, actual=result,
870 onpass="Port up successful",
871 onfail="Port up failed" )
872
873 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700874 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700875 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700876 """
877 Params:
878 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700879 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700880 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
881 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
882 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
883 Kill a link and verify ONOS can see the proper link change
884 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700885 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700886 if sleep is None:
887 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
888 else:
889 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700890 result = False
891 count = 0
892 while True:
893 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700894 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800895 main.Network.link( END1=end1, END2=end2, OPTION="up" )
896 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700897 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700898 "Waiting %s seconds for link up to be discovered" % sleep )
899 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700900
You Wangc02d8352018-04-17 16:42:10 -0700901 if portUp:
902 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
903 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700904 main.log.info(
905 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700906 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700907
Jon Halla604fd42018-05-04 14:27:27 -0700908 result = ctrl.CLI.checkStatus( numoswitch=switches,
909 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700910 if count > 5 or result:
911 break
912 utilities.assert_equals( expect=main.TRUE, actual=result,
913 onpass="Link up successful",
914 onfail="Failed to bring link up" )
915
916 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700917 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700918 """
919 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
920 Completely kill a switch and verify ONOS can see the proper change
921 """
Jon Halla604fd42018-05-04 14:27:27 -0700922 if sleep is None:
923 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
924 else:
925 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700926 switch = switch if isinstance( switch, list ) else [ switch ]
927 main.step( "Kill " + str( switch ) )
928 for s in switch:
929 main.log.info( "Stopping " + s )
930 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700931 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700932
933 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700934 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700935 sleep ) )
936 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700937 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700938 main.FALSE,
939 kwargs={ 'numoswitch': switches,
940 'numolink': links },
941 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700942 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700943 utilities.assert_equals( expect=main.TRUE, actual=topology,
944 onpass="Kill switch successful",
945 onfail="Failed to kill switch?" )
946
947 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700948 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700949 """
950 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
951 Recover a switch and verify ONOS can see the proper change
952 """
Jon Halla604fd42018-05-04 14:27:27 -0700953 if sleep is None:
954 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
955 else:
956 sleep = float( sleep )
957 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700958 switch = switch if isinstance( switch, list ) else [ switch ]
959 main.step( "Recovering " + str( switch ) )
960 for s in switch:
961 main.log.info( "Starting " + s )
962 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700963 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700964 sleep ) )
965 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700966 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700967 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700968 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700969 sleep ) )
970 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700971
Devin Lim142b5342017-07-20 15:22:39 -0700972 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700973 main.FALSE,
974 kwargs={ 'numoswitch': switches,
975 'numolink': links },
976 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700977 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700978 utilities.assert_equals( expect=main.TRUE, actual=topology,
979 onpass="Switch recovery successful",
980 onfail="Failed to recover switch?" )
981
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700982 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700983 def killRouter( main, router, sleep=None ):
984 """
985 Kill bgpd process on a quagga router
986 router: name of the router to be killed. E.g. "bgp1"
987 """
988 sleep = float( sleep )
989 main.step( "Kill " + str( router ) )
990 if hasattr( main, 'Mininet1' ):
991 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
992 main.Mininet1.handle.expect( "mininet>" )
993 else:
994 # TODO: support killing router in physical network
995 pass
996 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
997 time.sleep( sleep )
998
999 @staticmethod
1000 def recoverRouter( main, router, sleep=None ):
1001 """
1002 Restart bgpd process on a quagga router
1003 router: name of the router to be recovered. E.g. "bgp1"
1004 """
1005 sleep = float( sleep )
1006 main.step( "Recovering " + str( router ) )
1007 if hasattr( main, 'Mininet1' ):
1008 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1009 main.Mininet1.handle.expect( "mininet>" )
1010 else:
1011 # TODO: support recovering router in physical network
1012 pass
1013 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1014 time.sleep( sleep )
1015
1016 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001017 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001018 """
1019 Stop Onos-cluster.
1020 Stops Mininet
1021 Copies ONOS log
1022 """
You Wang4cc61912018-08-28 10:10:58 -07001023 from tests.dependencies.utils import Utils
1024 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001025 if not main.persistentSetup:
1026 for ctrl in main.Cluster.active():
1027 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001028 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001029 if hasattr( main, "scapyHosts" ):
1030 scapyResult = main.TRUE
1031 for host in main.scapyHosts:
1032 scapyResult = host.stopScapy() and scapyResult
1033 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1034 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001035 if hasattr( main, 'Mininet1' ):
1036 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1037 else:
1038 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001039 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1040 main.scapyHosts = []
1041
You Wang5da39c82018-04-26 22:55:08 -07001042 if removeHostComponent:
1043 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1044 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001045 if hasattr( main, 'Mininet1' ):
1046 pass
1047 else:
1048 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001049 main.Network.removeHostComponent( host )
1050
You Wang5df1c6d2018-04-06 18:02:02 -07001051 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001052 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001053 else:
1054 main.Network.disconnectInbandHosts()
1055 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001056
You Wang5df1c6d2018-04-06 18:02:02 -07001057 if copyKarafLog:
1058 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001059
Jon Hall627b1572020-12-01 12:01:15 -08001060 if not main.persistentSetup:
1061 for ctrl in main.Cluster.active():
1062 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001063 else:
1064 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001065 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001066
1067 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001068 def verifyNodes( main ):
1069 """
1070 Verifies Each active node in the cluster has an accurate view of other node's and their status
1071
1072 Params:
1073 nodes, integer array with position of the ONOS nodes in the CLIs array
1074 """
1075 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1076 False,
1077 attempts=10,
1078 sleep=10 )
1079 utilities.assert_equals( expect=True, actual=nodeResults,
1080 onpass="Nodes check successful",
1081 onfail="Nodes check NOT successful" )
1082
1083 if not nodeResults:
1084 for ctrl in main.Cluster.runningNodes:
1085 main.log.debug( "{} components not ACTIVE: \n{}".format(
1086 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001087 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001088 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001089 main.cleanAndExit()
1090
1091 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001092 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001093 """
1094 Verifies that the ONOS cluster has an acuurate view of the topology
1095
1096 Params:
1097 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 -08001098 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001099 """
1100 main.step( "Check number of topology elements" )
1101 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1102 main.FALSE,
1103 kwargs={ 'numoswitch': switches,
1104 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001105 'numoctrl': expNodes,
1106 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001107 attempts=10,
1108 sleep=12 )
1109 utilities.assert_equals( expect=main.TRUE, actual=topology,
1110 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001111 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001112
1113 @staticmethod
1114 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001115 """
1116 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1117 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1118 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1119 """
Jon Halla604fd42018-05-04 14:27:27 -07001120 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001121 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001122 if sleep is None:
1123 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1124 else:
1125 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001126
Jon Hall214f88b2020-09-21 10:21:42 -07001127 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001128 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001129 node = main.Cluster.runningNodes[ i ]
1130 if node.inDocker:
1131 killResult = node.server.dockerStop( node.name )
1132 else:
1133 killResult = main.ONOSbench.onosDie( node.ipAddress )
1134 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001135 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001136 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1137 onpass="ONOS instance Killed",
1138 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001139 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001140 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001141 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001142
Devin Lim142b5342017-07-20 15:22:39 -07001143 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001144 Testcaselib.verifyNodes( main )
1145 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001146
1147 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001148 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001149 """
1150 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1151 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1152 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1153 """
Jon Hall3c910162018-03-07 14:42:16 -08001154 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001155 if sleep is None:
1156 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1157 else:
1158 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001159 for i in nodes:
1160 node = main.Cluster.runningNodes[ i ]
1161 if node.inDocker:
1162 main.Cluster.startONOSDockerNode( i )
1163 else:
1164 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001165 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001166 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001167 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001168 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001169 if node.inDocker:
1170 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1171 isUp = isUp and node.CLI.prepareForCLI()
1172 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1173 else:
1174 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001175 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1176 onpass="ONOS service is ready",
1177 onfail="ONOS service did not start properly" )
1178 for i in nodes:
1179 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001180 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001181 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001182 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1183 commandlineTimeout=60,
1184 onosStartTimeout=100 )
1185 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001186 utilities.assert_equals( expect=main.TRUE,
1187 actual=cliResult,
1188 onpass="ONOS CLI is ready",
1189 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001190
Jon Halla604fd42018-05-04 14:27:27 -07001191 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001192 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001193 Testcaselib.verifyNodes( main )
1194 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001195
Devin Lim142b5342017-07-20 15:22:39 -07001196 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001197 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001198 attempts=10,
1199 sleep=12 )
1200 if ready:
1201 ready = main.TRUE
1202 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001203 onpass="ONOS summary command succeded",
1204 onfail="ONOS summary command failed" )
1205 if not ready:
1206 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001207 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001208
1209 @staticmethod
1210 def addHostCfg( main ):
1211 """
1212 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001213 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001214 """
1215 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001216 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001217 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001218 hostCfg = json.load( template )
1219 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1220 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001221 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001222 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1223 subjectClass="hosts",
1224 subjectKey=urllib.quote( mac,
1225 safe='' ),
1226 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001227 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1228 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001229 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001230 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1231 subjectClass="hosts",
1232 subjectKey=urllib.quote( mac,
1233 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001234 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001235 main.pingChart.update( { 'vlan1': { "expect": "True",
1236 "hosts": [ "olt1", "vsg1" ] } } )
1237 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1238 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001239 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1240 vlanId=1,
1241 port1=5,
1242 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001243
1244 @staticmethod
1245 def delHostCfg( main ):
1246 """
1247 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001248 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001249 """
1250 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001251 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001252 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001253 hostCfg = json.load( template )
1254 main.step( "Removing host configuration" )
1255 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001256 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001257 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1258 subjectKey=urllib.quote(
1259 mac,
1260 safe='' ),
1261 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001262 main.step( "Removing configuration" )
1263 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001264 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001265 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1266 subjectKey=urllib.quote(
1267 mac,
1268 safe='' ),
1269 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001270 main.step( "Removing vlan configuration" )
1271 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001272 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1273 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001274
1275 @staticmethod
1276 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1277 """
1278 Verifies IP address assignment from the hosts
1279 """
1280 main.step( "Verify IP address assignment from hosts" )
1281 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001282 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001283 # Find out names of disconnected hosts
1284 disconnectedHosts = []
1285 if hasattr( main, "disconnectedIpv4Hosts" ):
1286 for host in main.disconnectedIpv4Hosts:
1287 disconnectedHosts.append( host )
1288 if hasattr( main, "disconnectedIpv6Hosts" ):
1289 for host in main.disconnectedIpv6Hosts:
1290 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001291 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001292 # Exclude disconnected hosts
1293 if hostName in disconnectedHosts:
1294 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1295 continue
You Wang53dba1e2018-02-02 17:45:44 -08001296 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1297 main.FALSE,
1298 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001299 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001300 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001301 attempts=attempts,
1302 sleep=sleep )
1303 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1304 onpass="Verify network host IP succeded",
1305 onfail="Verify network host IP failed" )
1306
1307 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001308 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001309 """
1310 Verifies host IP address assignment from ONOS
1311 """
1312 main.step( "Verify host IP address assignment in ONOS" )
1313 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001314 # Find out IPs of disconnected hosts
1315 disconnectedIps = []
1316 if hasattr( main, "disconnectedIpv4Hosts" ):
1317 for host in main.disconnectedIpv4Hosts:
1318 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1319 if hasattr( main, "disconnectedIpv6Hosts" ):
1320 for host in main.disconnectedIpv6Hosts:
1321 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001322 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001323 # Exclude disconnected hosts
1324 if ip in disconnectedIps:
1325 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1326 continue
You Wang53dba1e2018-02-02 17:45:44 -08001327 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1328 main.FALSE,
1329 kwargs={ 'hostList': [ hostName ],
1330 'prefix': ip },
1331 attempts=attempts,
1332 sleep=sleep )
1333 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1334 onpass="Verify ONOS host IP succeded",
1335 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001336 if not ipResult and skipOnFail:
1337 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001338 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001339 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001340
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001341 @staticmethod
1342 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1343 """
1344 Description:
1345 Updates interface configuration in ONOS, with given IP and vlan parameters
1346 Required:
1347 * connectPoint: connect point to update configuration
1348 Optional:
1349 * ips: list of IP addresses, combined with '/xx' subnet representation,
1350 corresponding to 'ips' field in the configuration
1351 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1352 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1353 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1354 """
1355 cfg = dict()
1356 cfg[ "ports" ] = dict()
1357 cfg[ "ports" ][ connectPoint ] = dict()
1358 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1359 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1360 if untagged > 0:
1361 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1362 else:
1363 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1364 if native > 0:
1365 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1366
1367 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001368
1369 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001370 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001371 """
1372 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001373 scapyNames: list of names that will be used as component names for scapy hosts
1374 mininetNames: used when scapy host names are different from the host names
1375 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1376 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001377 """
1378 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001379 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1380 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001381 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001382 if hasattr( main, 'Mininet1' ):
1383 main.Scapy.createHostComponent( scapyName )
1384 scapyHandle = getattr( main, scapyName )
1385 if mininetNames:
1386 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1387 else:
1388 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001389 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1390 scapyHandle.mExecDir = "/tmp"
1391 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1392 main.log.debug( "start mn host component in docker" )
1393 scapyHandle.startHostCli( mininetName,
1394 execDir="/tmp",
1395 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1396 else:
1397 main.log.debug( "start mn host component" )
1398 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001399 else:
You Wang0fc21702018-11-02 17:49:18 -07001400 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001401 scapyHandle = getattr( main, scapyName )
1402 scapyHandle.connectInband()
1403 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001404 scapyHandle.startScapy()
1405 scapyHandle.updateSelf()
1406 main.log.debug( scapyHandle.name )
1407 main.log.debug( scapyHandle.hostIp )
1408 main.log.debug( scapyHandle.hostMac )
1409
1410 @staticmethod
1411 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1412 """
1413 Verify unicast traffic by pinging from source hosts to the destination IP
1414 and capturing the packets at the destination host using Scapy.
1415 srcHosts: List of host names to send the ping packets
1416 dstIp: destination IP of the ping packets
1417 dstHost: host that runs Scapy to capture the packets
1418 dstIntf: name of the interface on the destination host
1419 expect: use True if the ping is expected to be captured at destination;
1420 Otherwise False
1421 skipOnFail: skip the rest of this test case if result is not expected
1422 maxRetry: number of retries allowed
1423 """
1424 from tests.dependencies.topology import Topology
1425 try:
1426 main.topo
1427 except ( NameError, AttributeError ):
1428 main.topo = Topology()
1429 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1430 result = main.TRUE
1431 for srcHost in srcHosts:
1432 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1433 expect, maxRetry, True )
1434 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001435 result = main.FALSE
1436 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1437 utilities.assert_equals( expect=main.TRUE,
1438 actual=result,
1439 onpass="Verify traffic to {}: Pass".format( dstIp ),
1440 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1441 if skipOnFail and result != main.TRUE:
1442 Testcaselib.saveOnosDiagnostics( main )
1443 Testcaselib.cleanup( main, copyKarafLog=False )
1444 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001445
1446 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001447 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001448 """
1449 Verify multicast traffic using scapy
1450 """
You Wangc564c6f2018-05-01 15:24:57 -07001451 from tests.dependencies.topology import Topology
1452 try:
1453 main.topo
1454 except ( NameError, AttributeError ):
1455 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001456 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001457 routeData = main.multicastConfig[ routeName ]
1458 srcs = main.mcastRoutes[ routeName ][ "src" ]
1459 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1460 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1461 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001462 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001463 for src in srcs:
1464 srcEntry = routeData[ "src" ][ src ]
1465 for dst in dsts:
1466 dstEntry = routeData[ "dst" ][ dst ]
1467 sender = getattr( main, srcEntry[ "host" ] )
1468 receiver = getattr( main, dstEntry[ "host" ] )
1469 main.Network.addRoute( str( srcEntry[ "host" ] ),
1470 str( routeData[ "group" ] ),
1471 str( srcEntry[ "interface" ] ),
1472 True if routeData[ "ipVersion" ] == 6 else False )
1473 # Build the packet
1474 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1475 if routeData[ "ipVersion" ] == 4:
1476 sender.buildIP( dst=str( routeData[ "group" ] ) )
1477 elif routeData[ "ipVersion" ] == 6:
1478 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1479 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1480 sIface = srcEntry[ "interface" ]
1481 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1482 pktFilter = srcEntry[ "filter" ]
1483 pkt = srcEntry[ "packet" ]
1484 # Send packet and check received packet
1485 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001486 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001487 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001488 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1489 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001490 if not trafficResult:
1491 result = main.FALSE
1492 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1493 dstEntry[ "host" ] ) )
1494 utilities.assert_equals( expect=main.TRUE,
1495 actual=result,
1496 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1497 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001498 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001499 Testcaselib.saveOnosDiagnostics( main )
1500 Testcaselib.cleanup( main, copyKarafLog=False )
1501 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001502
1503 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001504 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001505 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1506 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001507 """
1508 Verify reachability from each host in srcList to each host in dstList
1509 """
1510 from tests.dependencies.topology import Topology
1511 try:
1512 main.topo
1513 except ( NameError, AttributeError ):
1514 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001515 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001516 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001517 utilities.assert_equals( expect=main.TRUE,
1518 actual=pingResult,
1519 onpass="{}: Pass".format( stepMsg ),
1520 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001521 if not pingResult and skipOnFail:
1522 Testcaselib.saveOnosDiagnostics( main )
1523 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1524 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001525
1526 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001527 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001528 """
1529 Verify if the specified host is discovered by ONOS on the given locations
1530 Required:
You Wang85747762018-05-11 15:51:50 -07001531 locationDict: a dictionary that maps host names to expected locations.
1532 locations could be a string or a list.
1533 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001534 Returns:
1535 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1536 """
You Wang85747762018-05-11 15:51:50 -07001537 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1538 result = main.TRUE
1539 for hostName, locations in locationDict.items():
1540 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1541 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1542 if not hostIp:
1543 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1544 if not hostIp:
1545 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1546 result = main.FALSE
1547 continue
1548 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1549 main.FALSE,
1550 args=( hostIp, locations ),
1551 attempts=retry + 1,
1552 sleep=10 )
1553 if not locationResult:
1554 result = main.FALSE
1555 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001556 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001557 onpass="Location verification passed",
1558 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001559
1560 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001561 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001562 """
1563 Move specified host from srcSw to dstSw.
1564 If srcSw and dstSw are same, the host will be moved from current port to
1565 next available port.
1566 Required:
1567 hostName: name of the host. e.g., "h1"
1568 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1569 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1570 gw: ip address of the gateway of the new location
1571 Optional:
1572 macAddr: if specified, change MAC address of the host to the specified MAC address.
1573 prefixLen: prefix length
1574 cfg: port configuration as JSON string
1575 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001576 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001577 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001578 if not hasattr( main, 'Mininet1' ):
1579 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1580 return
1581
You Wang6e5b48e2018-07-23 16:17:38 -07001582 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1583 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1584 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001585 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001586 if cfg:
1587 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1588 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001589 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001590 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001591 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001592
1593 main.Mininet1.discoverHosts( [ hostName, ] )
1594
1595 # Update expectedHost when MAC address is changed.
1596 if macAddr is not None:
1597 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1598 if ipAddr is not None:
1599 for hostName, ip in main.expectedHosts[ "onos" ].items():
1600 if ip == ipAddr:
1601 vlan = hostName.split( "/" )[ -1 ]
1602 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001603 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001604 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001605
1606 @staticmethod
1607 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001608 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001609 """
1610 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1611 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1612 to next available port.
1613 Required:
1614 hostName: name of the host. e.g., "h1"
1615 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1616 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1617 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1618 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1619 gw: ip address of the gateway of the new location
1620 Optional:
1621 macAddr: if specified, change MAC address of the host to the specified MAC address.
1622 prefixLen: prefix length
1623 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001624 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001625 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001626 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001627 if not hasattr( main, 'Mininet1' ):
1628 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1629 return
1630
You Wang6e5b48e2018-07-23 16:17:38 -07001631 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1632 srcSw, srcPairSw, dstSw, dstPairSw ) )
1633 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1634 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1635 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001636 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001637 if cfg:
1638 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1639 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001640 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001641 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001642 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001643
1644 main.Mininet1.discoverHosts( [ hostName, ] )
1645
1646 # Update expectedHost when MAC address is changed.
1647 if macAddr is not None:
1648 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1649 if ipAddr is not None:
1650 for hostName, ip in main.expectedHosts[ "onos" ].items():
1651 if ip == ipAddr:
1652 vlan = hostName.split( "/" )[ -1 ]
1653 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001654 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001655
1656 @staticmethod
1657 def mnDockerSetup( main ):
1658 """
1659 Optionally start and setup docker image for mininet
1660 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001661 try:
1662 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001663
Jon Hall9b0de1f2020-08-24 15:38:04 -07001664 main.log.info( "Creating Mininet Docker" )
1665 handle = main.Mininet1.handle
1666 # build docker image
1667 dockerFilePath = "%s/../dependencies/" % main.testDir
1668 dockerName = "trellis_mininet"
1669 # Stop any leftover container
1670 main.Mininet1.dockerStop( dockerName )
1671 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001672 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001673
Jon Hall9b0de1f2020-08-24 15:38:04 -07001674 confDir = "/tmp/mn_conf/"
1675 # Try to ensure the destination exists
1676 main.log.info( "Create folder for network config files" )
1677 handle.sendline( "rm -rf %s" % confDir )
1678 handle.expect( main.Mininet1.Prompt() )
1679 main.log.debug( handle.before + handle.after )
1680 handle.sendline( "mkdir -p %s" % confDir )
1681 handle.expect( main.Mininet1.Prompt() )
1682 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001683 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1684 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001685 # Make sure permissions are correct
1686 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1687 handle.expect( main.Mininet1.Prompt() )
1688 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1689 handle.expect( main.Mininet1.Prompt() )
1690 main.log.debug( handle.before + handle.after )
1691 # Start docker container
1692 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1693 dockerName,
1694 main.params[ 'MN_DOCKER' ][ 'args' ] )
1695 if runResponse == main.FALSE:
1696 main.log.error( "Docker container already running, aborting test" )
1697 main.cleanup()
1698 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001699
Jon Hall9b0de1f2020-08-24 15:38:04 -07001700 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1701 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001702
Jon Hall9b0de1f2020-08-24 15:38:04 -07001703 # Fow when we create component handles
1704 main.Mininet1.mExecDir = "/tmp"
1705 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1706 main.Mininet1.hostPrompt = "/home/root#"
1707
1708 # For some reason docker isn't doing this
1709 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1710 main.Mininet1.handle.expect( "etc/hosts" )
1711 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1712 except Exception as e:
1713 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001714 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001715
1716 @staticmethod
1717 def mnDockerTeardown( main ):
1718 """
1719 Optionally stop and cleanup docker image for mininet
1720 """
1721
1722 if hasattr( main, 'Mininet1' ):
1723 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001724 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001725
1726 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001727 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001728 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001729 main.Mininet1.sudoRequired = True
1730 except Exception as e:
1731 main.log.error( e )
1732
Jon Hall39570262020-11-17 12:18:19 -08001733 # Save docker logs
1734 copyResult = main.ONOSbench.scp( main.Mininet1,
1735 "/tmp/mn-stratum/*",
1736 main.logdir,
1737 direction="from",
1738 options="-rp" )
1739
1740
Jon Hall43060f62020-06-23 13:13:33 -07001741 @staticmethod
1742 def setOnosConfig( main ):
1743 """
1744 Read and Set onos configurations from the params file
1745 """
1746 main.step( "Set ONOS configurations" )
1747 config = main.params.get( 'ONOS_Configuration' )
1748 if config:
1749 main.log.debug( config )
1750 checkResult = main.TRUE
1751 for component in config:
1752 for setting in config[ component ]:
1753 value = config[ component ][ setting ]
1754 check = main.Cluster.next().setCfg( component, setting, value )
1755 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1756 checkResult = check and checkResult
1757 utilities.assert_equals( expect=main.TRUE,
1758 actual=checkResult,
1759 onpass="Successfully set config",
1760 onfail="Failed to set config" )
1761 else:
1762 main.log.warn( "No configurations were specified to be changed after startup" )
1763
1764 @staticmethod
1765 def setOnosLogLevels( main ):
1766 """
1767 Read and Set onos log levels from the params file
1768 """
1769 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001770 # Get original values incase we want to reset them
1771 ctrl = main.Cluster.active(0)
1772 ctrl.CLI.logList()
1773
Jon Hall43060f62020-06-23 13:13:33 -07001774 logging = True
1775 try:
1776 logs = main.params.get( 'ONOS_Logging', False )
1777 if logs:
1778 for namespace, level in logs.items():
1779 for ctrl in main.Cluster.active():
1780 ctrl.CLI.logSet( level, namespace )
1781 except AttributeError:
1782 logging = False
1783 utilities.assert_equals( expect=True, actual=logging,
1784 onpass="Set log levels",
1785 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001786
1787 @staticmethod
1788 def resetOnosLogLevels( main ):
1789 """
1790 Read and reset onos log levels to a previously read set of values
1791 """
1792 main.step( 'Reset logging levels' )
1793 # Get original values incase we want to reset them
1794 ctrl = main.Cluster.active(0)
1795 currentLevels = ctrl.CLI.logList( saveValues=False )
1796 origLevels = ctrl.CLI.logLevels
1797 toBeSet = {}
1798 for logger, level in currentLevels.iteritems():
1799 if logger not in origLevels:
1800 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1801 else:
1802 oldLevel = origLevels[ logger ]
1803 if level != oldLevel:
1804 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07001805 # In case a previous test didn't reset
1806 logs = main.params.get( 'ONOS_Logging_Reset', False )
1807 if logs:
1808 for namespace, level in logs.items():
1809 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08001810 logging = True
1811 try:
1812 for logger, level in toBeSet.iteritems():
1813 for ctrl in main.Cluster.active():
1814 ctrl.CLI.logSet( level, logger )
1815 except AttributeError:
1816 logging = False
1817 utilities.assert_equals( expect=True, actual=logging,
1818 onpass="Reset log levels",
1819 onfail="Failed to reset log levels" )