blob: eedd8d51a7d5a576dabea920a02ced47b06f5aef [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 )
Siddesh167bc882021-03-23 21:03:43 +000099 @staticmethod
100 def getTopo():
101 topo = dict()
102 # TODO: Check minFlowCount of leaf for BMv2 switch
103 # (number of spine switch, number of leaf switch, dual-homed, description, minFlowCount - leaf (OvS), minFlowCount - leaf (BMv2))
104 topo[ '0x1' ] = { 'spines': 0,'leaves': 1, 'mininetArgs': "--leaf=1 --spine=0", 'dual-homed': False,'description': 'single ToR','minFlow-OvS': 28,'minFlow-Stratum': 20,'dual-linked': False }
105 topo[ '0x2' ] = {'spines': 0,'leaves': 2, 'mininetArgs': "--leaf=2 --spine=0", 'dual-homed': True,'description': 'dual-homed ToR','minFlow-OvS': 37,'minFlow-Stratum': 37,'dual-linked': True }
106 topo[ '2x2' ] = {'spines': 2,'leaves': 2, 'mininetArgs': "--leaf=2 --spine=2", 'dual-homed': False,'description': '2x2 leaf-spine topology','minFlow-OvS': 37,'minFlow-Stratum': 32,'dual-linked': False }
107 topo[ '2x2 dual-linked' ] = {'spines': 2, 'leaves': 2, 'mininetArgs': "--leaf=2 --spine=2", 'dual-homed': False,'description': '2x2 aether dual-linked','minFlow-OvS': 37,'minFlow-Stratum': 32,'dual-linked': True }
108 topo[ '2x4' ] = { 'spines':2,'leaves': 4, 'mininetArgs': "--leaf=4 --spine=2",'dual-homed': True,'description': '2x4 dual-homed leaf-spine topology','minFlow-OvS': 53,'minFlow-Stratum': 53, 'dual-linked': False }
109 topo[ '4x4' ] = {'spines': 4,'leaves': 4, 'dual-homed': True, 'description': '4x4 dual-homed leaf-spine topology','dual-linked': True }
110 topo[ '2x2staging' ] = { 'spines': 2, 'leaves': 2,'dual-homed': True, 'description': '2x2 leaf-spine topology', 'minFlowOvS': 37, 'minFlow-Stratum': 32 }
111 return topo
Jon Hall1efcb3f2016-08-23 13:42:15 -0700112 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800113 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
114 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700115 """
116 - Set up cell
117 - Create cell file
118 - Set cell file
119 - Verify cell file
120 - Kill ONOS process
121 - Uninstall ONOS cluster
122 - Verify ONOS start up
123 - Install ONOS cluster
124 - Connect to cli
125 """
Siddesh13492972021-03-12 21:09:32 +0000126 # Check params file for local repos on external apps. cd to repos, run the build command, potentially move o/p file to a different location
127
Jon Hall1efcb3f2016-08-23 13:42:15 -0700128 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700129 try:
Jon Hall627b1572020-12-01 12:01:15 -0800130 if not main.persistentSetup and main.params.get( 'EXTERNAL_APPS' ):
Jon Hall43060f62020-06-23 13:13:33 -0700131 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800132 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700133 main.ONOSbench.onosFetchApp( url )
134 if not main.apps:
135 main.log.error( "App list is empty" )
136 except Exception as e:
137 main.log.debug( e )
138 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800139 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
140 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700141 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800142 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800143 skipPack=skipPackage,
144 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800145 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700146 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700147 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800148 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700149 attempts=10 )
150 if ready:
151 ready = main.TRUE
152 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700153 onpass="ONOS summary command succeded",
154 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700155 if not ready:
156 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700157 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700158
You Wang5bf49592020-07-08 18:47:46 -0700159 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700160 appInstallResult = main.TRUE
161 if main.trellisOar:
162 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700163 if main.t3Oar:
164 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
165 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
166 onpass="SR app installation succeded",
167 onfail="SR app installation failed" )
168 if not appInstallResult:
169 main.cleanAndExit()
170
Jon Hall43060f62020-06-23 13:13:33 -0700171 # FIXME: move to somewhere else?
172 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
173 # TODO: Support other pipeconfs/making this configurable
174 if switchPrefix == "tofino":
175 # It seems to take some time for the pipeconfs to be loaded
176 ctrl = main.Cluster.next()
177 for i in range( 120 ):
178 try:
179 main.log.debug( "Checking to see if pipeconfs are loaded" )
180 output = ctrl.CLI.sendline( "pipeconfs" )
181 if "tofino" in output:
182 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
183 break
184 time.sleep( 1 )
185 except Exception as e:
186 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700187
Jon Hall627b1572020-12-01 12:01:15 -0800188 # Install segmentrouting and t3 app
189 appInstallResult = main.TRUE
190 if not main.persistentSetup:
191 if main.trellisOar:
192 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
193 if main.t3Oar:
194 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
195 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
196 onpass="SR app installation succeded",
197 onfail="SR app installation failed" )
198 if not appInstallResult:
199 main.cleanAndExit()
200
Jon Hall43060f62020-06-23 13:13:33 -0700201 Testcaselib.setOnosLogLevels( main )
202 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700203
Jon Hall1efcb3f2016-08-23 13:42:15 -0700204 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800205 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700206 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
207 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800208
209 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700210 def loadJson( main, suffix='' ):
211 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
212 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800213 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
214
215 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700216 def loadXconnects( main, suffix='' ):
217 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
218 main.cfgName, suffix ) ) as cfg:
219 for xconnect in json.load( cfg ).get('xconnects'):
220 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
221
222 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800223 def loadChart( main ):
224 try:
225 with open( "%s%s.chart" % ( main.configPath + main.forChart,
226 main.cfgName ) ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700227 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800228 except IOError:
229 main.log.warn( "No chart file found." )
230
231 @staticmethod
232 def loadHost( main ):
233 with open( "%s%s.host" % ( main.configPath + main.forHost,
234 main.cfgName ) ) as host:
235 main.expectedHosts = json.load( host )
236
237 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800238 def loadSwitchFailureChart( main ):
239 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
240 main.cfgName ) ) as sfc:
241 main.switchFailureChart = json.load( sfc )
242
243 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800244 def loadLinkFailureChart( main ):
245 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700246 main.cfgName ) ) as lfc:
247 main.linkFailureChart = json.load( lfc )
248
249 @staticmethod
250 def loadMulticastConfig( main ):
251 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
252 main.cfgName ) ) as cfg:
253 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800254
255 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700256 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700257 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800258 copyResult = main.ONOSbench.scp( main.Mininet1,
259 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700260 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800261 direction="to" )
262 if main.topologyLib:
263 for lib in main.topologyLib.split(","):
264 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
265 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700266 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800267 direction="to" )
268 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700269 import re
270 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
271 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700272 destDir = "~/"
273 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
274 destDir = "/tmp/mn_conf/"
275 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800276 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700277 # Update zebra configurations with correct ONOS instance IP
278 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
279 ip = controllerIPs[ index ]
280 index = ( index + 1 ) % len( controllerIPs )
281 with open( main.configPath + main.forConfig + conf ) as f:
282 s = f.read()
283 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
284 with open( main.configPath + main.forConfig + conf, "w" ) as f:
285 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800286 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800287 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700288 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800289 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800290 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700291 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800292 main.Mininet1.home + "custom",
293 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700294
295 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
296 # move the config files into home
297 main.Mininet1.handle.sendline( "cp config/* . " )
298 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
299 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
300 main.Mininet1.handle.sendline( "ls -al " )
301 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
302 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
303
You Wangd87b2312018-01-30 12:47:17 -0800304 stepResult = copyResult
305 utilities.assert_equals( expect=main.TRUE,
306 actual=stepResult,
307 onpass="Successfully copied topo files",
308 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700309 if main.stratumRoot:
310 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700311 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700312 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700313 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700314 main.topology = topology
315 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700316 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700317 stepResult = topoResult
318 utilities.assert_equals( expect=main.TRUE,
319 actual=stepResult,
320 onpass="Successfully loaded topology",
321 onfail="Failed to load topology" )
322 # Exit if topology did not load properly
323 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700324 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700325 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700326 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700327 # Upload the net-cfg file created for each switch
328 filename = "onos-netcfg.json"
329 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700330 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700331 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
332 path = "/tmp/mn-stratum/%s/" % switch
333 dstPath = "/tmp/"
334 dstFileName = "%s-onos-netcfg.json" % switch
335 main.ONOSbench1.scp( main.Mininet1,
336 "%s%s" % ( path, filename ),
337 "%s%s" % ( dstPath, dstFileName ),
338 "from" )
339 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 -0700340 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700341 # Configure managementAddress
342 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
343 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
344 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
345 # Configure device id
346 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
347 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
348 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
349 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800350 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 -0700351 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
352 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700353 node = main.Cluster.active(0)
354 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
355 dstPath,
356 dstFileName,
357 user=node.REST.user_name,
358 password=node.REST.pwd )
359 # Stop test if we fail to push switch netcfg
360 utilities.assert_equals( expect=main.TRUE,
361 actual=switchNetCfg,
362 onpass="Successfully pushed switch netcfg",
363 onfail="Failed to configure switches in onos" )
364 if not switchNetCfg:
365 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700366 # Make sure hosts make some noise
367 Testcaselib.discoverHosts( main )
368
369 @staticmethod
370 def discoverHosts( main ):
371 # TODO add option to only select specific hosts
372 if hasattr( main, "Mininet1" ):
373 network = main.Mininet1
374 elif hasattr( main, "NetworkBench" ):
375 network = main.NetworkBench
376 else:
377 main.log.warn( "Could not find component for test network, skipping host discovery" )
378 return
379 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700380
381 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800382 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800383 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700384 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800385 topoResult = main.NetworkBench.connectToNet()
386 stepResult = topoResult
387 utilities.assert_equals( expect=main.TRUE,
388 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700389 onpass="Successfully connected to topology",
390 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800391 # Exit if topology did not load properly
392 if not topoResult:
393 main.cleanAndExit()
394
Jon Hall627b1572020-12-01 12:01:15 -0800395 if not main.persistentSetup:
396 # Perform any optional setup
397 for switch in main.NetworkBench.switches:
398 if hasattr( switch, "setup" ):
399 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700400
Jon Hall627b1572020-12-01 12:01:15 -0800401 main.step( "Assign switches to controllers." )
402 stepResult = main.TRUE
403 switches = main.NetworkBench.getSwitches()
404 pool = []
405 for name in switches.keys():
406 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
407 # e.g. push onos net-cfg for stratum switches
408 thread = main.Thread( target=main.NetworkBench.assignSwController,
409 name="assignSwitchToController",
410 args=[ name, main.Cluster.getIps(), '6653' ] )
411 pool.append( thread )
412 thread.start()
413 for thread in pool:
414 thread.join( 300 )
415 if not thread.result:
416 stepResult = main.FALSE
417 utilities.assert_equals( expect=main.TRUE,
418 actual=stepResult,
419 onpass="Successfully assign switches to controllers",
420 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800421
You Wang4cc61912018-08-28 10:10:58 -0700422 # Check devices
423 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700424 # Connecting to hosts that only have data plane connectivity
425 main.step( "Connecting inband hosts" )
426 stepResult = main.Network.connectInbandHosts()
427 utilities.assert_equals( expect=main.TRUE,
428 actual=stepResult,
429 onpass="Successfully connected inband hosts",
430 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800431 if hostDiscovery:
432 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700433
You Wang84f981d2018-01-12 16:11:50 -0800434 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700435 def saveOnosDiagnostics( main ):
436 """
437 Get onos-diags.tar.gz and save it to the log directory.
438 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
439 """
440 main.log.info( "Collecting onos-diags..." )
441 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress for ctrl in main.Cluster.runningNodes],
442 main.logdir,
443 "-CASE%d" % main.CurrentTestCaseNumber )
444
445 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700446 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700447 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700448
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700449 main.failures = int( main.params[ 'failures' ] )
450 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700451
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700452 if main.cfgName == '2x2':
453 spine = {}
454 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
455 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
456 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700457
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700458 spine = {}
459 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
460 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
461 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700462
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700463 elif main.cfgName == '4x4':
464 spine = {}
465 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
466 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
467 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700468
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700469 spine = {}
470 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
471 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
472 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700473
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700474 spine = {}
475 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
476 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
477 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700478
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700479 spine = {}
480 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
481 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
482 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700483
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700484 else:
Piera2a7e1b2016-10-04 11:51:43 -0700485 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700486 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800487
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800488 @staticmethod
489 def addStaticOnosRoute( main, subnet, intf):
490 """
491 Adds an ONOS static route with the use route-add command.
492 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800493 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
494
Piera2a7e1b2016-10-04 11:51:43 -0700495 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700496 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700497 """
498 Check number of groups for each subnet on device deviceId and matches
499 it with an expected value. subnetDict is a dictionarty containing values
500 of the type "10.0.1.0/24" : 5.
501 """
You Wangc02f3be2018-05-18 12:14:23 -0700502 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
503 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
504 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700505
You Wangc02f3be2018-05-18 12:14:23 -0700506 result = main.TRUE
507 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700508 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700509 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700510 # this will match the group id that this flow entry points to, for example :
511 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700512 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700513 count = 0
514 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700515 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700516 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700517 if count - 1 != numberInSelect:
518 result = main.FALSE
519 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 ) )
520 utilities.assert_equals( expect=main.TRUE, actual=result,
521 onpass="All bucket numbers are as expected",
522 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700523
524 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900525 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700526 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800527 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900528 if tag == "":
529 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700530 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700531 main.FALSE,
532 kwargs={ 'min': minFlowCount },
533 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800534 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800535 if count == main.FALSE:
536 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700537 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700538 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800539 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700540 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
541 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700542
543 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700544 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700545 main.FALSE,
546 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800547 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800548 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700549 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700550 expect=main.TRUE,
551 actual=flowCheck,
552 onpass="Flow status is correct!",
553 onfail="Flow status is wrong!" )
554 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700555 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700556 "flows",
557 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800558 tag + "_FlowsBefore",
559 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700560 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700561 "groups",
562 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800563 tag + "_GroupsBefore",
564 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700565
566 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700567 def checkDevices( main, switches, tag="", sleep=10 ):
568 main.step(
569 "Check whether the switches count is equal to %s" % switches )
570 if tag == "":
571 tag = 'CASE%d' % main.CurrentTestCaseNumber
572 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
573 main.FALSE,
574 kwargs={ 'numoswitch': switches},
575 attempts=10,
576 sleep=sleep )
577 utilities.assert_equals( expect=main.TRUE, actual=result,
578 onpass="Device up successful",
579 onfail="Failed to boot up devices?" )
580
581 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800582 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
583 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800584 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800585 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
586 main.FALSE,
587 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -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 )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800592 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800593 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800594 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800595 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800596 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800597
598 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700599 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800600 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700601 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800602 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
603 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700604 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800605 attempts=5,
606 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800607 if count == main.FALSE:
608 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800609 utilities.assertEquals(
610 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800611 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700612 onpass="Flow count looks correct: " + str( count ) ,
613 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800614
615 @staticmethod
616 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
617 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700618 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800619 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
620 main.FALSE,
621 args=( dpid, groupCount, False, 1),
622 attempts=5,
623 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800624 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800625 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800626 utilities.assertEquals(
627 expect=True,
628 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700629 onpass="Group count looks correct: " + str( count ) ,
630 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800631
632 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700633 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800634
635 for dpid, values in main.count.items():
636 flowCount = values["flows"]
637 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700638 main.log.report( "Check flow count for dpid " + str( dpid ) +
639 ", should be " + str( flowCount ) )
640 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800641
Jon Hall9677ed32018-04-24 11:16:23 -0700642 main.log.report( "Check group count for dpid " + str( dpid ) +
643 ", should be " + str( groupCount ) )
644 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800645
646 return
647
648 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700649 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800650 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800651 '''
You Wangba231e72018-03-01 13:18:21 -0800652 Verify connectivity between hosts according to the ping chart
653 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800654 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800655 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800656 '''
You Wangba231e72018-03-01 13:18:21 -0800657 main.log.report( "Check host connectivity" )
658 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800659 if tag == "":
660 tag = 'CASE%d' % main.CurrentTestCaseNumber
661 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800662 main.log.debug( "Entry in ping chart: %s" % entry )
663 expect = entry[ 'expect' ]
664 if expect == "Unidirectional":
665 # Verify ping from each src host to each dst host
666 src = entry[ 'src' ]
667 dst = entry[ 'dst' ]
668 expect = main.TRUE
669 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
670 if basedOnIp:
671 if ("v4" in src[0]):
672 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
673 utilities.assert_equals( expect=expect, actual=pa,
674 onpass="IPv4 connectivity successfully tested",
675 onfail="IPv4 connectivity failed" )
676 if ("v6" in src[0]):
677 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
678 utilities.assert_equals( expect=expect, actual=pa,
679 onpass="IPv6 connectivity successfully tested",
680 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700681 elif main.physicalNet:
682 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
683 utilities.assert_equals( expect=expect, actual=pa,
684 onpass="IP connectivity successfully tested",
685 onfail="IP connectivity failed" )
686
You Wangba231e72018-03-01 13:18:21 -0800687 else:
688 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
689 utilities.assert_equals( expect=expect, actual=pa,
690 onpass="IP connectivity successfully tested",
691 onfail="IP connectivity failed" )
692 else:
693 # Verify ping between each host pair
694 hosts = entry[ 'hosts' ]
695 try:
696 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
697 except:
698 expect = main.FALSE
699 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
700 if basedOnIp:
701 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800702 pa = utilities.retry( main.Network.pingallHosts,
703 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700704 args=(hosts, ),
705 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800706 attempts=retryAttempts,
707 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800708 utilities.assert_equals( expect=expect, actual=pa,
709 onpass="IPv4 connectivity successfully tested",
710 onfail="IPv4 connectivity failed" )
711 if ("v6" in hosts[0]):
712 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
713 utilities.assert_equals( expect=expect, actual=pa,
714 onpass="IPv6 connectivity successfully tested",
715 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700716 elif main.physicalNet:
Jon Hall06fd0df2021-01-25 15:50:06 -0800717 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy )
Jon Hall43060f62020-06-23 13:13:33 -0700718 utilities.assert_equals( expect=expect, actual=pa,
719 onpass="IP connectivity successfully tested",
720 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800721 else:
You Wangf19d9f42018-02-23 16:34:19 -0800722 pa = main.Network.pingallHosts( hosts )
723 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800724 onpass="IP connectivity successfully tested",
725 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700726 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700727 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700728 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700729 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700730 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800731
732 if dumpflows:
733 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
734 "flows",
735 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800736 tag + "_FlowsOn",
737 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800738 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
739 "groups",
740 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800741 tag + "_GroupsOn",
742 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800743
744 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700745 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700746 """
747 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
748 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
749 Kill a link and verify ONOS can see the proper link change
750 """
Jon Halla604fd42018-05-04 14:27:27 -0700751 if sleep is None:
752 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
753 else:
754 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700755 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700756 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
757 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700758 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
759 onpass="Link down successful",
760 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700761 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700762 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700763 "Waiting %s seconds for link down to be discovered" % sleep )
764 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700765 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700766 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700767 main.FALSE,
768 kwargs={ 'numoswitch': switches,
769 'numolink': links },
770 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700771 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700772 utilities.assert_equals( expect=main.TRUE, actual=topology,
773 onpass="Topology after link down is correct",
774 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700775
776 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700777 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800778 """
779 links = list of links (src, dst) to bring down.
780 """
781
782 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700783 if sleep is None:
784 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
785 else:
786 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800787
788 for end1, end2 in links:
789 main.Network.link( END1=end1, END2=end2, OPTION="down")
790 main.Network.link( END1=end2, END2=end1, OPTION="down")
791
Jon Halla604fd42018-05-04 14:27:27 -0700792 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800793 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700794 "Waiting %s seconds for links down to be discovered" % sleep )
795 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800796
797 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
798 main.FALSE,
799 kwargs={ 'numoswitch': switches,
800 'numolink': linksAfter },
801 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700802 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800803
You Wang2854bce2018-03-30 10:15:32 -0700804 utilities.assert_equals( expect=main.TRUE, actual=topology,
805 onpass="Link batch down successful",
806 onfail="Link batch down failed" )
807
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800808 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700809 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800810 """
811 links = list of link (src, dst) to bring up again.
812 """
813
814 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700815 if sleep is None:
816 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
817 else:
818 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800819
820 for end1, end2 in links:
821 main.Network.link( END1=end1, END2=end2, OPTION="up")
822 main.Network.link( END1=end2, END2=end1, OPTION="up")
823
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800824 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700825 "Waiting %s seconds for links up to be discovered" % sleep )
826 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800827
828 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
829 main.FALSE,
830 kwargs={ 'numoswitch': switches,
831 'numolink': linksAfter },
832 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700833 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800834
You Wang2854bce2018-03-30 10:15:32 -0700835 utilities.assert_equals( expect=main.TRUE, actual=topology,
836 onpass="Link batch up successful",
837 onfail="Link batch up failed" )
838
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800839 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700840 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
841 """
842 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
843 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
844 switches, links: number of expected switches and links after link change, ex.: '4', '6'
845 """
846 if sleep is None:
847 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
848 else:
849 sleep = float( sleep )
850 main.step( "Disable a batch of ports" )
851 for dpid, port in ports:
852 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
853 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
854 time.sleep( sleep )
855 if switches and links:
856 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
857 numolink=links )
858 utilities.assert_equals( expect=main.TRUE, actual=result,
859 onpass="Port down successful",
860 onfail="Port down failed" )
861
862 @staticmethod
863 def enablePortBatch( main, ports, switches, links, sleep=None ):
864 """
865 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
866 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
867 switches, links: number of expected switches and links after link change, ex.: '4', '6'
868 """
869 if sleep is None:
870 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
871 else:
872 sleep = float( sleep )
873 main.step( "Enable a batch of ports" )
874 for dpid, port in ports:
875 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
876 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
877 time.sleep( sleep )
878 if switches and links:
879 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
880 numolink=links )
881 utilities.assert_equals( expect=main.TRUE, actual=result,
882 onpass="Port up successful",
883 onfail="Port up failed" )
884
885 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700886 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700887 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700888 """
889 Params:
890 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700891 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700892 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
893 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
894 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
895 Kill a link and verify ONOS can see the proper link change
896 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700897 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700898 if sleep is None:
899 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
900 else:
901 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700902 result = False
903 count = 0
904 while True:
905 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700906 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800907 main.Network.link( END1=end1, END2=end2, OPTION="up" )
908 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700909 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700910 "Waiting %s seconds for link up to be discovered" % sleep )
911 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700912
You Wangc02d8352018-04-17 16:42:10 -0700913 if portUp:
914 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
915 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700916 main.log.info(
917 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700918 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700919
Jon Halla604fd42018-05-04 14:27:27 -0700920 result = ctrl.CLI.checkStatus( numoswitch=switches,
921 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700922 if count > 5 or result:
923 break
924 utilities.assert_equals( expect=main.TRUE, actual=result,
925 onpass="Link up successful",
926 onfail="Failed to bring link up" )
927
928 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700929 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700930 """
931 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
932 Completely kill a switch and verify ONOS can see the proper change
933 """
Jon Halla604fd42018-05-04 14:27:27 -0700934 if sleep is None:
935 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
936 else:
937 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700938 switch = switch if isinstance( switch, list ) else [ switch ]
939 main.step( "Kill " + str( switch ) )
940 for s in switch:
941 main.log.info( "Stopping " + s )
942 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700943 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700944
945 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700946 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700947 sleep ) )
948 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700949 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700950 main.FALSE,
951 kwargs={ 'numoswitch': switches,
952 'numolink': links },
953 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700954 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700955 utilities.assert_equals( expect=main.TRUE, actual=topology,
956 onpass="Kill switch successful",
957 onfail="Failed to kill switch?" )
958
959 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700960 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700961 """
962 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
963 Recover a switch and verify ONOS can see the proper change
964 """
Jon Halla604fd42018-05-04 14:27:27 -0700965 if sleep is None:
966 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
967 else:
968 sleep = float( sleep )
969 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700970 switch = switch if isinstance( switch, list ) else [ switch ]
971 main.step( "Recovering " + str( switch ) )
972 for s in switch:
973 main.log.info( "Starting " + s )
974 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700975 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700976 sleep ) )
977 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700978 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700979 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700980 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700981 sleep ) )
982 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700983
Devin Lim142b5342017-07-20 15:22:39 -0700984 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700985 main.FALSE,
986 kwargs={ 'numoswitch': switches,
987 'numolink': links },
988 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700989 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700990 utilities.assert_equals( expect=main.TRUE, actual=topology,
991 onpass="Switch recovery successful",
992 onfail="Failed to recover switch?" )
993
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700994 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700995 def killRouter( main, router, sleep=None ):
996 """
997 Kill bgpd process on a quagga router
998 router: name of the router to be killed. E.g. "bgp1"
999 """
1000 sleep = float( sleep )
1001 main.step( "Kill " + str( router ) )
1002 if hasattr( main, 'Mininet1' ):
1003 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
1004 main.Mininet1.handle.expect( "mininet>" )
1005 else:
1006 # TODO: support killing router in physical network
1007 pass
1008 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
1009 time.sleep( sleep )
1010
1011 @staticmethod
1012 def recoverRouter( main, router, sleep=None ):
1013 """
1014 Restart bgpd process on a quagga router
1015 router: name of the router to be recovered. E.g. "bgp1"
1016 """
1017 sleep = float( sleep )
1018 main.step( "Recovering " + str( router ) )
1019 if hasattr( main, 'Mininet1' ):
1020 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1021 main.Mininet1.handle.expect( "mininet>" )
1022 else:
1023 # TODO: support recovering router in physical network
1024 pass
1025 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1026 time.sleep( sleep )
1027
1028 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001029 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001030 """
1031 Stop Onos-cluster.
1032 Stops Mininet
1033 Copies ONOS log
1034 """
You Wang4cc61912018-08-28 10:10:58 -07001035 from tests.dependencies.utils import Utils
1036 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001037 if not main.persistentSetup:
1038 for ctrl in main.Cluster.active():
1039 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001040 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001041 if hasattr( main, "scapyHosts" ):
1042 scapyResult = main.TRUE
1043 for host in main.scapyHosts:
1044 scapyResult = host.stopScapy() and scapyResult
1045 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1046 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001047 if hasattr( main, 'Mininet1' ):
1048 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1049 else:
1050 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001051 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1052 main.scapyHosts = []
1053
You Wang5da39c82018-04-26 22:55:08 -07001054 if removeHostComponent:
1055 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1056 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001057 if hasattr( main, 'Mininet1' ):
1058 pass
1059 else:
1060 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001061 main.Network.removeHostComponent( host )
1062
You Wang5df1c6d2018-04-06 18:02:02 -07001063 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001064 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001065 else:
1066 main.Network.disconnectInbandHosts()
1067 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001068
You Wang5df1c6d2018-04-06 18:02:02 -07001069 if copyKarafLog:
1070 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001071
Jon Hall627b1572020-12-01 12:01:15 -08001072 if not main.persistentSetup:
1073 for ctrl in main.Cluster.active():
1074 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001075 else:
1076 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001077 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001078
1079 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001080 def verifyNodes( main ):
1081 """
1082 Verifies Each active node in the cluster has an accurate view of other node's and their status
1083
1084 Params:
1085 nodes, integer array with position of the ONOS nodes in the CLIs array
1086 """
1087 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1088 False,
1089 attempts=10,
1090 sleep=10 )
1091 utilities.assert_equals( expect=True, actual=nodeResults,
1092 onpass="Nodes check successful",
1093 onfail="Nodes check NOT successful" )
1094
1095 if not nodeResults:
1096 for ctrl in main.Cluster.runningNodes:
1097 main.log.debug( "{} components not ACTIVE: \n{}".format(
1098 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001099 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001100 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001101 main.cleanAndExit()
1102
1103 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001104 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001105 """
1106 Verifies that the ONOS cluster has an acuurate view of the topology
1107
1108 Params:
1109 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 -08001110 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001111 """
1112 main.step( "Check number of topology elements" )
1113 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1114 main.FALSE,
1115 kwargs={ 'numoswitch': switches,
1116 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001117 'numoctrl': expNodes,
1118 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001119 attempts=10,
1120 sleep=12 )
1121 utilities.assert_equals( expect=main.TRUE, actual=topology,
1122 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001123 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001124
1125 @staticmethod
1126 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001127 """
1128 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1129 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1130 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1131 """
Jon Halla604fd42018-05-04 14:27:27 -07001132 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001133 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001134 if sleep is None:
1135 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1136 else:
1137 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001138
Jon Hall214f88b2020-09-21 10:21:42 -07001139 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001140 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001141 node = main.Cluster.runningNodes[ i ]
1142 if node.inDocker:
1143 killResult = node.server.dockerStop( node.name )
1144 else:
1145 killResult = main.ONOSbench.onosDie( node.ipAddress )
1146 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001147 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001148 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1149 onpass="ONOS instance Killed",
1150 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001151 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001152 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001153 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001154
Devin Lim142b5342017-07-20 15:22:39 -07001155 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001156 Testcaselib.verifyNodes( main )
1157 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001158
1159 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001160 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001161 """
1162 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1163 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1164 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1165 """
Jon Hall3c910162018-03-07 14:42:16 -08001166 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001167 if sleep is None:
1168 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1169 else:
1170 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001171 for i in nodes:
1172 node = main.Cluster.runningNodes[ i ]
1173 if node.inDocker:
1174 main.Cluster.startONOSDockerNode( i )
1175 else:
1176 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001177 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001178 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001179 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001180 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001181 if node.inDocker:
1182 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1183 isUp = isUp and node.CLI.prepareForCLI()
1184 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1185 else:
1186 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001187 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1188 onpass="ONOS service is ready",
1189 onfail="ONOS service did not start properly" )
1190 for i in nodes:
1191 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001192 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001193 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001194 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1195 commandlineTimeout=60,
1196 onosStartTimeout=100 )
1197 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001198 utilities.assert_equals( expect=main.TRUE,
1199 actual=cliResult,
1200 onpass="ONOS CLI is ready",
1201 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001202
Jon Halla604fd42018-05-04 14:27:27 -07001203 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001204 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001205 Testcaselib.verifyNodes( main )
1206 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001207
Devin Lim142b5342017-07-20 15:22:39 -07001208 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001209 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001210 attempts=10,
1211 sleep=12 )
1212 if ready:
1213 ready = main.TRUE
1214 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001215 onpass="ONOS summary command succeded",
1216 onfail="ONOS summary command failed" )
1217 if not ready:
1218 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001219 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001220
1221 @staticmethod
1222 def addHostCfg( main ):
1223 """
1224 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001225 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001226 """
1227 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001228 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001229 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001230 hostCfg = json.load( template )
1231 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1232 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001233 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001234 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1235 subjectClass="hosts",
1236 subjectKey=urllib.quote( mac,
1237 safe='' ),
1238 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001239 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1240 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001241 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001242 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1243 subjectClass="hosts",
1244 subjectKey=urllib.quote( mac,
1245 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001246 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001247 main.pingChart.update( { 'vlan1': { "expect": "True",
1248 "hosts": [ "olt1", "vsg1" ] } } )
1249 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1250 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001251 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1252 vlanId=1,
1253 port1=5,
1254 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001255
1256 @staticmethod
1257 def delHostCfg( main ):
1258 """
1259 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001260 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001261 """
1262 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001263 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001264 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001265 hostCfg = json.load( template )
1266 main.step( "Removing host configuration" )
1267 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001268 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001269 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1270 subjectKey=urllib.quote(
1271 mac,
1272 safe='' ),
1273 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001274 main.step( "Removing configuration" )
1275 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001276 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001277 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1278 subjectKey=urllib.quote(
1279 mac,
1280 safe='' ),
1281 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001282 main.step( "Removing vlan configuration" )
1283 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001284 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1285 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001286
1287 @staticmethod
1288 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1289 """
1290 Verifies IP address assignment from the hosts
1291 """
1292 main.step( "Verify IP address assignment from hosts" )
1293 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001294 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001295 # Find out names of disconnected hosts
1296 disconnectedHosts = []
1297 if hasattr( main, "disconnectedIpv4Hosts" ):
1298 for host in main.disconnectedIpv4Hosts:
1299 disconnectedHosts.append( host )
1300 if hasattr( main, "disconnectedIpv6Hosts" ):
1301 for host in main.disconnectedIpv6Hosts:
1302 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001303 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001304 # Exclude disconnected hosts
1305 if hostName in disconnectedHosts:
1306 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1307 continue
You Wang53dba1e2018-02-02 17:45:44 -08001308 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1309 main.FALSE,
1310 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001311 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001312 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001313 attempts=attempts,
1314 sleep=sleep )
1315 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1316 onpass="Verify network host IP succeded",
1317 onfail="Verify network host IP failed" )
1318
1319 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001320 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001321 """
1322 Verifies host IP address assignment from ONOS
1323 """
1324 main.step( "Verify host IP address assignment in ONOS" )
1325 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001326 # Find out IPs of disconnected hosts
1327 disconnectedIps = []
1328 if hasattr( main, "disconnectedIpv4Hosts" ):
1329 for host in main.disconnectedIpv4Hosts:
1330 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1331 if hasattr( main, "disconnectedIpv6Hosts" ):
1332 for host in main.disconnectedIpv6Hosts:
1333 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001334 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001335 # Exclude disconnected hosts
1336 if ip in disconnectedIps:
1337 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1338 continue
You Wang53dba1e2018-02-02 17:45:44 -08001339 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1340 main.FALSE,
1341 kwargs={ 'hostList': [ hostName ],
1342 'prefix': ip },
1343 attempts=attempts,
1344 sleep=sleep )
1345 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1346 onpass="Verify ONOS host IP succeded",
1347 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001348 if not ipResult and skipOnFail:
1349 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001350 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001351 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001352
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001353 @staticmethod
1354 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1355 """
1356 Description:
1357 Updates interface configuration in ONOS, with given IP and vlan parameters
1358 Required:
1359 * connectPoint: connect point to update configuration
1360 Optional:
1361 * ips: list of IP addresses, combined with '/xx' subnet representation,
1362 corresponding to 'ips' field in the configuration
1363 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1364 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1365 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1366 """
1367 cfg = dict()
1368 cfg[ "ports" ] = dict()
1369 cfg[ "ports" ][ connectPoint ] = dict()
1370 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1371 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1372 if untagged > 0:
1373 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1374 else:
1375 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1376 if native > 0:
1377 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1378
1379 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001380
1381 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001382 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001383 """
1384 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001385 scapyNames: list of names that will be used as component names for scapy hosts
1386 mininetNames: used when scapy host names are different from the host names
1387 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1388 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001389 """
1390 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001391 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1392 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001393 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001394 if hasattr( main, 'Mininet1' ):
1395 main.Scapy.createHostComponent( scapyName )
1396 scapyHandle = getattr( main, scapyName )
1397 if mininetNames:
1398 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1399 else:
1400 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001401 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1402 scapyHandle.mExecDir = "/tmp"
1403 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1404 main.log.debug( "start mn host component in docker" )
1405 scapyHandle.startHostCli( mininetName,
1406 execDir="/tmp",
1407 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1408 else:
1409 main.log.debug( "start mn host component" )
1410 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001411 else:
You Wang0fc21702018-11-02 17:49:18 -07001412 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001413 scapyHandle = getattr( main, scapyName )
1414 scapyHandle.connectInband()
1415 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001416 scapyHandle.startScapy()
1417 scapyHandle.updateSelf()
1418 main.log.debug( scapyHandle.name )
1419 main.log.debug( scapyHandle.hostIp )
1420 main.log.debug( scapyHandle.hostMac )
1421
1422 @staticmethod
1423 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1424 """
1425 Verify unicast traffic by pinging from source hosts to the destination IP
1426 and capturing the packets at the destination host using Scapy.
1427 srcHosts: List of host names to send the ping packets
1428 dstIp: destination IP of the ping packets
1429 dstHost: host that runs Scapy to capture the packets
1430 dstIntf: name of the interface on the destination host
1431 expect: use True if the ping is expected to be captured at destination;
1432 Otherwise False
1433 skipOnFail: skip the rest of this test case if result is not expected
1434 maxRetry: number of retries allowed
1435 """
1436 from tests.dependencies.topology import Topology
1437 try:
1438 main.topo
1439 except ( NameError, AttributeError ):
1440 main.topo = Topology()
1441 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1442 result = main.TRUE
1443 for srcHost in srcHosts:
1444 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1445 expect, maxRetry, True )
1446 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001447 result = main.FALSE
1448 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1449 utilities.assert_equals( expect=main.TRUE,
1450 actual=result,
1451 onpass="Verify traffic to {}: Pass".format( dstIp ),
1452 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1453 if skipOnFail and result != main.TRUE:
1454 Testcaselib.saveOnosDiagnostics( main )
1455 Testcaselib.cleanup( main, copyKarafLog=False )
1456 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001457
1458 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001459 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001460 """
1461 Verify multicast traffic using scapy
1462 """
You Wangc564c6f2018-05-01 15:24:57 -07001463 from tests.dependencies.topology import Topology
1464 try:
1465 main.topo
1466 except ( NameError, AttributeError ):
1467 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001468 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001469 routeData = main.multicastConfig[ routeName ]
1470 srcs = main.mcastRoutes[ routeName ][ "src" ]
1471 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1472 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1473 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001474 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001475 for src in srcs:
1476 srcEntry = routeData[ "src" ][ src ]
1477 for dst in dsts:
1478 dstEntry = routeData[ "dst" ][ dst ]
1479 sender = getattr( main, srcEntry[ "host" ] )
1480 receiver = getattr( main, dstEntry[ "host" ] )
1481 main.Network.addRoute( str( srcEntry[ "host" ] ),
1482 str( routeData[ "group" ] ),
1483 str( srcEntry[ "interface" ] ),
1484 True if routeData[ "ipVersion" ] == 6 else False )
1485 # Build the packet
1486 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1487 if routeData[ "ipVersion" ] == 4:
1488 sender.buildIP( dst=str( routeData[ "group" ] ) )
1489 elif routeData[ "ipVersion" ] == 6:
1490 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1491 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1492 sIface = srcEntry[ "interface" ]
1493 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1494 pktFilter = srcEntry[ "filter" ]
1495 pkt = srcEntry[ "packet" ]
1496 # Send packet and check received packet
1497 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001498 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001499 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001500 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1501 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001502 if not trafficResult:
1503 result = main.FALSE
1504 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1505 dstEntry[ "host" ] ) )
1506 utilities.assert_equals( expect=main.TRUE,
1507 actual=result,
1508 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1509 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001510 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001511 Testcaselib.saveOnosDiagnostics( main )
1512 Testcaselib.cleanup( main, copyKarafLog=False )
1513 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001514
1515 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001516 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001517 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1518 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001519 """
1520 Verify reachability from each host in srcList to each host in dstList
1521 """
1522 from tests.dependencies.topology import Topology
1523 try:
1524 main.topo
1525 except ( NameError, AttributeError ):
1526 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001527 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001528 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001529 utilities.assert_equals( expect=main.TRUE,
1530 actual=pingResult,
1531 onpass="{}: Pass".format( stepMsg ),
1532 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001533 if not pingResult and skipOnFail:
1534 Testcaselib.saveOnosDiagnostics( main )
1535 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1536 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001537
1538 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001539 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001540 """
1541 Verify if the specified host is discovered by ONOS on the given locations
1542 Required:
You Wang85747762018-05-11 15:51:50 -07001543 locationDict: a dictionary that maps host names to expected locations.
1544 locations could be a string or a list.
1545 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001546 Returns:
1547 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1548 """
You Wang85747762018-05-11 15:51:50 -07001549 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1550 result = main.TRUE
1551 for hostName, locations in locationDict.items():
1552 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1553 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1554 if not hostIp:
1555 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1556 if not hostIp:
1557 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1558 result = main.FALSE
1559 continue
1560 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1561 main.FALSE,
1562 args=( hostIp, locations ),
1563 attempts=retry + 1,
1564 sleep=10 )
1565 if not locationResult:
1566 result = main.FALSE
1567 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001568 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001569 onpass="Location verification passed",
1570 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001571
1572 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001573 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001574 """
1575 Move specified host from srcSw to dstSw.
1576 If srcSw and dstSw are same, the host will be moved from current port to
1577 next available port.
1578 Required:
1579 hostName: name of the host. e.g., "h1"
1580 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1581 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1582 gw: ip address of the gateway of the new location
1583 Optional:
1584 macAddr: if specified, change MAC address of the host to the specified MAC address.
1585 prefixLen: prefix length
1586 cfg: port configuration as JSON string
1587 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001588 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001589 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001590 if not hasattr( main, 'Mininet1' ):
1591 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1592 return
1593
You Wang6e5b48e2018-07-23 16:17:38 -07001594 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1595 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1596 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001597 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001598 if cfg:
1599 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1600 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001601 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001602 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001603 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001604
1605 main.Mininet1.discoverHosts( [ hostName, ] )
1606
1607 # Update expectedHost when MAC address is changed.
1608 if macAddr is not None:
1609 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1610 if ipAddr is not None:
1611 for hostName, ip in main.expectedHosts[ "onos" ].items():
1612 if ip == ipAddr:
1613 vlan = hostName.split( "/" )[ -1 ]
1614 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001615 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001616 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001617
1618 @staticmethod
1619 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001620 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001621 """
1622 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1623 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1624 to next available port.
1625 Required:
1626 hostName: name of the host. e.g., "h1"
1627 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1628 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1629 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1630 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1631 gw: ip address of the gateway of the new location
1632 Optional:
1633 macAddr: if specified, change MAC address of the host to the specified MAC address.
1634 prefixLen: prefix length
1635 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001636 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001637 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001638 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001639 if not hasattr( main, 'Mininet1' ):
1640 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1641 return
1642
You Wang6e5b48e2018-07-23 16:17:38 -07001643 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1644 srcSw, srcPairSw, dstSw, dstPairSw ) )
1645 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1646 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1647 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001648 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001649 if cfg:
1650 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1651 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001652 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001653 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001654 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001655
1656 main.Mininet1.discoverHosts( [ hostName, ] )
1657
1658 # Update expectedHost when MAC address is changed.
1659 if macAddr is not None:
1660 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1661 if ipAddr is not None:
1662 for hostName, ip in main.expectedHosts[ "onos" ].items():
1663 if ip == ipAddr:
1664 vlan = hostName.split( "/" )[ -1 ]
1665 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001666 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001667
1668 @staticmethod
1669 def mnDockerSetup( main ):
1670 """
1671 Optionally start and setup docker image for mininet
1672 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001673 try:
1674 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001675
Jon Hall9b0de1f2020-08-24 15:38:04 -07001676 main.log.info( "Creating Mininet Docker" )
1677 handle = main.Mininet1.handle
1678 # build docker image
1679 dockerFilePath = "%s/../dependencies/" % main.testDir
1680 dockerName = "trellis_mininet"
1681 # Stop any leftover container
1682 main.Mininet1.dockerStop( dockerName )
1683 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001684 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001685
Jon Hall9b0de1f2020-08-24 15:38:04 -07001686 confDir = "/tmp/mn_conf/"
1687 # Try to ensure the destination exists
1688 main.log.info( "Create folder for network config files" )
1689 handle.sendline( "rm -rf %s" % confDir )
1690 handle.expect( main.Mininet1.Prompt() )
1691 main.log.debug( handle.before + handle.after )
1692 handle.sendline( "mkdir -p %s" % confDir )
1693 handle.expect( main.Mininet1.Prompt() )
1694 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001695 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1696 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001697 # Make sure permissions are correct
1698 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1699 handle.expect( main.Mininet1.Prompt() )
1700 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1701 handle.expect( main.Mininet1.Prompt() )
1702 main.log.debug( handle.before + handle.after )
1703 # Start docker container
1704 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1705 dockerName,
1706 main.params[ 'MN_DOCKER' ][ 'args' ] )
1707 if runResponse == main.FALSE:
1708 main.log.error( "Docker container already running, aborting test" )
1709 main.cleanup()
1710 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001711
Jon Hall9b0de1f2020-08-24 15:38:04 -07001712 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1713 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001714
Jon Hall9b0de1f2020-08-24 15:38:04 -07001715 # Fow when we create component handles
1716 main.Mininet1.mExecDir = "/tmp"
1717 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1718 main.Mininet1.hostPrompt = "/home/root#"
1719
1720 # For some reason docker isn't doing this
1721 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1722 main.Mininet1.handle.expect( "etc/hosts" )
1723 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1724 except Exception as e:
1725 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001726 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001727
1728 @staticmethod
1729 def mnDockerTeardown( main ):
1730 """
1731 Optionally stop and cleanup docker image for mininet
1732 """
1733
1734 if hasattr( main, 'Mininet1' ):
1735 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001736 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001737
1738 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001739 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001740 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001741 main.Mininet1.sudoRequired = True
1742 except Exception as e:
1743 main.log.error( e )
1744
Jon Hall39570262020-11-17 12:18:19 -08001745 # Save docker logs
1746 copyResult = main.ONOSbench.scp( main.Mininet1,
1747 "/tmp/mn-stratum/*",
1748 main.logdir,
1749 direction="from",
1750 options="-rp" )
1751
1752
Jon Hall43060f62020-06-23 13:13:33 -07001753 @staticmethod
1754 def setOnosConfig( main ):
1755 """
1756 Read and Set onos configurations from the params file
1757 """
1758 main.step( "Set ONOS configurations" )
1759 config = main.params.get( 'ONOS_Configuration' )
1760 if config:
1761 main.log.debug( config )
1762 checkResult = main.TRUE
1763 for component in config:
1764 for setting in config[ component ]:
1765 value = config[ component ][ setting ]
1766 check = main.Cluster.next().setCfg( component, setting, value )
1767 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1768 checkResult = check and checkResult
1769 utilities.assert_equals( expect=main.TRUE,
1770 actual=checkResult,
1771 onpass="Successfully set config",
1772 onfail="Failed to set config" )
1773 else:
1774 main.log.warn( "No configurations were specified to be changed after startup" )
1775
1776 @staticmethod
1777 def setOnosLogLevels( main ):
1778 """
1779 Read and Set onos log levels from the params file
1780 """
1781 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001782 # Get original values incase we want to reset them
1783 ctrl = main.Cluster.active(0)
1784 ctrl.CLI.logList()
1785
Jon Hall43060f62020-06-23 13:13:33 -07001786 logging = True
1787 try:
1788 logs = main.params.get( 'ONOS_Logging', False )
1789 if logs:
1790 for namespace, level in logs.items():
1791 for ctrl in main.Cluster.active():
1792 ctrl.CLI.logSet( level, namespace )
1793 except AttributeError:
1794 logging = False
1795 utilities.assert_equals( expect=True, actual=logging,
1796 onpass="Set log levels",
1797 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001798
1799 @staticmethod
1800 def resetOnosLogLevels( main ):
1801 """
1802 Read and reset onos log levels to a previously read set of values
1803 """
1804 main.step( 'Reset logging levels' )
1805 # Get original values incase we want to reset them
1806 ctrl = main.Cluster.active(0)
1807 currentLevels = ctrl.CLI.logList( saveValues=False )
1808 origLevels = ctrl.CLI.logLevels
1809 toBeSet = {}
1810 for logger, level in currentLevels.iteritems():
1811 if logger not in origLevels:
1812 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1813 else:
1814 oldLevel = origLevels[ logger ]
1815 if level != oldLevel:
1816 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07001817 # In case a previous test didn't reset
1818 logs = main.params.get( 'ONOS_Logging_Reset', False )
1819 if logs:
1820 for namespace, level in logs.items():
1821 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08001822 logging = True
1823 try:
1824 for logger, level in toBeSet.iteritems():
1825 for ctrl in main.Cluster.active():
1826 ctrl.CLI.logSet( level, logger )
1827 except AttributeError:
1828 logging = False
1829 utilities.assert_equals( expect=True, actual=logging,
1830 onpass="Reset log levels",
1831 onfail="Failed to reset log levels" )