blob: 5ed17848471f1d3c41c7727cf517bf5fadb82a21 [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 """
114 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700115 try:
Jon Hall627b1572020-12-01 12:01:15 -0800116 if not main.persistentSetup and main.params.get( 'EXTERNAL_APPS' ):
Jon Hall43060f62020-06-23 13:13:33 -0700117 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800118 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700119 main.ONOSbench.onosFetchApp( url )
120 if not main.apps:
121 main.log.error( "App list is empty" )
122 except Exception as e:
123 main.log.debug( e )
124 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800125 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
126 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700127 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800128 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800129 skipPack=skipPackage,
130 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800131 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700132 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700133 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800134 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700135 attempts=10 )
136 if ready:
137 ready = main.TRUE
138 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700139 onpass="ONOS summary command succeded",
140 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700141 if not ready:
142 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700143 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700144
You Wang5bf49592020-07-08 18:47:46 -0700145 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700146 appInstallResult = main.TRUE
147 if main.trellisOar:
148 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700149 if main.t3Oar:
150 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
151 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
152 onpass="SR app installation succeded",
153 onfail="SR app installation failed" )
154 if not appInstallResult:
155 main.cleanAndExit()
156
Jon Hall43060f62020-06-23 13:13:33 -0700157 # FIXME: move to somewhere else?
158 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
159 # TODO: Support other pipeconfs/making this configurable
160 if switchPrefix == "tofino":
161 # It seems to take some time for the pipeconfs to be loaded
162 ctrl = main.Cluster.next()
163 for i in range( 120 ):
164 try:
165 main.log.debug( "Checking to see if pipeconfs are loaded" )
166 output = ctrl.CLI.sendline( "pipeconfs" )
167 if "tofino" in output:
168 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
169 break
170 time.sleep( 1 )
171 except Exception as e:
172 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700173
Jon Hall627b1572020-12-01 12:01:15 -0800174 # Install segmentrouting and t3 app
175 appInstallResult = main.TRUE
176 if not main.persistentSetup:
177 if main.trellisOar:
178 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
179 if main.t3Oar:
180 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
181 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
182 onpass="SR app installation succeded",
183 onfail="SR app installation failed" )
184 if not appInstallResult:
185 main.cleanAndExit()
186
Jon Hall43060f62020-06-23 13:13:33 -0700187 Testcaselib.setOnosLogLevels( main )
188 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700189
Jon Hall1efcb3f2016-08-23 13:42:15 -0700190 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800191 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700192 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
193 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800194
195 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700196 def loadJson( main, suffix='' ):
197 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
198 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800199 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
200
201 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700202 def loadXconnects( main, suffix='' ):
203 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
204 main.cfgName, suffix ) ) as cfg:
205 for xconnect in json.load( cfg ).get('xconnects'):
206 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
207
208 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800209 def loadChart( main ):
210 try:
211 with open( "%s%s.chart" % ( main.configPath + main.forChart,
212 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700213 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800214 except IOError:
215 main.log.warn( "No chart file found." )
216
217 @staticmethod
218 def loadHost( main ):
219 with open( "%s%s.host" % ( main.configPath + main.forHost,
220 main.cfgName ) ) as host:
221 main.expectedHosts = json.load( host )
222
223 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800224 def loadSwitchFailureChart( main ):
225 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
226 main.cfgName ) ) as sfc:
227 main.switchFailureChart = json.load( sfc )
228
229 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800230 def loadLinkFailureChart( main ):
231 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700232 main.cfgName ) ) as lfc:
233 main.linkFailureChart = json.load( lfc )
234
235 @staticmethod
236 def loadMulticastConfig( main ):
237 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
238 main.cfgName ) ) as cfg:
239 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800240
241 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700242 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700243 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800244 copyResult = main.ONOSbench.scp( main.Mininet1,
245 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700246 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800247 direction="to" )
248 if main.topologyLib:
249 for lib in main.topologyLib.split(","):
250 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
251 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700252 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800253 direction="to" )
254 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700255 import re
256 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
257 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700258 destDir = "~/"
259 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
260 destDir = "/tmp/mn_conf/"
261 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800262 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700263 # Update zebra configurations with correct ONOS instance IP
264 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
265 ip = controllerIPs[ index ]
266 index = ( index + 1 ) % len( controllerIPs )
267 with open( main.configPath + main.forConfig + conf ) as f:
268 s = f.read()
269 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
270 with open( main.configPath + main.forConfig + conf, "w" ) as f:
271 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800272 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800273 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700274 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800275 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800276 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700277 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800278 main.Mininet1.home + "custom",
279 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700280
281 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
282 # move the config files into home
283 main.Mininet1.handle.sendline( "cp config/* . " )
284 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
285 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
286 main.Mininet1.handle.sendline( "ls -al " )
287 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
288 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
289
You Wangd87b2312018-01-30 12:47:17 -0800290 stepResult = copyResult
291 utilities.assert_equals( expect=main.TRUE,
292 actual=stepResult,
293 onpass="Successfully copied topo files",
294 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700295 if main.stratumRoot:
296 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700297 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700298 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700299 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700300 main.topology = topology
301 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700302 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700303 stepResult = topoResult
304 utilities.assert_equals( expect=main.TRUE,
305 actual=stepResult,
306 onpass="Successfully loaded topology",
307 onfail="Failed to load topology" )
308 # Exit if topology did not load properly
309 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700310 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700311 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700312 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700313 # Upload the net-cfg file created for each switch
314 filename = "onos-netcfg.json"
315 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700316 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700317 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
318 path = "/tmp/mn-stratum/%s/" % switch
319 dstPath = "/tmp/"
320 dstFileName = "%s-onos-netcfg.json" % switch
321 main.ONOSbench1.scp( main.Mininet1,
322 "%s%s" % ( path, filename ),
323 "%s%s" % ( dstPath, dstFileName ),
324 "from" )
325 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 -0700326 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700327 # Configure managementAddress
328 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
329 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
330 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
331 # Configure device id
332 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
333 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
334 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
335 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800336 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 -0700337 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
338 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700339 node = main.Cluster.active(0)
340 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
341 dstPath,
342 dstFileName,
343 user=node.REST.user_name,
344 password=node.REST.pwd )
345 # Stop test if we fail to push switch netcfg
346 utilities.assert_equals( expect=main.TRUE,
347 actual=switchNetCfg,
348 onpass="Successfully pushed switch netcfg",
349 onfail="Failed to configure switches in onos" )
350 if not switchNetCfg:
351 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700352 # Make sure hosts make some noise
353 Testcaselib.discoverHosts( main )
354
355 @staticmethod
356 def discoverHosts( main ):
357 # TODO add option to only select specific hosts
358 if hasattr( main, "Mininet1" ):
359 network = main.Mininet1
360 elif hasattr( main, "NetworkBench" ):
361 network = main.NetworkBench
362 else:
363 main.log.warn( "Could not find component for test network, skipping host discovery" )
364 return
365 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700366
367 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800368 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800369 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700370 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800371 topoResult = main.NetworkBench.connectToNet()
372 stepResult = topoResult
373 utilities.assert_equals( expect=main.TRUE,
374 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700375 onpass="Successfully connected to topology",
376 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800377 # Exit if topology did not load properly
378 if not topoResult:
379 main.cleanAndExit()
380
Jon Hall627b1572020-12-01 12:01:15 -0800381 if not main.persistentSetup:
382 # Perform any optional setup
383 for switch in main.NetworkBench.switches:
384 if hasattr( switch, "setup" ):
385 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700386
Jon Hall627b1572020-12-01 12:01:15 -0800387 main.step( "Assign switches to controllers." )
388 stepResult = main.TRUE
389 switches = main.NetworkBench.getSwitches()
390 pool = []
391 for name in switches.keys():
392 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
393 # e.g. push onos net-cfg for stratum switches
394 thread = main.Thread( target=main.NetworkBench.assignSwController,
395 name="assignSwitchToController",
396 args=[ name, main.Cluster.getIps(), '6653' ] )
397 pool.append( thread )
398 thread.start()
399 for thread in pool:
400 thread.join( 300 )
401 if not thread.result:
402 stepResult = main.FALSE
403 utilities.assert_equals( expect=main.TRUE,
404 actual=stepResult,
405 onpass="Successfully assign switches to controllers",
406 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800407
You Wang4cc61912018-08-28 10:10:58 -0700408 # Check devices
409 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700410 # Connecting to hosts that only have data plane connectivity
411 main.step( "Connecting inband hosts" )
412 stepResult = main.Network.connectInbandHosts()
413 utilities.assert_equals( expect=main.TRUE,
414 actual=stepResult,
415 onpass="Successfully connected inband hosts",
416 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800417 if hostDiscovery:
418 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700419
You Wang84f981d2018-01-12 16:11:50 -0800420 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700421 def saveOnosDiagnostics( main ):
422 """
423 Get onos-diags.tar.gz and save it to the log directory.
424 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
425 """
426 main.log.info( "Collecting onos-diags..." )
427 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
428 main.logdir,
429 "-CASE%d" % main.CurrentTestCaseNumber )
430
431 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700432 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700433 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700434
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700435 main.failures = int( main.params[ 'failures' ] )
436 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700437
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700438 if main.cfgName == '2x2':
439 spine = {}
440 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
441 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
442 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700443
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700444 spine = {}
445 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
446 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
447 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700448
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700449 elif main.cfgName == '4x4':
450 spine = {}
451 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
452 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
453 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700454
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700455 spine = {}
456 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
457 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
458 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700459
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700460 spine = {}
461 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
462 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
463 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700464
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700465 spine = {}
466 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
467 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
468 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700469
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700470 else:
Piera2a7e1b2016-10-04 11:51:43 -0700471 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700472 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800473
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800474 @staticmethod
475 def addStaticOnosRoute( main, subnet, intf):
476 """
477 Adds an ONOS static route with the use route-add command.
478 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800479 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
480
Piera2a7e1b2016-10-04 11:51:43 -0700481 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700482 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700483 """
484 Check number of groups for each subnet on device deviceId and matches
485 it with an expected value. subnetDict is a dictionarty containing values
486 of the type "10.0.1.0/24" : 5.
487 """
You Wangc02f3be2018-05-18 12:14:23 -0700488 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
489 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
490 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700491
You Wangc02f3be2018-05-18 12:14:23 -0700492 result = main.TRUE
493 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700494 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700495 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700496 # this will match the group id that this flow entry points to, for example :
497 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700498 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700499 count = 0
500 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700501 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700502 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700503 if count - 1 != numberInSelect:
504 result = main.FALSE
505 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 ) )
506 utilities.assert_equals( expect=main.TRUE, actual=result,
507 onpass="All bucket numbers are as expected",
508 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700509
510 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900511 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700512 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800513 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900514 if tag == "":
515 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700516 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700517 main.FALSE,
518 kwargs={ 'min': minFlowCount },
519 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800520 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800521 if count == main.FALSE:
522 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700523 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700524 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800525 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700526 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
527 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700528
529 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700530 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700531 main.FALSE,
532 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800533 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800534 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700535 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700536 expect=main.TRUE,
537 actual=flowCheck,
538 onpass="Flow status is correct!",
539 onfail="Flow status is wrong!" )
540 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700541 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700542 "flows",
543 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800544 tag + "_FlowsBefore",
545 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700546 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700547 "groups",
548 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800549 tag + "_GroupsBefore",
550 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700551
552 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700553 def checkDevices( main, switches, tag="", sleep=10 ):
554 main.step(
555 "Check whether the switches count is equal to %s" % switches )
556 if tag == "":
557 tag = 'CASE%d' % main.CurrentTestCaseNumber
558 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
559 main.FALSE,
560 kwargs={ 'numoswitch': switches},
561 attempts=10,
562 sleep=sleep )
563 utilities.assert_equals( expect=main.TRUE, actual=result,
564 onpass="Device up successful",
565 onfail="Failed to boot up devices?" )
566
567 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800568 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
569 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800570 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800571 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
572 main.FALSE,
573 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800574 attempts=5,
575 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800576 if count == main.FALSE:
577 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800578 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800579 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800580 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800581 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800582 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800583
584 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700585 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800586 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700587 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800588 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
589 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700590 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800591 attempts=5,
592 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800593 if count == main.FALSE:
594 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800595 utilities.assertEquals(
596 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800597 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700598 onpass="Flow count looks correct: " + str( count ) ,
599 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800600
601 @staticmethod
602 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
603 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700604 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800605 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
606 main.FALSE,
607 args=( dpid, groupCount, False, 1),
608 attempts=5,
609 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800610 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800611 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800612 utilities.assertEquals(
613 expect=True,
614 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700615 onpass="Group count looks correct: " + str( count ) ,
616 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800617
618 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700619 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800620
621 for dpid, values in main.count.items():
622 flowCount = values["flows"]
623 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700624 main.log.report( "Check flow count for dpid " + str( dpid ) +
625 ", should be " + str( flowCount ) )
626 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800627
Jon Hall9677ed32018-04-24 11:16:23 -0700628 main.log.report( "Check group count for dpid " + str( dpid ) +
629 ", should be " + str( groupCount ) )
630 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800631
632 return
633
634 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700635 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800636 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800637 '''
You Wangba231e72018-03-01 13:18:21 -0800638 Verify connectivity between hosts according to the ping chart
639 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800640 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800641 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800642 '''
You Wangba231e72018-03-01 13:18:21 -0800643 main.log.report( "Check host connectivity" )
644 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800645 if tag == "":
646 tag = 'CASE%d' % main.CurrentTestCaseNumber
647 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800648 main.log.debug( "Entry in ping chart: %s" % entry )
649 expect = entry[ 'expect' ]
650 if expect == "Unidirectional":
651 # Verify ping from each src host to each dst host
652 src = entry[ 'src' ]
653 dst = entry[ 'dst' ]
654 expect = main.TRUE
655 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
656 if basedOnIp:
657 if ("v4" in src[0]):
658 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
659 utilities.assert_equals( expect=expect, actual=pa,
660 onpass="IPv4 connectivity successfully tested",
661 onfail="IPv4 connectivity failed" )
662 if ("v6" in src[0]):
663 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
664 utilities.assert_equals( expect=expect, actual=pa,
665 onpass="IPv6 connectivity successfully tested",
666 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700667 elif main.physicalNet:
668 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
669 utilities.assert_equals( expect=expect, actual=pa,
670 onpass="IP connectivity successfully tested",
671 onfail="IP connectivity failed" )
672
You Wangba231e72018-03-01 13:18:21 -0800673 else:
674 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
675 utilities.assert_equals( expect=expect, actual=pa,
676 onpass="IP connectivity successfully tested",
677 onfail="IP connectivity failed" )
678 else:
679 # Verify ping between each host pair
680 hosts = entry[ 'hosts' ]
681 try:
682 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
683 except:
684 expect = main.FALSE
685 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
686 if basedOnIp:
687 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800688 pa = utilities.retry( main.Network.pingallHosts,
689 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700690 args=(hosts, ),
691 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800692 attempts=retryAttempts,
693 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800694 utilities.assert_equals( expect=expect, actual=pa,
695 onpass="IPv4 connectivity successfully tested",
696 onfail="IPv4 connectivity failed" )
697 if ("v6" in hosts[0]):
698 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
699 utilities.assert_equals( expect=expect, actual=pa,
700 onpass="IPv6 connectivity successfully tested",
701 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700702 elif main.physicalNet:
Jon Hall06fd0df2021-01-25 15:50:06 -0800703 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy )
Jon Hall43060f62020-06-23 13:13:33 -0700704 utilities.assert_equals( expect=expect, actual=pa,
705 onpass="IP connectivity successfully tested",
706 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800707 else:
You Wangf19d9f42018-02-23 16:34:19 -0800708 pa = main.Network.pingallHosts( hosts )
709 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800710 onpass="IP connectivity successfully tested",
711 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700712 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700713 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700714 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700715 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700716 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800717
718 if dumpflows:
719 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
720 "flows",
721 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800722 tag + "_FlowsOn",
723 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800724 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
725 "groups",
726 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800727 tag + "_GroupsOn",
728 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800729
730 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700731 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700732 """
733 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
734 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
735 Kill a link and verify ONOS can see the proper link change
736 """
Jon Halla604fd42018-05-04 14:27:27 -0700737 if sleep is None:
738 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
739 else:
740 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700741 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700742 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
743 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700744 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
745 onpass="Link down successful",
746 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700747 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700748 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700749 "Waiting %s seconds for link down to be discovered" % sleep )
750 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700751 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700752 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700753 main.FALSE,
754 kwargs={ 'numoswitch': switches,
755 'numolink': links },
756 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700757 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700758 utilities.assert_equals( expect=main.TRUE, actual=topology,
759 onpass="Topology after link down is correct",
760 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700761
762 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700763 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800764 """
765 links = list of links (src, dst) to bring down.
766 """
767
768 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700769 if sleep is None:
770 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
771 else:
772 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800773
774 for end1, end2 in links:
775 main.Network.link( END1=end1, END2=end2, OPTION="down")
776 main.Network.link( END1=end2, END2=end1, OPTION="down")
777
Jon Halla604fd42018-05-04 14:27:27 -0700778 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800779 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700780 "Waiting %s seconds for links down to be discovered" % sleep )
781 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800782
783 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
784 main.FALSE,
785 kwargs={ 'numoswitch': switches,
786 'numolink': linksAfter },
787 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700788 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800789
You Wang2854bce2018-03-30 10:15:32 -0700790 utilities.assert_equals( expect=main.TRUE, actual=topology,
791 onpass="Link batch down successful",
792 onfail="Link batch down failed" )
793
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800794 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700795 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800796 """
797 links = list of link (src, dst) to bring up again.
798 """
799
800 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700801 if sleep is None:
802 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
803 else:
804 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800805
806 for end1, end2 in links:
807 main.Network.link( END1=end1, END2=end2, OPTION="up")
808 main.Network.link( END1=end2, END2=end1, OPTION="up")
809
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800810 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700811 "Waiting %s seconds for links up to be discovered" % sleep )
812 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800813
814 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
815 main.FALSE,
816 kwargs={ 'numoswitch': switches,
817 'numolink': linksAfter },
818 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700819 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800820
You Wang2854bce2018-03-30 10:15:32 -0700821 utilities.assert_equals( expect=main.TRUE, actual=topology,
822 onpass="Link batch up successful",
823 onfail="Link batch up failed" )
824
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800825 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700826 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
827 """
828 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
829 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
830 switches, links: number of expected switches and links after link change, ex.: '4', '6'
831 """
832 if sleep is None:
833 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
834 else:
835 sleep = float( sleep )
836 main.step( "Disable a batch of ports" )
837 for dpid, port in ports:
838 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
839 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
840 time.sleep( sleep )
841 if switches and links:
842 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
843 numolink=links )
844 utilities.assert_equals( expect=main.TRUE, actual=result,
845 onpass="Port down successful",
846 onfail="Port down failed" )
847
848 @staticmethod
849 def enablePortBatch( main, ports, switches, links, sleep=None ):
850 """
851 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
852 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
853 switches, links: number of expected switches and links after link change, ex.: '4', '6'
854 """
855 if sleep is None:
856 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
857 else:
858 sleep = float( sleep )
859 main.step( "Enable a batch of ports" )
860 for dpid, port in ports:
861 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
862 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
863 time.sleep( sleep )
864 if switches and links:
865 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
866 numolink=links )
867 utilities.assert_equals( expect=main.TRUE, actual=result,
868 onpass="Port up successful",
869 onfail="Port up failed" )
870
871 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700872 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700873 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700874 """
875 Params:
876 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700877 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700878 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
879 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
880 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
881 Kill a link and verify ONOS can see the proper link change
882 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700883 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700884 if sleep is None:
885 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
886 else:
887 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700888 result = False
889 count = 0
890 while True:
891 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700892 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800893 main.Network.link( END1=end1, END2=end2, OPTION="up" )
894 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700895 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700896 "Waiting %s seconds for link up to be discovered" % sleep )
897 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700898
You Wangc02d8352018-04-17 16:42:10 -0700899 if portUp:
900 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
901 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700902 main.log.info(
903 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700904 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700905
Jon Halla604fd42018-05-04 14:27:27 -0700906 result = ctrl.CLI.checkStatus( numoswitch=switches,
907 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700908 if count > 5 or result:
909 break
910 utilities.assert_equals( expect=main.TRUE, actual=result,
911 onpass="Link up successful",
912 onfail="Failed to bring link up" )
913
914 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700915 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700916 """
917 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
918 Completely kill a switch and verify ONOS can see the proper change
919 """
Jon Halla604fd42018-05-04 14:27:27 -0700920 if sleep is None:
921 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
922 else:
923 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700924 switch = switch if isinstance( switch, list ) else [ switch ]
925 main.step( "Kill " + str( switch ) )
926 for s in switch:
927 main.log.info( "Stopping " + s )
928 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700929 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700930
931 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700932 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700933 sleep ) )
934 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700935 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700936 main.FALSE,
937 kwargs={ 'numoswitch': switches,
938 'numolink': links },
939 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700940 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700941 utilities.assert_equals( expect=main.TRUE, actual=topology,
942 onpass="Kill switch successful",
943 onfail="Failed to kill switch?" )
944
945 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700946 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700947 """
948 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
949 Recover a switch and verify ONOS can see the proper change
950 """
Jon Halla604fd42018-05-04 14:27:27 -0700951 if sleep is None:
952 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
953 else:
954 sleep = float( sleep )
955 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700956 switch = switch if isinstance( switch, list ) else [ switch ]
957 main.step( "Recovering " + str( switch ) )
958 for s in switch:
959 main.log.info( "Starting " + s )
960 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700961 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700962 sleep ) )
963 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700964 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700965 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700966 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700967 sleep ) )
968 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700969
Devin Lim142b5342017-07-20 15:22:39 -0700970 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700971 main.FALSE,
972 kwargs={ 'numoswitch': switches,
973 'numolink': links },
974 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700975 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700976 utilities.assert_equals( expect=main.TRUE, actual=topology,
977 onpass="Switch recovery successful",
978 onfail="Failed to recover switch?" )
979
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700980 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700981 def killRouter( main, router, sleep=None ):
982 """
983 Kill bgpd process on a quagga router
984 router: name of the router to be killed. E.g. "bgp1"
985 """
986 sleep = float( sleep )
987 main.step( "Kill " + str( router ) )
988 if hasattr( main, 'Mininet1' ):
989 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
990 main.Mininet1.handle.expect( "mininet>" )
991 else:
992 # TODO: support killing router in physical network
993 pass
994 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
995 time.sleep( sleep )
996
997 @staticmethod
998 def recoverRouter( main, router, sleep=None ):
999 """
1000 Restart bgpd process on a quagga router
1001 router: name of the router to be recovered. E.g. "bgp1"
1002 """
1003 sleep = float( sleep )
1004 main.step( "Recovering " + str( router ) )
1005 if hasattr( main, 'Mininet1' ):
1006 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1007 main.Mininet1.handle.expect( "mininet>" )
1008 else:
1009 # TODO: support recovering router in physical network
1010 pass
1011 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1012 time.sleep( sleep )
1013
1014 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001015 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001016 """
1017 Stop Onos-cluster.
1018 Stops Mininet
1019 Copies ONOS log
1020 """
You Wang4cc61912018-08-28 10:10:58 -07001021 from tests.dependencies.utils import Utils
1022 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001023 if not main.persistentSetup:
1024 for ctrl in main.Cluster.active():
1025 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001026 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001027 if hasattr( main, "scapyHosts" ):
1028 scapyResult = main.TRUE
1029 for host in main.scapyHosts:
1030 scapyResult = host.stopScapy() and scapyResult
1031 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1032 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001033 if hasattr( main, 'Mininet1' ):
1034 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1035 else:
1036 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001037 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1038 main.scapyHosts = []
1039
You Wang5da39c82018-04-26 22:55:08 -07001040 if removeHostComponent:
1041 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1042 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001043 if hasattr( main, 'Mininet1' ):
1044 pass
1045 else:
1046 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001047 main.Network.removeHostComponent( host )
1048
You Wang5df1c6d2018-04-06 18:02:02 -07001049 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001050 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001051 else:
1052 main.Network.disconnectInbandHosts()
1053 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001054
You Wang5df1c6d2018-04-06 18:02:02 -07001055 if copyKarafLog:
1056 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001057
Jon Hall627b1572020-12-01 12:01:15 -08001058 if not main.persistentSetup:
1059 for ctrl in main.Cluster.active():
1060 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001061 else:
1062 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001063 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001064
1065 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001066 def verifyNodes( main ):
1067 """
1068 Verifies Each active node in the cluster has an accurate view of other node's and their status
1069
1070 Params:
1071 nodes, integer array with position of the ONOS nodes in the CLIs array
1072 """
1073 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1074 False,
1075 attempts=10,
1076 sleep=10 )
1077 utilities.assert_equals( expect=True, actual=nodeResults,
1078 onpass="Nodes check successful",
1079 onfail="Nodes check NOT successful" )
1080
1081 if not nodeResults:
1082 for ctrl in main.Cluster.runningNodes:
1083 main.log.debug( "{} components not ACTIVE: \n{}".format(
1084 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001085 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001086 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001087 main.cleanAndExit()
1088
1089 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001090 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001091 """
1092 Verifies that the ONOS cluster has an acuurate view of the topology
1093
1094 Params:
1095 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 -08001096 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001097 """
1098 main.step( "Check number of topology elements" )
1099 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1100 main.FALSE,
1101 kwargs={ 'numoswitch': switches,
1102 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001103 'numoctrl': expNodes,
1104 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001105 attempts=10,
1106 sleep=12 )
1107 utilities.assert_equals( expect=main.TRUE, actual=topology,
1108 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001109 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001110
1111 @staticmethod
1112 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001113 """
1114 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1115 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1116 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1117 """
Jon Halla604fd42018-05-04 14:27:27 -07001118 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001119 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001120 if sleep is None:
1121 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1122 else:
1123 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001124
Jon Hall214f88b2020-09-21 10:21:42 -07001125 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001126 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001127 node = main.Cluster.runningNodes[ i ]
1128 if node.inDocker:
1129 killResult = node.server.dockerStop( node.name )
1130 else:
1131 killResult = main.ONOSbench.onosDie( node.ipAddress )
1132 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001133 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001134 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1135 onpass="ONOS instance Killed",
1136 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001137 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001138 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001139 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001140
Devin Lim142b5342017-07-20 15:22:39 -07001141 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001142 Testcaselib.verifyNodes( main )
1143 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001144
1145 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001146 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001147 """
1148 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1149 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1150 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1151 """
Jon Hall3c910162018-03-07 14:42:16 -08001152 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001153 if sleep is None:
1154 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1155 else:
1156 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001157 for i in nodes:
1158 node = main.Cluster.runningNodes[ i ]
1159 if node.inDocker:
1160 main.Cluster.startONOSDockerNode( i )
1161 else:
1162 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001163 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001164 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001165 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001166 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001167 if node.inDocker:
1168 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1169 isUp = isUp and node.CLI.prepareForCLI()
1170 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1171 else:
1172 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001173 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1174 onpass="ONOS service is ready",
1175 onfail="ONOS service did not start properly" )
1176 for i in nodes:
1177 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001178 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001179 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001180 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1181 commandlineTimeout=60,
1182 onosStartTimeout=100 )
1183 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001184 utilities.assert_equals( expect=main.TRUE,
1185 actual=cliResult,
1186 onpass="ONOS CLI is ready",
1187 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001188
Jon Halla604fd42018-05-04 14:27:27 -07001189 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001190 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001191 Testcaselib.verifyNodes( main )
1192 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001193
Devin Lim142b5342017-07-20 15:22:39 -07001194 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001195 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001196 attempts=10,
1197 sleep=12 )
1198 if ready:
1199 ready = main.TRUE
1200 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001201 onpass="ONOS summary command succeded",
1202 onfail="ONOS summary command failed" )
1203 if not ready:
1204 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001205 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001206
1207 @staticmethod
1208 def addHostCfg( main ):
1209 """
1210 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001211 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001212 """
1213 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001214 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001215 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001216 hostCfg = json.load( template )
1217 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1218 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001219 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001220 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1221 subjectClass="hosts",
1222 subjectKey=urllib.quote( mac,
1223 safe='' ),
1224 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001225 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1226 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001227 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001228 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1229 subjectClass="hosts",
1230 subjectKey=urllib.quote( mac,
1231 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001232 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001233 main.pingChart.update( { 'vlan1': { "expect": "True",
1234 "hosts": [ "olt1", "vsg1" ] } } )
1235 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1236 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001237 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1238 vlanId=1,
1239 port1=5,
1240 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001241
1242 @staticmethod
1243 def delHostCfg( main ):
1244 """
1245 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001246 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001247 """
1248 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001249 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001250 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001251 hostCfg = json.load( template )
1252 main.step( "Removing host configuration" )
1253 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001254 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001255 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1256 subjectKey=urllib.quote(
1257 mac,
1258 safe='' ),
1259 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001260 main.step( "Removing configuration" )
1261 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001262 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001263 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1264 subjectKey=urllib.quote(
1265 mac,
1266 safe='' ),
1267 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001268 main.step( "Removing vlan configuration" )
1269 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001270 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1271 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001272
1273 @staticmethod
1274 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1275 """
1276 Verifies IP address assignment from the hosts
1277 """
1278 main.step( "Verify IP address assignment from hosts" )
1279 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001280 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001281 # Find out names of disconnected hosts
1282 disconnectedHosts = []
1283 if hasattr( main, "disconnectedIpv4Hosts" ):
1284 for host in main.disconnectedIpv4Hosts:
1285 disconnectedHosts.append( host )
1286 if hasattr( main, "disconnectedIpv6Hosts" ):
1287 for host in main.disconnectedIpv6Hosts:
1288 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001289 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001290 # Exclude disconnected hosts
1291 if hostName in disconnectedHosts:
1292 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1293 continue
You Wang53dba1e2018-02-02 17:45:44 -08001294 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1295 main.FALSE,
1296 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001297 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001298 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001299 attempts=attempts,
1300 sleep=sleep )
1301 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1302 onpass="Verify network host IP succeded",
1303 onfail="Verify network host IP failed" )
1304
1305 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001306 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001307 """
1308 Verifies host IP address assignment from ONOS
1309 """
1310 main.step( "Verify host IP address assignment in ONOS" )
1311 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001312 # Find out IPs of disconnected hosts
1313 disconnectedIps = []
1314 if hasattr( main, "disconnectedIpv4Hosts" ):
1315 for host in main.disconnectedIpv4Hosts:
1316 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1317 if hasattr( main, "disconnectedIpv6Hosts" ):
1318 for host in main.disconnectedIpv6Hosts:
1319 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001320 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001321 # Exclude disconnected hosts
1322 if ip in disconnectedIps:
1323 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1324 continue
You Wang53dba1e2018-02-02 17:45:44 -08001325 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1326 main.FALSE,
1327 kwargs={ 'hostList': [ hostName ],
1328 'prefix': ip },
1329 attempts=attempts,
1330 sleep=sleep )
1331 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1332 onpass="Verify ONOS host IP succeded",
1333 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001334 if not ipResult and skipOnFail:
1335 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001336 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001337 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001338
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001339 @staticmethod
1340 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1341 """
1342 Description:
1343 Updates interface configuration in ONOS, with given IP and vlan parameters
1344 Required:
1345 * connectPoint: connect point to update configuration
1346 Optional:
1347 * ips: list of IP addresses, combined with '/xx' subnet representation,
1348 corresponding to 'ips' field in the configuration
1349 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1350 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1351 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1352 """
1353 cfg = dict()
1354 cfg[ "ports" ] = dict()
1355 cfg[ "ports" ][ connectPoint ] = dict()
1356 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1357 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1358 if untagged > 0:
1359 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1360 else:
1361 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1362 if native > 0:
1363 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1364
1365 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001366
1367 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001368 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001369 """
1370 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001371 scapyNames: list of names that will be used as component names for scapy hosts
1372 mininetNames: used when scapy host names are different from the host names
1373 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1374 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001375 """
1376 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001377 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1378 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001379 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001380 if hasattr( main, 'Mininet1' ):
1381 main.Scapy.createHostComponent( scapyName )
1382 scapyHandle = getattr( main, scapyName )
1383 if mininetNames:
1384 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1385 else:
1386 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001387 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1388 scapyHandle.mExecDir = "/tmp"
1389 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1390 main.log.debug( "start mn host component in docker" )
1391 scapyHandle.startHostCli( mininetName,
1392 execDir="/tmp",
1393 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1394 else:
1395 main.log.debug( "start mn host component" )
1396 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001397 else:
You Wang0fc21702018-11-02 17:49:18 -07001398 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001399 scapyHandle = getattr( main, scapyName )
1400 scapyHandle.connectInband()
1401 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001402 scapyHandle.startScapy()
1403 scapyHandle.updateSelf()
1404 main.log.debug( scapyHandle.name )
1405 main.log.debug( scapyHandle.hostIp )
1406 main.log.debug( scapyHandle.hostMac )
1407
1408 @staticmethod
1409 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1410 """
1411 Verify unicast traffic by pinging from source hosts to the destination IP
1412 and capturing the packets at the destination host using Scapy.
1413 srcHosts: List of host names to send the ping packets
1414 dstIp: destination IP of the ping packets
1415 dstHost: host that runs Scapy to capture the packets
1416 dstIntf: name of the interface on the destination host
1417 expect: use True if the ping is expected to be captured at destination;
1418 Otherwise False
1419 skipOnFail: skip the rest of this test case if result is not expected
1420 maxRetry: number of retries allowed
1421 """
1422 from tests.dependencies.topology import Topology
1423 try:
1424 main.topo
1425 except ( NameError, AttributeError ):
1426 main.topo = Topology()
1427 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1428 result = main.TRUE
1429 for srcHost in srcHosts:
1430 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1431 expect, maxRetry, True )
1432 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001433 result = main.FALSE
1434 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1435 utilities.assert_equals( expect=main.TRUE,
1436 actual=result,
1437 onpass="Verify traffic to {}: Pass".format( dstIp ),
1438 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1439 if skipOnFail and result != main.TRUE:
1440 Testcaselib.saveOnosDiagnostics( main )
1441 Testcaselib.cleanup( main, copyKarafLog=False )
1442 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001443
1444 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001445 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001446 """
1447 Verify multicast traffic using scapy
1448 """
You Wangc564c6f2018-05-01 15:24:57 -07001449 from tests.dependencies.topology import Topology
1450 try:
1451 main.topo
1452 except ( NameError, AttributeError ):
1453 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001454 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001455 routeData = main.multicastConfig[ routeName ]
1456 srcs = main.mcastRoutes[ routeName ][ "src" ]
1457 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1458 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1459 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001460 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001461 for src in srcs:
1462 srcEntry = routeData[ "src" ][ src ]
1463 for dst in dsts:
1464 dstEntry = routeData[ "dst" ][ dst ]
1465 sender = getattr( main, srcEntry[ "host" ] )
1466 receiver = getattr( main, dstEntry[ "host" ] )
1467 main.Network.addRoute( str( srcEntry[ "host" ] ),
1468 str( routeData[ "group" ] ),
1469 str( srcEntry[ "interface" ] ),
1470 True if routeData[ "ipVersion" ] == 6 else False )
1471 # Build the packet
1472 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1473 if routeData[ "ipVersion" ] == 4:
1474 sender.buildIP( dst=str( routeData[ "group" ] ) )
1475 elif routeData[ "ipVersion" ] == 6:
1476 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1477 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1478 sIface = srcEntry[ "interface" ]
1479 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1480 pktFilter = srcEntry[ "filter" ]
1481 pkt = srcEntry[ "packet" ]
1482 # Send packet and check received packet
1483 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001484 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001485 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001486 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1487 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001488 if not trafficResult:
1489 result = main.FALSE
1490 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1491 dstEntry[ "host" ] ) )
1492 utilities.assert_equals( expect=main.TRUE,
1493 actual=result,
1494 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1495 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001496 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001497 Testcaselib.saveOnosDiagnostics( main )
1498 Testcaselib.cleanup( main, copyKarafLog=False )
1499 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001500
1501 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001502 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001503 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1504 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001505 """
1506 Verify reachability from each host in srcList to each host in dstList
1507 """
1508 from tests.dependencies.topology import Topology
1509 try:
1510 main.topo
1511 except ( NameError, AttributeError ):
1512 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001513 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001514 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001515 utilities.assert_equals( expect=main.TRUE,
1516 actual=pingResult,
1517 onpass="{}: Pass".format( stepMsg ),
1518 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001519 if not pingResult and skipOnFail:
1520 Testcaselib.saveOnosDiagnostics( main )
1521 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1522 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001523
1524 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001525 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001526 """
1527 Verify if the specified host is discovered by ONOS on the given locations
1528 Required:
You Wang85747762018-05-11 15:51:50 -07001529 locationDict: a dictionary that maps host names to expected locations.
1530 locations could be a string or a list.
1531 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001532 Returns:
1533 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1534 """
You Wang85747762018-05-11 15:51:50 -07001535 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1536 result = main.TRUE
1537 for hostName, locations in locationDict.items():
1538 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1539 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1540 if not hostIp:
1541 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1542 if not hostIp:
1543 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1544 result = main.FALSE
1545 continue
1546 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1547 main.FALSE,
1548 args=( hostIp, locations ),
1549 attempts=retry + 1,
1550 sleep=10 )
1551 if not locationResult:
1552 result = main.FALSE
1553 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001554 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001555 onpass="Location verification passed",
1556 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001557
1558 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001559 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001560 """
1561 Move specified host from srcSw to dstSw.
1562 If srcSw and dstSw are same, the host will be moved from current port to
1563 next available port.
1564 Required:
1565 hostName: name of the host. e.g., "h1"
1566 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1567 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1568 gw: ip address of the gateway of the new location
1569 Optional:
1570 macAddr: if specified, change MAC address of the host to the specified MAC address.
1571 prefixLen: prefix length
1572 cfg: port configuration as JSON string
1573 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001574 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001575 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001576 if not hasattr( main, 'Mininet1' ):
1577 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1578 return
1579
You Wang6e5b48e2018-07-23 16:17:38 -07001580 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1581 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1582 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001583 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001584 if cfg:
1585 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1586 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001587 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001588 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001589 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001590
1591 main.Mininet1.discoverHosts( [ hostName, ] )
1592
1593 # Update expectedHost when MAC address is changed.
1594 if macAddr is not None:
1595 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1596 if ipAddr is not None:
1597 for hostName, ip in main.expectedHosts[ "onos" ].items():
1598 if ip == ipAddr:
1599 vlan = hostName.split( "/" )[ -1 ]
1600 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001601 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001602 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001603
1604 @staticmethod
1605 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001606 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001607 """
1608 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1609 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1610 to next available port.
1611 Required:
1612 hostName: name of the host. e.g., "h1"
1613 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1614 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1615 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1616 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1617 gw: ip address of the gateway of the new location
1618 Optional:
1619 macAddr: if specified, change MAC address of the host to the specified MAC address.
1620 prefixLen: prefix length
1621 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001622 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001623 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001624 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001625 if not hasattr( main, 'Mininet1' ):
1626 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1627 return
1628
You Wang6e5b48e2018-07-23 16:17:38 -07001629 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1630 srcSw, srcPairSw, dstSw, dstPairSw ) )
1631 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1632 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1633 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001634 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001635 if cfg:
1636 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1637 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001638 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001639 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001640 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001641
1642 main.Mininet1.discoverHosts( [ hostName, ] )
1643
1644 # Update expectedHost when MAC address is changed.
1645 if macAddr is not None:
1646 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1647 if ipAddr is not None:
1648 for hostName, ip in main.expectedHosts[ "onos" ].items():
1649 if ip == ipAddr:
1650 vlan = hostName.split( "/" )[ -1 ]
1651 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001652 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001653
1654 @staticmethod
1655 def mnDockerSetup( main ):
1656 """
1657 Optionally start and setup docker image for mininet
1658 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001659 try:
1660 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001661
Jon Hall9b0de1f2020-08-24 15:38:04 -07001662 main.log.info( "Creating Mininet Docker" )
1663 handle = main.Mininet1.handle
1664 # build docker image
1665 dockerFilePath = "%s/../dependencies/" % main.testDir
1666 dockerName = "trellis_mininet"
1667 # Stop any leftover container
1668 main.Mininet1.dockerStop( dockerName )
1669 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001670 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001671
Jon Hall9b0de1f2020-08-24 15:38:04 -07001672 confDir = "/tmp/mn_conf/"
1673 # Try to ensure the destination exists
1674 main.log.info( "Create folder for network config files" )
1675 handle.sendline( "rm -rf %s" % confDir )
1676 handle.expect( main.Mininet1.Prompt() )
1677 main.log.debug( handle.before + handle.after )
1678 handle.sendline( "mkdir -p %s" % confDir )
1679 handle.expect( main.Mininet1.Prompt() )
1680 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001681 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1682 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001683 # Make sure permissions are correct
1684 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1685 handle.expect( main.Mininet1.Prompt() )
1686 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1687 handle.expect( main.Mininet1.Prompt() )
1688 main.log.debug( handle.before + handle.after )
1689 # Start docker container
1690 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1691 dockerName,
1692 main.params[ 'MN_DOCKER' ][ 'args' ] )
1693 if runResponse == main.FALSE:
1694 main.log.error( "Docker container already running, aborting test" )
1695 main.cleanup()
1696 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001697
Jon Hall9b0de1f2020-08-24 15:38:04 -07001698 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1699 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001700
Jon Hall9b0de1f2020-08-24 15:38:04 -07001701 # Fow when we create component handles
1702 main.Mininet1.mExecDir = "/tmp"
1703 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1704 main.Mininet1.hostPrompt = "/home/root#"
1705
1706 # For some reason docker isn't doing this
1707 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1708 main.Mininet1.handle.expect( "etc/hosts" )
1709 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1710 except Exception as e:
1711 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001712 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001713
1714 @staticmethod
1715 def mnDockerTeardown( main ):
1716 """
1717 Optionally stop and cleanup docker image for mininet
1718 """
1719
1720 if hasattr( main, 'Mininet1' ):
1721 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001722 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001723
1724 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001725 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001726 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001727 main.Mininet1.sudoRequired = True
1728 except Exception as e:
1729 main.log.error( e )
1730
Jon Hall39570262020-11-17 12:18:19 -08001731 # Save docker logs
1732 copyResult = main.ONOSbench.scp( main.Mininet1,
1733 "/tmp/mn-stratum/*",
1734 main.logdir,
1735 direction="from",
1736 options="-rp" )
1737
1738
Jon Hall43060f62020-06-23 13:13:33 -07001739 @staticmethod
1740 def setOnosConfig( main ):
1741 """
1742 Read and Set onos configurations from the params file
1743 """
1744 main.step( "Set ONOS configurations" )
1745 config = main.params.get( 'ONOS_Configuration' )
1746 if config:
1747 main.log.debug( config )
1748 checkResult = main.TRUE
1749 for component in config:
1750 for setting in config[ component ]:
1751 value = config[ component ][ setting ]
1752 check = main.Cluster.next().setCfg( component, setting, value )
1753 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1754 checkResult = check and checkResult
1755 utilities.assert_equals( expect=main.TRUE,
1756 actual=checkResult,
1757 onpass="Successfully set config",
1758 onfail="Failed to set config" )
1759 else:
1760 main.log.warn( "No configurations were specified to be changed after startup" )
1761
1762 @staticmethod
1763 def setOnosLogLevels( main ):
1764 """
1765 Read and Set onos log levels from the params file
1766 """
1767 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001768 # Get original values incase we want to reset them
1769 ctrl = main.Cluster.active(0)
1770 ctrl.CLI.logList()
1771
Jon Hall43060f62020-06-23 13:13:33 -07001772 logging = True
1773 try:
1774 logs = main.params.get( 'ONOS_Logging', False )
1775 if logs:
1776 for namespace, level in logs.items():
1777 for ctrl in main.Cluster.active():
1778 ctrl.CLI.logSet( level, namespace )
1779 except AttributeError:
1780 logging = False
1781 utilities.assert_equals( expect=True, actual=logging,
1782 onpass="Set log levels",
1783 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001784
1785 @staticmethod
1786 def resetOnosLogLevels( main ):
1787 """
1788 Read and reset onos log levels to a previously read set of values
1789 """
1790 main.step( 'Reset logging levels' )
1791 # Get original values incase we want to reset them
1792 ctrl = main.Cluster.active(0)
1793 currentLevels = ctrl.CLI.logList( saveValues=False )
1794 origLevels = ctrl.CLI.logLevels
1795 toBeSet = {}
1796 for logger, level in currentLevels.iteritems():
1797 if logger not in origLevels:
1798 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1799 else:
1800 oldLevel = origLevels[ logger ]
1801 if level != oldLevel:
1802 toBeSet[ logger ] = oldLevel
1803 logging = True
1804 try:
1805 for logger, level in toBeSet.iteritems():
1806 for ctrl in main.Cluster.active():
1807 ctrl.CLI.logSet( level, logger )
1808 except AttributeError:
1809 logging = False
1810 utilities.assert_equals( expect=True, actual=logging,
1811 onpass="Reset log levels",
1812 onfail="Failed to reset log levels" )