blob: b5f61a76471098999ea8c614e2260035aed5b312 [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..." )
Siddesha2938fe2021-04-06 02:46:06 +0000441 for ctrl in main.Cluster.runningNodes:
442 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress], main.logdir,"-CASE%d" % main.CurrentTestCaseNumber, onosPortnumber=ctrl.REST.port )
You Wang5df1c6d2018-04-06 18:02:02 -0700443
444 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700445 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700446 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700447
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700448 main.failures = int( main.params[ 'failures' ] )
449 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700450
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700451 if main.cfgName == '2x2':
452 spine = {}
453 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
454 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
455 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700456
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700457 spine = {}
458 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
459 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
460 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700461
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700462 elif main.cfgName == '4x4':
463 spine = {}
464 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
465 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
466 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700467
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700468 spine = {}
469 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
470 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
471 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700472
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700473 spine = {}
474 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
475 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
476 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700477
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700478 spine = {}
479 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
480 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
481 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700482
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700483 else:
Piera2a7e1b2016-10-04 11:51:43 -0700484 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700485 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800486
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800487 @staticmethod
488 def addStaticOnosRoute( main, subnet, intf):
489 """
490 Adds an ONOS static route with the use route-add command.
491 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800492 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
493
Piera2a7e1b2016-10-04 11:51:43 -0700494 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700495 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700496 """
497 Check number of groups for each subnet on device deviceId and matches
498 it with an expected value. subnetDict is a dictionarty containing values
499 of the type "10.0.1.0/24" : 5.
500 """
You Wangc02f3be2018-05-18 12:14:23 -0700501 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
502 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
503 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700504
You Wangc02f3be2018-05-18 12:14:23 -0700505 result = main.TRUE
506 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700507 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700508 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700509 # this will match the group id that this flow entry points to, for example :
510 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700511 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700512 count = 0
513 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700514 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700515 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700516 if count - 1 != numberInSelect:
517 result = main.FALSE
518 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 ) )
519 utilities.assert_equals( expect=main.TRUE, actual=result,
520 onpass="All bucket numbers are as expected",
521 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700522
523 @staticmethod
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900524 def checkFlows( main, minFlowCount, tag="", dumpflows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700525 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800526 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900527 if tag == "":
528 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700529 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700530 main.FALSE,
531 kwargs={ 'min': minFlowCount },
532 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800533 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800534 if count == main.FALSE:
535 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700536 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700537 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800538 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700539 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
540 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700541
542 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700543 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700544 main.FALSE,
545 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800546 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800547 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700548 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700549 expect=main.TRUE,
550 actual=flowCheck,
551 onpass="Flow status is correct!",
552 onfail="Flow status is wrong!" )
553 if dumpflows:
Devin Lim142b5342017-07-20 15:22:39 -0700554 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700555 "flows",
556 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800557 tag + "_FlowsBefore",
558 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700559 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700560 "groups",
561 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800562 tag + "_GroupsBefore",
563 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700564
565 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700566 def checkDevices( main, switches, tag="", sleep=10 ):
567 main.step(
568 "Check whether the switches count is equal to %s" % switches )
569 if tag == "":
570 tag = 'CASE%d' % main.CurrentTestCaseNumber
571 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
572 main.FALSE,
573 kwargs={ 'numoswitch': switches},
574 attempts=10,
575 sleep=sleep )
576 utilities.assert_equals( expect=main.TRUE, actual=result,
577 onpass="Device up successful",
578 onfail="Failed to boot up devices?" )
579
580 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800581 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
582 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800583 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800584 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
585 main.FALSE,
586 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800587 attempts=5,
588 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800589 if count == main.FALSE:
590 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800591 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800592 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800593 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800594 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800595 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800596
597 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700598 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800599 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700600 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800601 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
602 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700603 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800604 attempts=5,
605 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800606 if count == main.FALSE:
607 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800608 utilities.assertEquals(
609 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800610 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700611 onpass="Flow count looks correct: " + str( count ) ,
612 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800613
614 @staticmethod
615 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
616 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700617 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800618 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
619 main.FALSE,
620 args=( dpid, groupCount, False, 1),
621 attempts=5,
622 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800623 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800624 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800625 utilities.assertEquals(
626 expect=True,
627 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700628 onpass="Group count looks correct: " + str( count ) ,
629 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800630
631 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700632 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800633
634 for dpid, values in main.count.items():
635 flowCount = values["flows"]
636 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700637 main.log.report( "Check flow count for dpid " + str( dpid ) +
638 ", should be " + str( flowCount ) )
639 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800640
Jon Hall9677ed32018-04-24 11:16:23 -0700641 main.log.report( "Check group count for dpid " + str( dpid ) +
642 ", should be " + str( groupCount ) )
643 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800644
645 return
646
647 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700648 def pingAll( main, tag="", dumpflows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800649 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800650 '''
You Wangba231e72018-03-01 13:18:21 -0800651 Verify connectivity between hosts according to the ping chart
652 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800653 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800654 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800655 '''
You Wangba231e72018-03-01 13:18:21 -0800656 main.log.report( "Check host connectivity" )
657 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800658 if tag == "":
659 tag = 'CASE%d' % main.CurrentTestCaseNumber
660 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800661 main.log.debug( "Entry in ping chart: %s" % entry )
662 expect = entry[ 'expect' ]
663 if expect == "Unidirectional":
664 # Verify ping from each src host to each dst host
665 src = entry[ 'src' ]
666 dst = entry[ 'dst' ]
667 expect = main.TRUE
668 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
669 if basedOnIp:
670 if ("v4" in src[0]):
671 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
672 utilities.assert_equals( expect=expect, actual=pa,
673 onpass="IPv4 connectivity successfully tested",
674 onfail="IPv4 connectivity failed" )
675 if ("v6" in src[0]):
676 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
677 utilities.assert_equals( expect=expect, actual=pa,
678 onpass="IPv6 connectivity successfully tested",
679 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700680 elif main.physicalNet:
681 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
682 utilities.assert_equals( expect=expect, actual=pa,
683 onpass="IP connectivity successfully tested",
684 onfail="IP connectivity failed" )
685
You Wangba231e72018-03-01 13:18:21 -0800686 else:
687 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
688 utilities.assert_equals( expect=expect, actual=pa,
689 onpass="IP connectivity successfully tested",
690 onfail="IP connectivity failed" )
691 else:
692 # Verify ping between each host pair
693 hosts = entry[ 'hosts' ]
694 try:
695 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
696 except:
697 expect = main.FALSE
698 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
699 if basedOnIp:
700 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800701 pa = utilities.retry( main.Network.pingallHosts,
702 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700703 args=(hosts, ),
704 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800705 attempts=retryAttempts,
706 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800707 utilities.assert_equals( expect=expect, actual=pa,
708 onpass="IPv4 connectivity successfully tested",
709 onfail="IPv4 connectivity failed" )
710 if ("v6" in hosts[0]):
711 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
712 utilities.assert_equals( expect=expect, actual=pa,
713 onpass="IPv6 connectivity successfully tested",
714 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700715 elif main.physicalNet:
Jon Hall06fd0df2021-01-25 15:50:06 -0800716 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy )
Jon Hall43060f62020-06-23 13:13:33 -0700717 utilities.assert_equals( expect=expect, actual=pa,
718 onpass="IP connectivity successfully tested",
719 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800720 else:
You Wangf19d9f42018-02-23 16:34:19 -0800721 pa = main.Network.pingallHosts( hosts )
722 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800723 onpass="IP connectivity successfully tested",
724 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700725 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700726 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700727 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700728 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700729 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800730
731 if dumpflows:
732 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
733 "flows",
734 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800735 tag + "_FlowsOn",
736 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800737 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
738 "groups",
739 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800740 tag + "_GroupsOn",
741 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800742
743 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700744 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700745 """
746 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
747 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
748 Kill a link and verify ONOS can see the proper link change
749 """
Jon Halla604fd42018-05-04 14:27:27 -0700750 if sleep is None:
751 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
752 else:
753 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700754 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700755 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
756 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700757 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
758 onpass="Link down successful",
759 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700760 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700761 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700762 "Waiting %s seconds for link down to be discovered" % sleep )
763 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700764 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700765 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700766 main.FALSE,
767 kwargs={ 'numoswitch': switches,
768 'numolink': links },
769 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700770 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700771 utilities.assert_equals( expect=main.TRUE, actual=topology,
772 onpass="Topology after link down is correct",
773 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700774
775 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700776 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800777 """
778 links = list of links (src, dst) to bring down.
779 """
780
781 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700782 if sleep is None:
783 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
784 else:
785 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800786
787 for end1, end2 in links:
788 main.Network.link( END1=end1, END2=end2, OPTION="down")
789 main.Network.link( END1=end2, END2=end1, OPTION="down")
790
Jon Halla604fd42018-05-04 14:27:27 -0700791 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800792 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700793 "Waiting %s seconds for links down to be discovered" % sleep )
794 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800795
796 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
797 main.FALSE,
798 kwargs={ 'numoswitch': switches,
799 'numolink': linksAfter },
800 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700801 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800802
You Wang2854bce2018-03-30 10:15:32 -0700803 utilities.assert_equals( expect=main.TRUE, actual=topology,
804 onpass="Link batch down successful",
805 onfail="Link batch down failed" )
806
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800807 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700808 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800809 """
810 links = list of link (src, dst) to bring up again.
811 """
812
813 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700814 if sleep is None:
815 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
816 else:
817 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800818
819 for end1, end2 in links:
820 main.Network.link( END1=end1, END2=end2, OPTION="up")
821 main.Network.link( END1=end2, END2=end1, OPTION="up")
822
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800823 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700824 "Waiting %s seconds for links up to be discovered" % sleep )
825 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800826
827 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
828 main.FALSE,
829 kwargs={ 'numoswitch': switches,
830 'numolink': linksAfter },
831 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700832 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800833
You Wang2854bce2018-03-30 10:15:32 -0700834 utilities.assert_equals( expect=main.TRUE, actual=topology,
835 onpass="Link batch up successful",
836 onfail="Link batch up failed" )
837
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800838 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700839 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
840 """
841 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
842 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
843 switches, links: number of expected switches and links after link change, ex.: '4', '6'
844 """
845 if sleep is None:
846 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
847 else:
848 sleep = float( sleep )
849 main.step( "Disable a batch of ports" )
850 for dpid, port in ports:
851 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
852 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
853 time.sleep( sleep )
854 if switches and links:
855 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
856 numolink=links )
857 utilities.assert_equals( expect=main.TRUE, actual=result,
858 onpass="Port down successful",
859 onfail="Port down failed" )
860
861 @staticmethod
862 def enablePortBatch( main, ports, switches, links, sleep=None ):
863 """
864 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
865 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
866 switches, links: number of expected switches and links after link change, ex.: '4', '6'
867 """
868 if sleep is None:
869 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
870 else:
871 sleep = float( sleep )
872 main.step( "Enable a batch of ports" )
873 for dpid, port in ports:
874 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
875 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
876 time.sleep( sleep )
877 if switches and links:
878 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
879 numolink=links )
880 utilities.assert_equals( expect=main.TRUE, actual=result,
881 onpass="Port up successful",
882 onfail="Port up failed" )
883
884 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -0700885 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -0700886 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700887 """
888 Params:
889 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -0700890 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -0700891 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
892 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
893 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
894 Kill a link and verify ONOS can see the proper link change
895 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700896 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700897 if sleep is None:
898 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
899 else:
900 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700901 result = False
902 count = 0
903 while True:
904 count += 1
Jon Halla604fd42018-05-04 14:27:27 -0700905 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -0800906 main.Network.link( END1=end1, END2=end2, OPTION="up" )
907 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700908 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700909 "Waiting %s seconds for link up to be discovered" % sleep )
910 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -0700911
You Wangc02d8352018-04-17 16:42:10 -0700912 if portUp:
913 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
914 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -0700915 main.log.info(
916 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -0700917 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700918
Jon Halla604fd42018-05-04 14:27:27 -0700919 result = ctrl.CLI.checkStatus( numoswitch=switches,
920 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700921 if count > 5 or result:
922 break
923 utilities.assert_equals( expect=main.TRUE, actual=result,
924 onpass="Link up successful",
925 onfail="Failed to bring link up" )
926
927 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700928 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700929 """
930 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
931 Completely kill a switch and verify ONOS can see the proper change
932 """
Jon Halla604fd42018-05-04 14:27:27 -0700933 if sleep is None:
934 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
935 else:
936 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -0700937 switch = switch if isinstance( switch, list ) else [ switch ]
938 main.step( "Kill " + str( switch ) )
939 for s in switch:
940 main.log.info( "Stopping " + s )
941 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700942 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -0700943
944 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700945 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700946 sleep ) )
947 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -0700948 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700949 main.FALSE,
950 kwargs={ 'numoswitch': switches,
951 'numolink': links },
952 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700953 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700954 utilities.assert_equals( expect=main.TRUE, actual=topology,
955 onpass="Kill switch successful",
956 onfail="Failed to kill switch?" )
957
958 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700959 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700960 """
961 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
962 Recover a switch and verify ONOS can see the proper change
963 """
Jon Halla604fd42018-05-04 14:27:27 -0700964 if sleep is None:
965 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
966 else:
967 sleep = float( sleep )
968 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -0700969 switch = switch if isinstance( switch, list ) else [ switch ]
970 main.step( "Recovering " + str( switch ) )
971 for s in switch:
972 main.log.info( "Starting " + s )
973 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700974 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700975 sleep ) )
976 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700977 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -0700978 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700979 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -0700980 sleep ) )
981 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -0700982
Devin Lim142b5342017-07-20 15:22:39 -0700983 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700984 main.FALSE,
985 kwargs={ 'numoswitch': switches,
986 'numolink': links },
987 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700988 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700989 utilities.assert_equals( expect=main.TRUE, actual=topology,
990 onpass="Switch recovery successful",
991 onfail="Failed to recover switch?" )
992
Jonghwan Hyun25c98a62018-05-04 13:59:09 -0700993 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -0700994 def killRouter( main, router, sleep=None ):
995 """
996 Kill bgpd process on a quagga router
997 router: name of the router to be killed. E.g. "bgp1"
998 """
999 sleep = float( sleep )
1000 main.step( "Kill " + str( router ) )
1001 if hasattr( main, 'Mininet1' ):
1002 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
1003 main.Mininet1.handle.expect( "mininet>" )
1004 else:
1005 # TODO: support killing router in physical network
1006 pass
1007 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
1008 time.sleep( sleep )
1009
1010 @staticmethod
1011 def recoverRouter( main, router, sleep=None ):
1012 """
1013 Restart bgpd process on a quagga router
1014 router: name of the router to be recovered. E.g. "bgp1"
1015 """
1016 sleep = float( sleep )
1017 main.step( "Recovering " + str( router ) )
1018 if hasattr( main, 'Mininet1' ):
1019 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1020 main.Mininet1.handle.expect( "mininet>" )
1021 else:
1022 # TODO: support recovering router in physical network
1023 pass
1024 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1025 time.sleep( sleep )
1026
1027 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001028 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001029 """
1030 Stop Onos-cluster.
1031 Stops Mininet
1032 Copies ONOS log
1033 """
You Wang4cc61912018-08-28 10:10:58 -07001034 from tests.dependencies.utils import Utils
1035 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001036 if not main.persistentSetup:
1037 for ctrl in main.Cluster.active():
1038 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001039 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001040 if hasattr( main, "scapyHosts" ):
1041 scapyResult = main.TRUE
1042 for host in main.scapyHosts:
1043 scapyResult = host.stopScapy() and scapyResult
1044 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1045 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001046 if hasattr( main, 'Mininet1' ):
1047 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1048 else:
1049 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001050 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1051 main.scapyHosts = []
1052
You Wang5da39c82018-04-26 22:55:08 -07001053 if removeHostComponent:
1054 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1055 if hasattr( main, host ):
You Wang4cc61912018-08-28 10:10:58 -07001056 if hasattr( main, 'Mininet1' ):
1057 pass
1058 else:
1059 getattr( main, host ).disconnectInband()
You Wang5da39c82018-04-26 22:55:08 -07001060 main.Network.removeHostComponent( host )
1061
You Wang5df1c6d2018-04-06 18:02:02 -07001062 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001063 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001064 else:
1065 main.Network.disconnectInbandHosts()
1066 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001067
You Wang5df1c6d2018-04-06 18:02:02 -07001068 if copyKarafLog:
1069 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001070
Jon Hall627b1572020-12-01 12:01:15 -08001071 if not main.persistentSetup:
1072 for ctrl in main.Cluster.active():
1073 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001074 else:
1075 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001076 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001077
1078 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001079 def verifyNodes( main ):
1080 """
1081 Verifies Each active node in the cluster has an accurate view of other node's and their status
1082
1083 Params:
1084 nodes, integer array with position of the ONOS nodes in the CLIs array
1085 """
1086 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1087 False,
1088 attempts=10,
1089 sleep=10 )
1090 utilities.assert_equals( expect=True, actual=nodeResults,
1091 onpass="Nodes check successful",
1092 onfail="Nodes check NOT successful" )
1093
1094 if not nodeResults:
1095 for ctrl in main.Cluster.runningNodes:
1096 main.log.debug( "{} components not ACTIVE: \n{}".format(
1097 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001098 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001099 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001100 main.cleanAndExit()
1101
1102 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001103 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001104 """
1105 Verifies that the ONOS cluster has an acuurate view of the topology
1106
1107 Params:
1108 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 -08001109 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001110 """
1111 main.step( "Check number of topology elements" )
1112 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1113 main.FALSE,
1114 kwargs={ 'numoswitch': switches,
1115 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001116 'numoctrl': expNodes,
1117 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001118 attempts=10,
1119 sleep=12 )
1120 utilities.assert_equals( expect=main.TRUE, actual=topology,
1121 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001122 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001123
1124 @staticmethod
1125 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001126 """
1127 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1128 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1129 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1130 """
Jon Halla604fd42018-05-04 14:27:27 -07001131 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001132 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001133 if sleep is None:
1134 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1135 else:
1136 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001137
Jon Hall214f88b2020-09-21 10:21:42 -07001138 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001139 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001140 node = main.Cluster.runningNodes[ i ]
1141 if node.inDocker:
1142 killResult = node.server.dockerStop( node.name )
1143 else:
1144 killResult = main.ONOSbench.onosDie( node.ipAddress )
1145 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001146 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001147 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1148 onpass="ONOS instance Killed",
1149 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001150 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001151 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001152 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001153
Devin Lim142b5342017-07-20 15:22:39 -07001154 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001155 Testcaselib.verifyNodes( main )
1156 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001157
1158 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001159 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001160 """
1161 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1162 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1163 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1164 """
Jon Hall3c910162018-03-07 14:42:16 -08001165 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001166 if sleep is None:
1167 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1168 else:
1169 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001170 for i in nodes:
1171 node = main.Cluster.runningNodes[ i ]
1172 if node.inDocker:
1173 main.Cluster.startONOSDockerNode( i )
1174 else:
1175 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001176 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001177 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001178 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001179 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001180 if node.inDocker:
1181 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1182 isUp = isUp and node.CLI.prepareForCLI()
1183 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1184 else:
1185 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001186 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1187 onpass="ONOS service is ready",
1188 onfail="ONOS service did not start properly" )
1189 for i in nodes:
1190 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001191 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001192 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001193 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1194 commandlineTimeout=60,
1195 onosStartTimeout=100 )
1196 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001197 utilities.assert_equals( expect=main.TRUE,
1198 actual=cliResult,
1199 onpass="ONOS CLI is ready",
1200 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001201
Jon Halla604fd42018-05-04 14:27:27 -07001202 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001203 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001204 Testcaselib.verifyNodes( main )
1205 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001206
Devin Lim142b5342017-07-20 15:22:39 -07001207 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001208 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001209 attempts=10,
1210 sleep=12 )
1211 if ready:
1212 ready = main.TRUE
1213 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001214 onpass="ONOS summary command succeded",
1215 onfail="ONOS summary command failed" )
1216 if not ready:
1217 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001218 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001219
1220 @staticmethod
1221 def addHostCfg( main ):
1222 """
1223 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001224 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001225 """
1226 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001227 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001228 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001229 hostCfg = json.load( template )
1230 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1231 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001232 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001233 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1234 subjectClass="hosts",
1235 subjectKey=urllib.quote( mac,
1236 safe='' ),
1237 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001238 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1239 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001240 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001241 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1242 subjectClass="hosts",
1243 subjectKey=urllib.quote( mac,
1244 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001245 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001246 main.pingChart.update( { 'vlan1': { "expect": "True",
1247 "hosts": [ "olt1", "vsg1" ] } } )
1248 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1249 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001250 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1251 vlanId=1,
1252 port1=5,
1253 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001254
1255 @staticmethod
1256 def delHostCfg( main ):
1257 """
1258 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001259 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001260 """
1261 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001262 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001263 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001264 hostCfg = json.load( template )
1265 main.step( "Removing host configuration" )
1266 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001267 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001268 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1269 subjectKey=urllib.quote(
1270 mac,
1271 safe='' ),
1272 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001273 main.step( "Removing configuration" )
1274 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001275 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001276 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1277 subjectKey=urllib.quote(
1278 mac,
1279 safe='' ),
1280 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001281 main.step( "Removing vlan configuration" )
1282 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001283 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1284 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001285
1286 @staticmethod
1287 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1288 """
1289 Verifies IP address assignment from the hosts
1290 """
1291 main.step( "Verify IP address assignment from hosts" )
1292 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001293 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001294 # Find out names of disconnected hosts
1295 disconnectedHosts = []
1296 if hasattr( main, "disconnectedIpv4Hosts" ):
1297 for host in main.disconnectedIpv4Hosts:
1298 disconnectedHosts.append( host )
1299 if hasattr( main, "disconnectedIpv6Hosts" ):
1300 for host in main.disconnectedIpv6Hosts:
1301 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001302 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001303 # Exclude disconnected hosts
1304 if hostName in disconnectedHosts:
1305 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1306 continue
You Wang53dba1e2018-02-02 17:45:44 -08001307 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1308 main.FALSE,
1309 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001310 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001311 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001312 attempts=attempts,
1313 sleep=sleep )
1314 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1315 onpass="Verify network host IP succeded",
1316 onfail="Verify network host IP failed" )
1317
1318 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001319 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001320 """
1321 Verifies host IP address assignment from ONOS
1322 """
1323 main.step( "Verify host IP address assignment in ONOS" )
1324 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001325 # Find out IPs of disconnected hosts
1326 disconnectedIps = []
1327 if hasattr( main, "disconnectedIpv4Hosts" ):
1328 for host in main.disconnectedIpv4Hosts:
1329 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1330 if hasattr( main, "disconnectedIpv6Hosts" ):
1331 for host in main.disconnectedIpv6Hosts:
1332 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001333 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001334 # Exclude disconnected hosts
1335 if ip in disconnectedIps:
1336 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1337 continue
You Wang53dba1e2018-02-02 17:45:44 -08001338 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1339 main.FALSE,
1340 kwargs={ 'hostList': [ hostName ],
1341 'prefix': ip },
1342 attempts=attempts,
1343 sleep=sleep )
1344 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1345 onpass="Verify ONOS host IP succeded",
1346 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001347 if not ipResult and skipOnFail:
1348 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001349 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001350 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001351
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001352 @staticmethod
1353 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1354 """
1355 Description:
1356 Updates interface configuration in ONOS, with given IP and vlan parameters
1357 Required:
1358 * connectPoint: connect point to update configuration
1359 Optional:
1360 * ips: list of IP addresses, combined with '/xx' subnet representation,
1361 corresponding to 'ips' field in the configuration
1362 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1363 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1364 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1365 """
1366 cfg = dict()
1367 cfg[ "ports" ] = dict()
1368 cfg[ "ports" ][ connectPoint ] = dict()
1369 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1370 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1371 if untagged > 0:
1372 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1373 else:
1374 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1375 if native > 0:
1376 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1377
1378 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001379
1380 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001381 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001382 """
1383 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001384 scapyNames: list of names that will be used as component names for scapy hosts
1385 mininetNames: used when scapy host names are different from the host names
1386 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1387 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001388 """
1389 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001390 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1391 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001392 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001393 if hasattr( main, 'Mininet1' ):
1394 main.Scapy.createHostComponent( scapyName )
1395 scapyHandle = getattr( main, scapyName )
1396 if mininetNames:
1397 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1398 else:
1399 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001400 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1401 scapyHandle.mExecDir = "/tmp"
1402 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1403 main.log.debug( "start mn host component in docker" )
1404 scapyHandle.startHostCli( mininetName,
1405 execDir="/tmp",
1406 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1407 else:
1408 main.log.debug( "start mn host component" )
1409 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001410 else:
You Wang0fc21702018-11-02 17:49:18 -07001411 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001412 scapyHandle = getattr( main, scapyName )
1413 scapyHandle.connectInband()
1414 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001415 scapyHandle.startScapy()
1416 scapyHandle.updateSelf()
1417 main.log.debug( scapyHandle.name )
1418 main.log.debug( scapyHandle.hostIp )
1419 main.log.debug( scapyHandle.hostMac )
1420
1421 @staticmethod
1422 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1423 """
1424 Verify unicast traffic by pinging from source hosts to the destination IP
1425 and capturing the packets at the destination host using Scapy.
1426 srcHosts: List of host names to send the ping packets
1427 dstIp: destination IP of the ping packets
1428 dstHost: host that runs Scapy to capture the packets
1429 dstIntf: name of the interface on the destination host
1430 expect: use True if the ping is expected to be captured at destination;
1431 Otherwise False
1432 skipOnFail: skip the rest of this test case if result is not expected
1433 maxRetry: number of retries allowed
1434 """
1435 from tests.dependencies.topology import Topology
1436 try:
1437 main.topo
1438 except ( NameError, AttributeError ):
1439 main.topo = Topology()
1440 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1441 result = main.TRUE
1442 for srcHost in srcHosts:
1443 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1444 expect, maxRetry, True )
1445 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001446 result = main.FALSE
1447 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1448 utilities.assert_equals( expect=main.TRUE,
1449 actual=result,
1450 onpass="Verify traffic to {}: Pass".format( dstIp ),
1451 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1452 if skipOnFail and result != main.TRUE:
1453 Testcaselib.saveOnosDiagnostics( main )
1454 Testcaselib.cleanup( main, copyKarafLog=False )
1455 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001456
1457 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001458 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001459 """
1460 Verify multicast traffic using scapy
1461 """
You Wangc564c6f2018-05-01 15:24:57 -07001462 from tests.dependencies.topology import Topology
1463 try:
1464 main.topo
1465 except ( NameError, AttributeError ):
1466 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001467 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001468 routeData = main.multicastConfig[ routeName ]
1469 srcs = main.mcastRoutes[ routeName ][ "src" ]
1470 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1471 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1472 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001473 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001474 for src in srcs:
1475 srcEntry = routeData[ "src" ][ src ]
1476 for dst in dsts:
1477 dstEntry = routeData[ "dst" ][ dst ]
1478 sender = getattr( main, srcEntry[ "host" ] )
1479 receiver = getattr( main, dstEntry[ "host" ] )
1480 main.Network.addRoute( str( srcEntry[ "host" ] ),
1481 str( routeData[ "group" ] ),
1482 str( srcEntry[ "interface" ] ),
1483 True if routeData[ "ipVersion" ] == 6 else False )
1484 # Build the packet
1485 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1486 if routeData[ "ipVersion" ] == 4:
1487 sender.buildIP( dst=str( routeData[ "group" ] ) )
1488 elif routeData[ "ipVersion" ] == 6:
1489 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1490 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1491 sIface = srcEntry[ "interface" ]
1492 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1493 pktFilter = srcEntry[ "filter" ]
1494 pkt = srcEntry[ "packet" ]
1495 # Send packet and check received packet
1496 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001497 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001498 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001499 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1500 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001501 if not trafficResult:
1502 result = main.FALSE
1503 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1504 dstEntry[ "host" ] ) )
1505 utilities.assert_equals( expect=main.TRUE,
1506 actual=result,
1507 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1508 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001509 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001510 Testcaselib.saveOnosDiagnostics( main )
1511 Testcaselib.cleanup( main, copyKarafLog=False )
1512 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001513
1514 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001515 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001516 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1517 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001518 """
1519 Verify reachability from each host in srcList to each host in dstList
1520 """
1521 from tests.dependencies.topology import Topology
1522 try:
1523 main.topo
1524 except ( NameError, AttributeError ):
1525 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001526 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001527 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001528 utilities.assert_equals( expect=main.TRUE,
1529 actual=pingResult,
1530 onpass="{}: Pass".format( stepMsg ),
1531 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001532 if not pingResult and skipOnFail:
1533 Testcaselib.saveOnosDiagnostics( main )
1534 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1535 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001536
1537 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001538 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001539 """
1540 Verify if the specified host is discovered by ONOS on the given locations
1541 Required:
You Wang85747762018-05-11 15:51:50 -07001542 locationDict: a dictionary that maps host names to expected locations.
1543 locations could be a string or a list.
1544 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001545 Returns:
1546 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1547 """
You Wang85747762018-05-11 15:51:50 -07001548 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1549 result = main.TRUE
1550 for hostName, locations in locationDict.items():
1551 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1552 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1553 if not hostIp:
1554 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1555 if not hostIp:
1556 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1557 result = main.FALSE
1558 continue
1559 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1560 main.FALSE,
1561 args=( hostIp, locations ),
1562 attempts=retry + 1,
1563 sleep=10 )
1564 if not locationResult:
1565 result = main.FALSE
1566 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001567 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001568 onpass="Location verification passed",
1569 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001570
1571 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001572 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001573 """
1574 Move specified host from srcSw to dstSw.
1575 If srcSw and dstSw are same, the host will be moved from current port to
1576 next available port.
1577 Required:
1578 hostName: name of the host. e.g., "h1"
1579 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1580 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1581 gw: ip address of the gateway of the new location
1582 Optional:
1583 macAddr: if specified, change MAC address of the host to the specified MAC address.
1584 prefixLen: prefix length
1585 cfg: port configuration as JSON string
1586 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001587 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001588 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001589 if not hasattr( main, 'Mininet1' ):
1590 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1591 return
1592
You Wang6e5b48e2018-07-23 16:17:38 -07001593 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1594 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1595 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001596 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001597 if cfg:
1598 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1599 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001600 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001601 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001602 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001603
1604 main.Mininet1.discoverHosts( [ hostName, ] )
1605
1606 # Update expectedHost when MAC address is changed.
1607 if macAddr is not None:
1608 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1609 if ipAddr is not None:
1610 for hostName, ip in main.expectedHosts[ "onos" ].items():
1611 if ip == ipAddr:
1612 vlan = hostName.split( "/" )[ -1 ]
1613 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001614 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001615 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001616
1617 @staticmethod
1618 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001619 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001620 """
1621 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1622 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1623 to next available port.
1624 Required:
1625 hostName: name of the host. e.g., "h1"
1626 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1627 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1628 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1629 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1630 gw: ip address of the gateway of the new location
1631 Optional:
1632 macAddr: if specified, change MAC address of the host to the specified MAC address.
1633 prefixLen: prefix length
1634 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001635 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001636 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001637 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001638 if not hasattr( main, 'Mininet1' ):
1639 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1640 return
1641
You Wang6e5b48e2018-07-23 16:17:38 -07001642 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1643 srcSw, srcPairSw, dstSw, dstPairSw ) )
1644 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1645 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1646 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001647 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001648 if cfg:
1649 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1650 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001651 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001652 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001653 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001654
1655 main.Mininet1.discoverHosts( [ hostName, ] )
1656
1657 # Update expectedHost when MAC address is changed.
1658 if macAddr is not None:
1659 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1660 if ipAddr is not None:
1661 for hostName, ip in main.expectedHosts[ "onos" ].items():
1662 if ip == ipAddr:
1663 vlan = hostName.split( "/" )[ -1 ]
1664 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001665 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001666
1667 @staticmethod
1668 def mnDockerSetup( main ):
1669 """
1670 Optionally start and setup docker image for mininet
1671 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001672 try:
1673 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001674
Jon Hall9b0de1f2020-08-24 15:38:04 -07001675 main.log.info( "Creating Mininet Docker" )
1676 handle = main.Mininet1.handle
1677 # build docker image
1678 dockerFilePath = "%s/../dependencies/" % main.testDir
1679 dockerName = "trellis_mininet"
1680 # Stop any leftover container
1681 main.Mininet1.dockerStop( dockerName )
1682 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001683 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001684
Jon Hall9b0de1f2020-08-24 15:38:04 -07001685 confDir = "/tmp/mn_conf/"
1686 # Try to ensure the destination exists
1687 main.log.info( "Create folder for network config files" )
1688 handle.sendline( "rm -rf %s" % confDir )
1689 handle.expect( main.Mininet1.Prompt() )
1690 main.log.debug( handle.before + handle.after )
1691 handle.sendline( "mkdir -p %s" % confDir )
1692 handle.expect( main.Mininet1.Prompt() )
1693 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001694 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1695 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001696 # Make sure permissions are correct
1697 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1698 handle.expect( main.Mininet1.Prompt() )
1699 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1700 handle.expect( main.Mininet1.Prompt() )
1701 main.log.debug( handle.before + handle.after )
1702 # Start docker container
1703 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1704 dockerName,
1705 main.params[ 'MN_DOCKER' ][ 'args' ] )
1706 if runResponse == main.FALSE:
1707 main.log.error( "Docker container already running, aborting test" )
1708 main.cleanup()
1709 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001710
Jon Hall9b0de1f2020-08-24 15:38:04 -07001711 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1712 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001713
Jon Hall9b0de1f2020-08-24 15:38:04 -07001714 # Fow when we create component handles
1715 main.Mininet1.mExecDir = "/tmp"
1716 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1717 main.Mininet1.hostPrompt = "/home/root#"
1718
1719 # For some reason docker isn't doing this
1720 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1721 main.Mininet1.handle.expect( "etc/hosts" )
1722 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1723 except Exception as e:
1724 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001725 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001726
1727 @staticmethod
1728 def mnDockerTeardown( main ):
1729 """
1730 Optionally stop and cleanup docker image for mininet
1731 """
1732
1733 if hasattr( main, 'Mininet1' ):
1734 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001735 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001736
1737 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001738 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001739 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001740 main.Mininet1.sudoRequired = True
1741 except Exception as e:
1742 main.log.error( e )
1743
Jon Hall39570262020-11-17 12:18:19 -08001744 # Save docker logs
1745 copyResult = main.ONOSbench.scp( main.Mininet1,
1746 "/tmp/mn-stratum/*",
1747 main.logdir,
1748 direction="from",
1749 options="-rp" )
1750
1751
Jon Hall43060f62020-06-23 13:13:33 -07001752 @staticmethod
1753 def setOnosConfig( main ):
1754 """
1755 Read and Set onos configurations from the params file
1756 """
1757 main.step( "Set ONOS configurations" )
1758 config = main.params.get( 'ONOS_Configuration' )
1759 if config:
1760 main.log.debug( config )
1761 checkResult = main.TRUE
1762 for component in config:
1763 for setting in config[ component ]:
1764 value = config[ component ][ setting ]
1765 check = main.Cluster.next().setCfg( component, setting, value )
1766 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1767 checkResult = check and checkResult
1768 utilities.assert_equals( expect=main.TRUE,
1769 actual=checkResult,
1770 onpass="Successfully set config",
1771 onfail="Failed to set config" )
1772 else:
1773 main.log.warn( "No configurations were specified to be changed after startup" )
1774
1775 @staticmethod
1776 def setOnosLogLevels( main ):
1777 """
1778 Read and Set onos log levels from the params file
1779 """
1780 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001781 # Get original values incase we want to reset them
1782 ctrl = main.Cluster.active(0)
1783 ctrl.CLI.logList()
1784
Jon Hall43060f62020-06-23 13:13:33 -07001785 logging = True
1786 try:
1787 logs = main.params.get( 'ONOS_Logging', False )
1788 if logs:
1789 for namespace, level in logs.items():
1790 for ctrl in main.Cluster.active():
1791 ctrl.CLI.logSet( level, namespace )
1792 except AttributeError:
1793 logging = False
1794 utilities.assert_equals( expect=True, actual=logging,
1795 onpass="Set log levels",
1796 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001797
1798 @staticmethod
1799 def resetOnosLogLevels( main ):
1800 """
1801 Read and reset onos log levels to a previously read set of values
1802 """
1803 main.step( 'Reset logging levels' )
1804 # Get original values incase we want to reset them
1805 ctrl = main.Cluster.active(0)
1806 currentLevels = ctrl.CLI.logList( saveValues=False )
1807 origLevels = ctrl.CLI.logLevels
1808 toBeSet = {}
1809 for logger, level in currentLevels.iteritems():
1810 if logger not in origLevels:
1811 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1812 else:
1813 oldLevel = origLevels[ logger ]
1814 if level != oldLevel:
1815 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07001816 # In case a previous test didn't reset
1817 logs = main.params.get( 'ONOS_Logging_Reset', False )
1818 if logs:
1819 for namespace, level in logs.items():
1820 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08001821 logging = True
1822 try:
1823 for logger, level in toBeSet.iteritems():
1824 for ctrl in main.Cluster.active():
1825 ctrl.CLI.logSet( level, logger )
1826 except AttributeError:
1827 logging = False
1828 utilities.assert_equals( expect=True, actual=logging,
1829 onpass="Reset log levels",
1830 onfail="Failed to reset log levels" )