blob: 699370c620fa8a8086239859554e212bf8d3397b [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
You Wang4cc61912018-08-28 10:10:58 -0700368 def connectToPhysicalNetwork( main ):
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 Hall43060f62020-06-23 13:13:33 -0700417 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700418
You Wang84f981d2018-01-12 16:11:50 -0800419 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700420 def saveOnosDiagnostics( main ):
421 """
422 Get onos-diags.tar.gz and save it to the log directory.
423 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
424 """
425 main.log.info( "Collecting onos-diags..." )
426 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
427 main.logdir,
428 "-CASE%d" % main.CurrentTestCaseNumber )
429
430 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700431 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700432 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700433
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700434 main.failures = int( main.params[ 'failures' ] )
435 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700436
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700437 if main.cfgName == '2x2':
438 spine = {}
439 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
440 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
441 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700442
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700443 spine = {}
444 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
445 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
446 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700447
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700448 elif main.cfgName == '4x4':
449 spine = {}
450 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
451 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
452 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700453
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700454 spine = {}
455 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
456 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
457 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700458
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700459 spine = {}
460 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
461 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
462 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700463
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700464 spine = {}
465 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
466 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
467 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700468
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700469 else:
Piera2a7e1b2016-10-04 11:51:43 -0700470 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700471 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800472
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800473 @staticmethod
474 def addStaticOnosRoute( main, subnet, intf):
475 """
476 Adds an ONOS static route with the use route-add command.
477 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800478 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
479
Piera2a7e1b2016-10-04 11:51:43 -0700480 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700481 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700482 """
483 Check number of groups for each subnet on device deviceId and matches
484 it with an expected value. subnetDict is a dictionarty containing values
485 of the type "10.0.1.0/24" : 5.
486 """
You Wangc02f3be2018-05-18 12:14:23 -0700487 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
488 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
489 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700490
You Wangc02f3be2018-05-18 12:14:23 -0700491 result = main.TRUE
492 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700493 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700494 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700495 # this will match the group id that this flow entry points to, for example :
496 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700497 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700498 count = 0
499 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700500 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700501 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700502 if count - 1 != numberInSelect:
503 result = main.FALSE
504 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 ) )
505 utilities.assert_equals( expect=main.TRUE, actual=result,
506 onpass="All bucket numbers are as expected",
507 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700508
509 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900510 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700511 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800512 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900513 if tag == "":
514 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700515 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700516 main.FALSE,
517 kwargs={ 'min': minFlowCount },
518 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800519 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800520 if count == main.FALSE:
521 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700522 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700523 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800524 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700525 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
526 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700527
528 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700529 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700530 main.FALSE,
531 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800532 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800533 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700534 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700535 expect=main.TRUE,
536 actual=flowCheck,
537 onpass="Flow status is correct!",
538 onfail="Flow status is wrong!" )
539 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700540 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700541 "flows",
542 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900543 tag + "_FlowsBefore" )
Devin Lim142b5342017-07-20 15:22:39 -0700544 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700545 "groups",
546 main.logdir,
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900547 tag + "_GroupsBefore" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700548
549 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700550 def checkDevices( main, switches, tag="", sleep=10 ):
551 main.step(
552 "Check whether the switches count is equal to %s" % switches )
553 if tag == "":
554 tag = 'CASE%d' % main.CurrentTestCaseNumber
555 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
556 main.FALSE,
557 kwargs={ 'numoswitch': switches},
558 attempts=10,
559 sleep=sleep )
560 utilities.assert_equals( expect=main.TRUE, actual=result,
561 onpass="Device up successful",
562 onfail="Failed to boot up devices?" )
563
564 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800565 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
566 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800567 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800568 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
569 main.FALSE,
570 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800571 attempts=5,
572 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800573 if count == main.FALSE:
574 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800575 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800576 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800577 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800578 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800579 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800580
581 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700582 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800583 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700584 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800585 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
586 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700587 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800588 attempts=5,
589 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800590 if count == main.FALSE:
591 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800592 utilities.assertEquals(
593 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800594 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700595 onpass="Flow count looks correct: " + str( count ) ,
596 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800597
598 @staticmethod
599 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
600 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700601 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800602 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
603 main.FALSE,
604 args=( dpid, groupCount, False, 1),
605 attempts=5,
606 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800607 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800608 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800609 utilities.assertEquals(
610 expect=True,
611 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700612 onpass="Group count looks correct: " + str( count ) ,
613 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800614
615 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700616 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800617
618 for dpid, values in main.count.items():
619 flowCount = values["flows"]
620 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700621 main.log.report( "Check flow count for dpid " + str( dpid ) +
622 ", should be " + str( flowCount ) )
623 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800624
Jon Hall9677ed32018-04-24 11:16:23 -0700625 main.log.report( "Check group count for dpid " + str( dpid ) +
626 ", should be " + str( groupCount ) )
627 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800628
629 return
630
631 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700632 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
633 sleep=10, retryAttempts=1, skipOnFail=False ):
You Wangf19d9f42018-02-23 16:34:19 -0800634 '''
You Wangba231e72018-03-01 13:18:21 -0800635 Verify connectivity between hosts according to the ping chart
636 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800637 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800638 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800639 '''
You Wangba231e72018-03-01 13:18:21 -0800640 main.log.report( "Check host connectivity" )
641 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800642 if tag == "":
643 tag = 'CASE%d' % main.CurrentTestCaseNumber
644 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800645 main.log.debug( "Entry in ping chart: %s" % entry )
646 expect = entry[ 'expect' ]
647 if expect == "Unidirectional":
648 # Verify ping from each src host to each dst host
649 src = entry[ 'src' ]
650 dst = entry[ 'dst' ]
651 expect = main.TRUE
652 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
653 if basedOnIp:
654 if ("v4" in src[0]):
655 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
656 utilities.assert_equals( expect=expect, actual=pa,
657 onpass="IPv4 connectivity successfully tested",
658 onfail="IPv4 connectivity failed" )
659 if ("v6" in src[0]):
660 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
661 utilities.assert_equals( expect=expect, actual=pa,
662 onpass="IPv6 connectivity successfully tested",
663 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700664 elif main.physicalNet:
665 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
666 utilities.assert_equals( expect=expect, actual=pa,
667 onpass="IP connectivity successfully tested",
668 onfail="IP connectivity failed" )
669
You Wangba231e72018-03-01 13:18:21 -0800670 else:
671 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
672 utilities.assert_equals( expect=expect, actual=pa,
673 onpass="IP connectivity successfully tested",
674 onfail="IP connectivity failed" )
675 else:
676 # Verify ping between each host pair
677 hosts = entry[ 'hosts' ]
678 try:
679 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
680 except:
681 expect = main.FALSE
682 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
683 if basedOnIp:
684 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800685 pa = utilities.retry( main.Network.pingallHosts,
686 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700687 args=(hosts, ),
688 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800689 attempts=retryAttempts,
690 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800691 utilities.assert_equals( expect=expect, actual=pa,
692 onpass="IPv4 connectivity successfully tested",
693 onfail="IPv4 connectivity failed" )
694 if ("v6" in hosts[0]):
695 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
696 utilities.assert_equals( expect=expect, actual=pa,
697 onpass="IPv6 connectivity successfully tested",
698 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700699 elif main.physicalNet:
700 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=True )
701 utilities.assert_equals( expect=expect, actual=pa,
702 onpass="IP connectivity successfully tested",
703 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800704 else:
You Wangf19d9f42018-02-23 16:34:19 -0800705 pa = main.Network.pingallHosts( hosts )
706 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800707 onpass="IP connectivity successfully tested",
708 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700709 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700710 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700711 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700712 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700713 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800714
715 if dumpflows:
716 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
717 "flows",
718 main.logdir,
719 tag + "_FlowsOn" )
720 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
721 "groups",
722 main.logdir,
723 tag + "_GroupsOn" )
724
725 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700726 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700727 """
728 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
729 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
730 Kill a link and verify ONOS can see the proper link change
731 """
Jon Halla604fd42018-05-04 14:27:27 -0700732 if sleep is None:
733 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
734 else:
735 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700736 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700737 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
738 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700739 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
740 onpass="Link down successful",
741 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700742 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700743 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700744 "Waiting %s seconds for link down to be discovered" % sleep )
745 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700746 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700747 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700748 main.FALSE,
749 kwargs={ 'numoswitch': switches,
750 'numolink': links },
751 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700752 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700753 utilities.assert_equals( expect=main.TRUE, actual=topology,
754 onpass="Topology after link down is correct",
755 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700756
757 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700758 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800759 """
760 links = list of links (src, dst) to bring down.
761 """
762
763 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700764 if sleep is None:
765 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
766 else:
767 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800768
769 for end1, end2 in links:
770 main.Network.link( END1=end1, END2=end2, OPTION="down")
771 main.Network.link( END1=end2, END2=end1, OPTION="down")
772
Jon Halla604fd42018-05-04 14:27:27 -0700773 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800774 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700775 "Waiting %s seconds for links down to be discovered" % sleep )
776 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800777
778 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
779 main.FALSE,
780 kwargs={ 'numoswitch': switches,
781 'numolink': linksAfter },
782 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700783 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800784
You Wang2854bce2018-03-30 10:15:32 -0700785 utilities.assert_equals( expect=main.TRUE, actual=topology,
786 onpass="Link batch down successful",
787 onfail="Link batch down failed" )
788
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800789 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700790 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800791 """
792 links = list of link (src, dst) to bring up again.
793 """
794
795 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700796 if sleep is None:
797 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
798 else:
799 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800800
801 for end1, end2 in links:
802 main.Network.link( END1=end1, END2=end2, OPTION="up")
803 main.Network.link( END1=end2, END2=end1, OPTION="up")
804
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800805 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700806 "Waiting %s seconds for links up to be discovered" % sleep )
807 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800808
809 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
810 main.FALSE,
811 kwargs={ 'numoswitch': switches,
812 'numolink': linksAfter },
813 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700814 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800815
You Wang2854bce2018-03-30 10:15:32 -0700816 utilities.assert_equals( expect=main.TRUE, actual=topology,
817 onpass="Link batch up successful",
818 onfail="Link batch up failed" )
819
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800820 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700821 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
822 """
823 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
824 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
825 switches, links: number of expected switches and links after link change, ex.: '4', '6'
826 """
827 if sleep is None:
828 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
829 else:
830 sleep = float( sleep )
831 main.step( "Disable a batch of ports" )
832 for dpid, port in ports:
833 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
834 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
835 time.sleep( sleep )
836 if switches and links:
837 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
838 numolink=links )
839 utilities.assert_equals( expect=main.TRUE, actual=result,
840 onpass="Port down successful",
841 onfail="Port down failed" )
842
843 @staticmethod
844 def enablePortBatch( main, ports, switches, links, sleep=None ):
845 """
846 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
847 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
848 switches, links: number of expected switches and links after link change, ex.: '4', '6'
849 """
850 if sleep is None:
851 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
852 else:
853 sleep = float( sleep )
854 main.step( "Enable a batch of ports" )
855 for dpid, port in ports:
856 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
857 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
858 time.sleep( sleep )
859 if switches and links:
860 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
861 numolink=links )
862 utilities.assert_equals( expect=main.TRUE, actual=result,
863 onpass="Port up successful",
864 onfail="Port up failed" )
865
866 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700867 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700868 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700869 """
870 Params:
871 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700872 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700873 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
874 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
875 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
876 Kill a link and verify ONOS can see the proper link change
877 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700878 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700879 if sleep is None:
880 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
881 else:
882 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700883 result = False
884 count = 0
885 while True:
886 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700887 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800888 main.Network.link( END1=end1, END2=end2, OPTION="up" )
889 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700890 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700891 "Waiting %s seconds for link up to be discovered" % sleep )
892 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700893
You Wangc02d8352018-04-17 16:42:10 -0700894 if portUp:
895 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
896 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700897 main.log.info(
898 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700899 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700900
Jon Halla604fd42018-05-04 14:27:27 -0700901 result = ctrl.CLI.checkStatus( numoswitch=switches,
902 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700903 if count > 5 or result:
904 break
905 utilities.assert_equals( expect=main.TRUE, actual=result,
906 onpass="Link up successful",
907 onfail="Failed to bring link up" )
908
909 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700910 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700911 """
912 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
913 Completely kill a switch and verify ONOS can see the proper change
914 """
Jon Halla604fd42018-05-04 14:27:27 -0700915 if sleep is None:
916 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
917 else:
918 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700919 switch = switch if isinstance( switch, list ) else [ switch ]
920 main.step( "Kill " + str( switch ) )
921 for s in switch:
922 main.log.info( "Stopping " + s )
923 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700924 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700925
926 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700927 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700928 sleep ) )
929 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700930 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700931 main.FALSE,
932 kwargs={ 'numoswitch': switches,
933 'numolink': links },
934 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700935 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700936 utilities.assert_equals( expect=main.TRUE, actual=topology,
937 onpass="Kill switch successful",
938 onfail="Failed to kill switch?" )
939
940 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700941 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700942 """
943 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
944 Recover a switch and verify ONOS can see the proper change
945 """
Jon Halla604fd42018-05-04 14:27:27 -0700946 if sleep is None:
947 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
948 else:
949 sleep = float( sleep )
950 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700951 switch = switch if isinstance( switch, list ) else [ switch ]
952 main.step( "Recovering " + str( switch ) )
953 for s in switch:
954 main.log.info( "Starting " + s )
955 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700956 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700957 sleep ) )
958 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700959 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700960 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700961 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700962 sleep ) )
963 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700964
Devin Lim142b5342017-07-20 15:22:39 -0700965 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700966 main.FALSE,
967 kwargs={ 'numoswitch': switches,
968 'numolink': links },
969 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700970 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700971 utilities.assert_equals( expect=main.TRUE, actual=topology,
972 onpass="Switch recovery successful",
973 onfail="Failed to recover switch?" )
974
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700975 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700976 def killRouter( main, router, sleep=None ):
977 """
978 Kill bgpd process on a quagga router
979 router: name of the router to be killed. E.g. "bgp1"
980 """
981 sleep = float( sleep )
982 main.step( "Kill " + str( router ) )
983 if hasattr( main, 'Mininet1' ):
984 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
985 main.Mininet1.handle.expect( "mininet>" )
986 else:
987 # TODO: support killing router in physical network
988 pass
989 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
990 time.sleep( sleep )
991
992 @staticmethod
993 def recoverRouter( main, router, sleep=None ):
994 """
995 Restart bgpd process on a quagga router
996 router: name of the router to be recovered. E.g. "bgp1"
997 """
998 sleep = float( sleep )
999 main.step( "Recovering " + str( router ) )
1000 if hasattr( main, 'Mininet1' ):
1001 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1002 main.Mininet1.handle.expect( "mininet>" )
1003 else:
1004 # TODO: support recovering router in physical network
1005 pass
1006 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1007 time.sleep( sleep )
1008
1009 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001010 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001011 """
1012 Stop Onos-cluster.
1013 Stops Mininet
1014 Copies ONOS log
1015 """
You Wang4cc61912018-08-28 10:10:58 -07001016 from tests.dependencies.utils import Utils
1017 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001018 if not main.persistentSetup:
1019 for ctrl in main.Cluster.active():
1020 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001021 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001022 if hasattr( main, "scapyHosts" ):
1023 scapyResult = main.TRUE
1024 for host in main.scapyHosts:
1025 scapyResult = host.stopScapy() and scapyResult
1026 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1027 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001028 if hasattr( main, 'Mininet1' ):
1029 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1030 else:
1031 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001032 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1033 main.scapyHosts = []
1034
You Wang5da39c82018-04-26 22:55:08 -07001035 if removeHostComponent:
1036 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1037 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001038 if hasattr( main, 'Mininet1' ):
1039 pass
1040 else:
1041 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001042 main.Network.removeHostComponent( host )
1043
You Wang5df1c6d2018-04-06 18:02:02 -07001044 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001045 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001046 else:
1047 main.Network.disconnectInbandHosts()
1048 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001049
You Wang5df1c6d2018-04-06 18:02:02 -07001050 if copyKarafLog:
1051 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001052
Jon Hall627b1572020-12-01 12:01:15 -08001053 if not main.persistentSetup:
1054 for ctrl in main.Cluster.active():
1055 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001056 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001057
1058 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001059 def verifyNodes( main ):
1060 """
1061 Verifies Each active node in the cluster has an accurate view of other node's and their status
1062
1063 Params:
1064 nodes, integer array with position of the ONOS nodes in the CLIs array
1065 """
1066 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1067 False,
1068 attempts=10,
1069 sleep=10 )
1070 utilities.assert_equals( expect=True, actual=nodeResults,
1071 onpass="Nodes check successful",
1072 onfail="Nodes check NOT successful" )
1073
1074 if not nodeResults:
1075 for ctrl in main.Cluster.runningNodes:
1076 main.log.debug( "{} components not ACTIVE: \n{}".format(
1077 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001078 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001079 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001080 main.cleanAndExit()
1081
1082 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001083 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001084 """
1085 Verifies that the ONOS cluster has an acuurate view of the topology
1086
1087 Params:
1088 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 -08001089 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001090 """
1091 main.step( "Check number of topology elements" )
1092 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1093 main.FALSE,
1094 kwargs={ 'numoswitch': switches,
1095 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001096 'numoctrl': expNodes,
1097 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001098 attempts=10,
1099 sleep=12 )
1100 utilities.assert_equals( expect=main.TRUE, actual=topology,
1101 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001102 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001103
1104 @staticmethod
1105 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001106 """
1107 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1108 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1109 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1110 """
Jon Halla604fd42018-05-04 14:27:27 -07001111 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001112 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001113 if sleep is None:
1114 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1115 else:
1116 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001117
Jon Hall214f88b2020-09-21 10:21:42 -07001118 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001119 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001120 node = main.Cluster.runningNodes[ i ]
1121 if node.inDocker:
1122 killResult = node.server.dockerStop( node.name )
1123 else:
1124 killResult = main.ONOSbench.onosDie( node.ipAddress )
1125 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001126 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001127 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1128 onpass="ONOS instance Killed",
1129 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001130 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001131 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001132 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001133
Devin Lim142b5342017-07-20 15:22:39 -07001134 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001135 Testcaselib.verifyNodes( main )
1136 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001137
1138 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001139 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001140 """
1141 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1142 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1143 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1144 """
Jon Hall3c910162018-03-07 14:42:16 -08001145 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001146 if sleep is None:
1147 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1148 else:
1149 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001150 for i in nodes:
1151 node = main.Cluster.runningNodes[ i ]
1152 if node.inDocker:
1153 main.Cluster.startONOSDockerNode( i )
1154 else:
1155 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001156 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001157 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001158 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001159 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001160 if node.inDocker:
1161 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1162 isUp = isUp and node.CLI.prepareForCLI()
1163 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1164 else:
1165 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001166 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1167 onpass="ONOS service is ready",
1168 onfail="ONOS service did not start properly" )
1169 for i in nodes:
1170 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001171 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001172 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001173 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1174 commandlineTimeout=60,
1175 onosStartTimeout=100 )
1176 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001177 utilities.assert_equals( expect=main.TRUE,
1178 actual=cliResult,
1179 onpass="ONOS CLI is ready",
1180 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001181
Jon Halla604fd42018-05-04 14:27:27 -07001182 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001183 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001184 Testcaselib.verifyNodes( main )
1185 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001186
Devin Lim142b5342017-07-20 15:22:39 -07001187 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001188 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001189 attempts=10,
1190 sleep=12 )
1191 if ready:
1192 ready = main.TRUE
1193 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001194 onpass="ONOS summary command succeded",
1195 onfail="ONOS summary command failed" )
1196 if not ready:
1197 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001198 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001199
1200 @staticmethod
1201 def addHostCfg( main ):
1202 """
1203 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001204 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001205 """
1206 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001207 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001208 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001209 hostCfg = json.load( template )
1210 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1211 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001212 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001213 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1214 subjectClass="hosts",
1215 subjectKey=urllib.quote( mac,
1216 safe='' ),
1217 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001218 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1219 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001220 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001221 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1222 subjectClass="hosts",
1223 subjectKey=urllib.quote( mac,
1224 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001225 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001226 main.pingChart.update( { 'vlan1': { "expect": "True",
1227 "hosts": [ "olt1", "vsg1" ] } } )
1228 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1229 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001230 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1231 vlanId=1,
1232 port1=5,
1233 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001234
1235 @staticmethod
1236 def delHostCfg( main ):
1237 """
1238 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001239 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001240 """
1241 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001242 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001243 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001244 hostCfg = json.load( template )
1245 main.step( "Removing host configuration" )
1246 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001247 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001248 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1249 subjectKey=urllib.quote(
1250 mac,
1251 safe='' ),
1252 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001253 main.step( "Removing configuration" )
1254 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001255 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001256 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1257 subjectKey=urllib.quote(
1258 mac,
1259 safe='' ),
1260 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001261 main.step( "Removing vlan configuration" )
1262 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001263 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1264 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001265
1266 @staticmethod
1267 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1268 """
1269 Verifies IP address assignment from the hosts
1270 """
1271 main.step( "Verify IP address assignment from hosts" )
1272 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001273 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001274 # Find out names of disconnected hosts
1275 disconnectedHosts = []
1276 if hasattr( main, "disconnectedIpv4Hosts" ):
1277 for host in main.disconnectedIpv4Hosts:
1278 disconnectedHosts.append( host )
1279 if hasattr( main, "disconnectedIpv6Hosts" ):
1280 for host in main.disconnectedIpv6Hosts:
1281 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001282 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001283 # Exclude disconnected hosts
1284 if hostName in disconnectedHosts:
1285 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1286 continue
You Wang53dba1e2018-02-02 17:45:44 -08001287 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1288 main.FALSE,
1289 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001290 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001291 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001292 attempts=attempts,
1293 sleep=sleep )
1294 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1295 onpass="Verify network host IP succeded",
1296 onfail="Verify network host IP failed" )
1297
1298 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001299 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001300 """
1301 Verifies host IP address assignment from ONOS
1302 """
1303 main.step( "Verify host IP address assignment in ONOS" )
1304 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001305 # Find out IPs of disconnected hosts
1306 disconnectedIps = []
1307 if hasattr( main, "disconnectedIpv4Hosts" ):
1308 for host in main.disconnectedIpv4Hosts:
1309 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1310 if hasattr( main, "disconnectedIpv6Hosts" ):
1311 for host in main.disconnectedIpv6Hosts:
1312 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001313 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001314 # Exclude disconnected hosts
1315 if ip in disconnectedIps:
1316 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1317 continue
You Wang53dba1e2018-02-02 17:45:44 -08001318 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1319 main.FALSE,
1320 kwargs={ 'hostList': [ hostName ],
1321 'prefix': ip },
1322 attempts=attempts,
1323 sleep=sleep )
1324 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1325 onpass="Verify ONOS host IP succeded",
1326 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001327 if not ipResult and skipOnFail:
1328 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001329 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001330 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001331
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001332 @staticmethod
1333 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1334 """
1335 Description:
1336 Updates interface configuration in ONOS, with given IP and vlan parameters
1337 Required:
1338 * connectPoint: connect point to update configuration
1339 Optional:
1340 * ips: list of IP addresses, combined with '/xx' subnet representation,
1341 corresponding to 'ips' field in the configuration
1342 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1343 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1344 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1345 """
1346 cfg = dict()
1347 cfg[ "ports" ] = dict()
1348 cfg[ "ports" ][ connectPoint ] = dict()
1349 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1350 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1351 if untagged > 0:
1352 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1353 else:
1354 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1355 if native > 0:
1356 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1357
1358 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001359
1360 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001361 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001362 """
1363 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001364 scapyNames: list of names that will be used as component names for scapy hosts
1365 mininetNames: used when scapy host names are different from the host names
1366 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1367 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001368 """
1369 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001370 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1371 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001372 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001373 if hasattr( main, 'Mininet1' ):
1374 main.Scapy.createHostComponent( scapyName )
1375 scapyHandle = getattr( main, scapyName )
1376 if mininetNames:
1377 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1378 else:
1379 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001380 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1381 scapyHandle.mExecDir = "/tmp"
1382 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1383 main.log.debug( "start mn host component in docker" )
1384 scapyHandle.startHostCli( mininetName,
1385 execDir="/tmp",
1386 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1387 else:
1388 main.log.debug( "start mn host component" )
1389 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001390 else:
You Wang0fc21702018-11-02 17:49:18 -07001391 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001392 scapyHandle = getattr( main, scapyName )
1393 scapyHandle.connectInband()
1394 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001395 scapyHandle.startScapy()
1396 scapyHandle.updateSelf()
1397 main.log.debug( scapyHandle.name )
1398 main.log.debug( scapyHandle.hostIp )
1399 main.log.debug( scapyHandle.hostMac )
1400
1401 @staticmethod
1402 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1403 """
1404 Verify unicast traffic by pinging from source hosts to the destination IP
1405 and capturing the packets at the destination host using Scapy.
1406 srcHosts: List of host names to send the ping packets
1407 dstIp: destination IP of the ping packets
1408 dstHost: host that runs Scapy to capture the packets
1409 dstIntf: name of the interface on the destination host
1410 expect: use True if the ping is expected to be captured at destination;
1411 Otherwise False
1412 skipOnFail: skip the rest of this test case if result is not expected
1413 maxRetry: number of retries allowed
1414 """
1415 from tests.dependencies.topology import Topology
1416 try:
1417 main.topo
1418 except ( NameError, AttributeError ):
1419 main.topo = Topology()
1420 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1421 result = main.TRUE
1422 for srcHost in srcHosts:
1423 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1424 expect, maxRetry, True )
1425 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001426 result = main.FALSE
1427 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1428 utilities.assert_equals( expect=main.TRUE,
1429 actual=result,
1430 onpass="Verify traffic to {}: Pass".format( dstIp ),
1431 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1432 if skipOnFail and result != main.TRUE:
1433 Testcaselib.saveOnosDiagnostics( main )
1434 Testcaselib.cleanup( main, copyKarafLog=False )
1435 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001436
1437 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001438 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001439 """
1440 Verify multicast traffic using scapy
1441 """
You Wangc564c6f2018-05-01 15:24:57 -07001442 from tests.dependencies.topology import Topology
1443 try:
1444 main.topo
1445 except ( NameError, AttributeError ):
1446 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001447 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001448 routeData = main.multicastConfig[ routeName ]
1449 srcs = main.mcastRoutes[ routeName ][ "src" ]
1450 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1451 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1452 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001453 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001454 for src in srcs:
1455 srcEntry = routeData[ "src" ][ src ]
1456 for dst in dsts:
1457 dstEntry = routeData[ "dst" ][ dst ]
1458 sender = getattr( main, srcEntry[ "host" ] )
1459 receiver = getattr( main, dstEntry[ "host" ] )
1460 main.Network.addRoute( str( srcEntry[ "host" ] ),
1461 str( routeData[ "group" ] ),
1462 str( srcEntry[ "interface" ] ),
1463 True if routeData[ "ipVersion" ] == 6 else False )
1464 # Build the packet
1465 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1466 if routeData[ "ipVersion" ] == 4:
1467 sender.buildIP( dst=str( routeData[ "group" ] ) )
1468 elif routeData[ "ipVersion" ] == 6:
1469 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1470 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1471 sIface = srcEntry[ "interface" ]
1472 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1473 pktFilter = srcEntry[ "filter" ]
1474 pkt = srcEntry[ "packet" ]
1475 # Send packet and check received packet
1476 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001477 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001478 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001479 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1480 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001481 if not trafficResult:
1482 result = main.FALSE
1483 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1484 dstEntry[ "host" ] ) )
1485 utilities.assert_equals( expect=main.TRUE,
1486 actual=result,
1487 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1488 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001489 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001490 Testcaselib.saveOnosDiagnostics( main )
1491 Testcaselib.cleanup( main, copyKarafLog=False )
1492 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001493
1494 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001495 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001496 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1497 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001498 """
1499 Verify reachability from each host in srcList to each host in dstList
1500 """
1501 from tests.dependencies.topology import Topology
1502 try:
1503 main.topo
1504 except ( NameError, AttributeError ):
1505 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001506 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001507 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001508 utilities.assert_equals( expect=main.TRUE,
1509 actual=pingResult,
1510 onpass="{}: Pass".format( stepMsg ),
1511 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001512 if not pingResult and skipOnFail:
1513 Testcaselib.saveOnosDiagnostics( main )
1514 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1515 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001516
1517 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001518 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001519 """
1520 Verify if the specified host is discovered by ONOS on the given locations
1521 Required:
You Wang85747762018-05-11 15:51:50 -07001522 locationDict: a dictionary that maps host names to expected locations.
1523 locations could be a string or a list.
1524 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001525 Returns:
1526 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1527 """
You Wang85747762018-05-11 15:51:50 -07001528 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1529 result = main.TRUE
1530 for hostName, locations in locationDict.items():
1531 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1532 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1533 if not hostIp:
1534 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1535 if not hostIp:
1536 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1537 result = main.FALSE
1538 continue
1539 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1540 main.FALSE,
1541 args=( hostIp, locations ),
1542 attempts=retry + 1,
1543 sleep=10 )
1544 if not locationResult:
1545 result = main.FALSE
1546 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001547 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001548 onpass="Location verification passed",
1549 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001550
1551 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001552 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001553 """
1554 Move specified host from srcSw to dstSw.
1555 If srcSw and dstSw are same, the host will be moved from current port to
1556 next available port.
1557 Required:
1558 hostName: name of the host. e.g., "h1"
1559 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1560 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1561 gw: ip address of the gateway of the new location
1562 Optional:
1563 macAddr: if specified, change MAC address of the host to the specified MAC address.
1564 prefixLen: prefix length
1565 cfg: port configuration as JSON string
1566 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001567 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001568 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001569 if not hasattr( main, 'Mininet1' ):
1570 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1571 return
1572
You Wang6e5b48e2018-07-23 16:17:38 -07001573 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1574 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1575 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001576 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001577 if cfg:
1578 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1579 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001580 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001581 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001582 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001583
1584 main.Mininet1.discoverHosts( [ hostName, ] )
1585
1586 # Update expectedHost when MAC address is changed.
1587 if macAddr is not None:
1588 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1589 if ipAddr is not None:
1590 for hostName, ip in main.expectedHosts[ "onos" ].items():
1591 if ip == ipAddr:
1592 vlan = hostName.split( "/" )[ -1 ]
1593 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001594 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001595 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001596
1597 @staticmethod
1598 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001599 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001600 """
1601 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1602 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1603 to next available port.
1604 Required:
1605 hostName: name of the host. e.g., "h1"
1606 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1607 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1608 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1609 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1610 gw: ip address of the gateway of the new location
1611 Optional:
1612 macAddr: if specified, change MAC address of the host to the specified MAC address.
1613 prefixLen: prefix length
1614 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001615 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001616 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001617 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001618 if not hasattr( main, 'Mininet1' ):
1619 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1620 return
1621
You Wang6e5b48e2018-07-23 16:17:38 -07001622 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1623 srcSw, srcPairSw, dstSw, dstPairSw ) )
1624 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1625 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1626 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001627 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001628 if cfg:
1629 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1630 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001631 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001632 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001633 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001634
1635 main.Mininet1.discoverHosts( [ hostName, ] )
1636
1637 # Update expectedHost when MAC address is changed.
1638 if macAddr is not None:
1639 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1640 if ipAddr is not None:
1641 for hostName, ip in main.expectedHosts[ "onos" ].items():
1642 if ip == ipAddr:
1643 vlan = hostName.split( "/" )[ -1 ]
1644 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001645 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001646
1647 @staticmethod
1648 def mnDockerSetup( main ):
1649 """
1650 Optionally start and setup docker image for mininet
1651 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001652 try:
1653 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001654
Jon Hall9b0de1f2020-08-24 15:38:04 -07001655 main.log.info( "Creating Mininet Docker" )
1656 handle = main.Mininet1.handle
1657 # build docker image
1658 dockerFilePath = "%s/../dependencies/" % main.testDir
1659 dockerName = "trellis_mininet"
1660 # Stop any leftover container
1661 main.Mininet1.dockerStop( dockerName )
1662 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001663 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001664
Jon Hall9b0de1f2020-08-24 15:38:04 -07001665 confDir = "/tmp/mn_conf/"
1666 # Try to ensure the destination exists
1667 main.log.info( "Create folder for network config files" )
1668 handle.sendline( "rm -rf %s" % confDir )
1669 handle.expect( main.Mininet1.Prompt() )
1670 main.log.debug( handle.before + handle.after )
1671 handle.sendline( "mkdir -p %s" % confDir )
1672 handle.expect( main.Mininet1.Prompt() )
1673 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001674 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1675 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001676 # Make sure permissions are correct
1677 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1678 handle.expect( main.Mininet1.Prompt() )
1679 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1680 handle.expect( main.Mininet1.Prompt() )
1681 main.log.debug( handle.before + handle.after )
1682 # Start docker container
1683 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1684 dockerName,
1685 main.params[ 'MN_DOCKER' ][ 'args' ] )
1686 if runResponse == main.FALSE:
1687 main.log.error( "Docker container already running, aborting test" )
1688 main.cleanup()
1689 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001690
Jon Hall9b0de1f2020-08-24 15:38:04 -07001691 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1692 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001693
Jon Hall9b0de1f2020-08-24 15:38:04 -07001694 # Fow when we create component handles
1695 main.Mininet1.mExecDir = "/tmp"
1696 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1697 main.Mininet1.hostPrompt = "/home/root#"
1698
1699 # For some reason docker isn't doing this
1700 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1701 main.Mininet1.handle.expect( "etc/hosts" )
1702 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1703 except Exception as e:
1704 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001705 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001706
1707 @staticmethod
1708 def mnDockerTeardown( main ):
1709 """
1710 Optionally stop and cleanup docker image for mininet
1711 """
1712
1713 if hasattr( main, 'Mininet1' ):
1714 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001715 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001716
1717 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001718 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001719 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001720 main.Mininet1.sudoRequired = True
1721 except Exception as e:
1722 main.log.error( e )
1723
Jon Hall39570262020-11-17 12:18:19 -08001724 # Save docker logs
1725 copyResult = main.ONOSbench.scp( main.Mininet1,
1726 "/tmp/mn-stratum/*",
1727 main.logdir,
1728 direction="from",
1729 options="-rp" )
1730
1731
Jon Hall43060f62020-06-23 13:13:33 -07001732 @staticmethod
1733 def setOnosConfig( main ):
1734 """
1735 Read and Set onos configurations from the params file
1736 """
1737 main.step( "Set ONOS configurations" )
1738 config = main.params.get( 'ONOS_Configuration' )
1739 if config:
1740 main.log.debug( config )
1741 checkResult = main.TRUE
1742 for component in config:
1743 for setting in config[ component ]:
1744 value = config[ component ][ setting ]
1745 check = main.Cluster.next().setCfg( component, setting, value )
1746 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1747 checkResult = check and checkResult
1748 utilities.assert_equals( expect=main.TRUE,
1749 actual=checkResult,
1750 onpass="Successfully set config",
1751 onfail="Failed to set config" )
1752 else:
1753 main.log.warn( "No configurations were specified to be changed after startup" )
1754
1755 @staticmethod
1756 def setOnosLogLevels( main ):
1757 """
1758 Read and Set onos log levels from the params file
1759 """
1760 main.step( 'Set logging levels' )
1761 logging = True
1762 try:
1763 logs = main.params.get( 'ONOS_Logging', False )
1764 if logs:
1765 for namespace, level in logs.items():
1766 for ctrl in main.Cluster.active():
1767 ctrl.CLI.logSet( level, namespace )
1768 except AttributeError:
1769 logging = False
1770 utilities.assert_equals( expect=True, actual=logging,
1771 onpass="Set log levels",
1772 onfail="Failed to set log levels" )