blob: 93af0ee81b74adb179948292023b2c063577e5b6 [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/"
Siddeshde1d1692021-09-15 18:12:57 +000078 # main.forcfg = "netcfg/"
Devin Lim57221b02018-02-14 15:45:36 -080079 main.forChart = "chart/"
80 main.forConfig = "conf/"
81 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080082 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080083 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070084 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070085 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080086 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
87 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080088 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070089 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070090 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070091 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070092 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070093 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070094
Devin Lim0c972b72018-02-08 14:53:59 -080095 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070096 except Exception as e:
97 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070098
Jon Hallaa1d9b82020-07-30 13:49:42 -070099 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall32c90f32021-06-24 16:32:44 -0700100
Siddesh167bc882021-03-23 21:03:43 +0000101 @staticmethod
102 def getTopo():
103 topo = dict()
104 # TODO: Check minFlowCount of leaf for BMv2 switch
105 # (number of spine switch, number of leaf switch, dual-homed, description, minFlowCount - leaf (OvS), minFlowCount - leaf (BMv2))
106 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 }
107 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 }
108 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 }
109 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 }
110 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 }
111 topo[ '4x4' ] = {'spines': 4,'leaves': 4, 'dual-homed': True, 'description': '4x4 dual-homed leaf-spine topology','dual-linked': True }
112 topo[ '2x2staging' ] = { 'spines': 2, 'leaves': 2,'dual-homed': True, 'description': '2x2 leaf-spine topology', 'minFlowOvS': 37, 'minFlow-Stratum': 32 }
113 return topo
Jon Hall1efcb3f2016-08-23 13:42:15 -0700114 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800115 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
116 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700117 """
118 - Set up cell
119 - Create cell file
120 - Set cell file
121 - Verify cell file
122 - Kill ONOS process
123 - Uninstall ONOS cluster
124 - Verify ONOS start up
125 - Install ONOS cluster
126 - Connect to cli
127 """
Siddesh13492972021-03-12 21:09:32 +0000128 # 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
129
Jon Hall1efcb3f2016-08-23 13:42:15 -0700130 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700131 try:
Jon Hall627b1572020-12-01 12:01:15 -0800132 if not main.persistentSetup and main.params.get( 'EXTERNAL_APPS' ):
Jon Hall43060f62020-06-23 13:13:33 -0700133 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800134 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700135 main.ONOSbench.onosFetchApp( url )
136 if not main.apps:
137 main.log.error( "App list is empty" )
138 except Exception as e:
139 main.log.debug( e )
140 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800141 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
142 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700143 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800144 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800145 skipPack=skipPackage,
146 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800147 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700148 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700149 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800150 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700151 attempts=10 )
152 if ready:
153 ready = main.TRUE
154 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700155 onpass="ONOS summary command succeded",
156 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700157 if not ready:
158 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700159 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700160
You Wang5bf49592020-07-08 18:47:46 -0700161 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700162 appInstallResult = main.TRUE
163 if main.trellisOar:
164 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700165 if main.t3Oar:
166 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
167 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
168 onpass="SR app installation succeded",
169 onfail="SR app installation failed" )
170 if not appInstallResult:
171 main.cleanAndExit()
172
Jon Hall43060f62020-06-23 13:13:33 -0700173 # FIXME: move to somewhere else?
174 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
175 # TODO: Support other pipeconfs/making this configurable
176 if switchPrefix == "tofino":
177 # It seems to take some time for the pipeconfs to be loaded
178 ctrl = main.Cluster.next()
179 for i in range( 120 ):
180 try:
181 main.log.debug( "Checking to see if pipeconfs are loaded" )
182 output = ctrl.CLI.sendline( "pipeconfs" )
183 if "tofino" in output:
184 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
185 break
186 time.sleep( 1 )
187 except Exception as e:
188 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700189
Jon Hall627b1572020-12-01 12:01:15 -0800190 # Install segmentrouting and t3 app
191 appInstallResult = main.TRUE
192 if not main.persistentSetup:
193 if main.trellisOar:
194 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
195 if main.t3Oar:
196 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
197 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
198 onpass="SR app installation succeded",
199 onfail="SR app installation failed" )
200 if not appInstallResult:
201 main.cleanAndExit()
202
Jon Hall43060f62020-06-23 13:13:33 -0700203 Testcaselib.setOnosLogLevels( main )
204 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700205
Jon Hall1efcb3f2016-08-23 13:42:15 -0700206 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800207 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700208 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
209 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800210
211 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700212 def loadJson( main, suffix='' ):
213 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
214 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800215 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
216
217 @staticmethod
Siddesh606bd872021-06-29 23:42:36 +0000218 def loadNewJson( main, suffix='' ):
219 returnValue = main.TRUE
Siddeshde1d1692021-09-15 18:12:57 +0000220 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
Siddesh606bd872021-06-29 23:42:36 +0000221 main.cfgName, suffix ) ) as cfg:
222 desiredJSON = json.load ( cfg )
223 for device in desiredJSON ["ports"].keys():
224 deviceCfg = desiredJSON[ "ports" ][ device ]
225 currentJSON = main.Cluster.active( 0 ).REST.getNetCfg( subjectClass = "ports", subjectKey = device )
226
227 currentJSON = json.loads( currentJSON )
228 if currentJSON['interfaces'][0]['ips'] != deviceCfg['interfaces'][0]['ips']:
Siddeshd9840842021-08-06 19:26:05 +0000229 currentJSON['interfaces'][0]['ips'] = deviceCfg['interfaces'][0]['ips']
Siddesh606bd872021-06-29 23:42:36 +0000230 data = { 'interfaces': currentJSON['interfaces'] }
231 A = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
232 returnValue = returnValue and A
233 currentJSON['interfaces'] = deviceCfg['interfaces']
234 data = { 'interfaces': currentJSON['interfaces'] }
235 B = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
236 returnValue = returnValue and B
237 return returnValue
238
239 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700240 def loadXconnects( main, suffix='' ):
241 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
242 main.cfgName, suffix ) ) as cfg:
243 for xconnect in json.load( cfg ).get('xconnects'):
244 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
245
246 @staticmethod
Siddesh559d7412021-10-01 06:01:55 +0000247 def loadChart( main, suffix='' ):
Devin Lim57221b02018-02-14 15:45:36 -0800248 try:
Siddesh559d7412021-10-01 06:01:55 +0000249 filename = "%s%s.chart%s" % ( main.configPath + main.forChart,
250 main.cfgName, suffix )
Jon Hall32c90f32021-06-24 16:32:44 -0700251 with open( filename ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700252 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800253 except IOError:
Jon Hall32c90f32021-06-24 16:32:44 -0700254 main.log.warn( "No chart file found at %s" % filename )
Devin Lim57221b02018-02-14 15:45:36 -0800255
256 @staticmethod
257 def loadHost( main ):
258 with open( "%s%s.host" % ( main.configPath + main.forHost,
259 main.cfgName ) ) as host:
260 main.expectedHosts = json.load( host )
261
262 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800263 def loadSwitchFailureChart( main ):
264 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
265 main.cfgName ) ) as sfc:
266 main.switchFailureChart = json.load( sfc )
267
268 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800269 def loadLinkFailureChart( main ):
270 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700271 main.cfgName ) ) as lfc:
272 main.linkFailureChart = json.load( lfc )
273
274 @staticmethod
275 def loadMulticastConfig( main ):
276 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
277 main.cfgName ) ) as cfg:
278 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800279
280 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700281 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700282 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800283 copyResult = main.ONOSbench.scp( main.Mininet1,
284 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700285 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800286 direction="to" )
287 if main.topologyLib:
288 for lib in main.topologyLib.split(","):
289 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
290 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700291 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800292 direction="to" )
293 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700294 import re
295 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
296 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700297 destDir = "~/"
298 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
299 destDir = "/tmp/mn_conf/"
300 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800301 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700302 # Update zebra configurations with correct ONOS instance IP
303 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
304 ip = controllerIPs[ index ]
305 index = ( index + 1 ) % len( controllerIPs )
306 with open( main.configPath + main.forConfig + conf ) as f:
307 s = f.read()
308 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
309 with open( main.configPath + main.forConfig + conf, "w" ) as f:
310 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800311 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800312 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700313 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800314 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800315 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700316 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800317 main.Mininet1.home + "custom",
318 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700319
320 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
321 # move the config files into home
322 main.Mininet1.handle.sendline( "cp config/* . " )
323 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
324 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
325 main.Mininet1.handle.sendline( "ls -al " )
326 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
327 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
328
You Wangd87b2312018-01-30 12:47:17 -0800329 stepResult = copyResult
330 utilities.assert_equals( expect=main.TRUE,
331 actual=stepResult,
332 onpass="Successfully copied topo files",
333 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700334 if main.stratumRoot:
335 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700336 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700337 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700338 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700339 main.topology = topology
340 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700341 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700342 stepResult = topoResult
343 utilities.assert_equals( expect=main.TRUE,
344 actual=stepResult,
345 onpass="Successfully loaded topology",
346 onfail="Failed to load topology" )
347 # Exit if topology did not load properly
348 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700349 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700350 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700351 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700352 # Upload the net-cfg file created for each switch
353 filename = "onos-netcfg.json"
354 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700355 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700356 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
357 path = "/tmp/mn-stratum/%s/" % switch
358 dstPath = "/tmp/"
359 dstFileName = "%s-onos-netcfg.json" % switch
360 main.ONOSbench1.scp( main.Mininet1,
361 "%s%s" % ( path, filename ),
362 "%s%s" % ( dstPath, dstFileName ),
363 "from" )
364 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 -0700365 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700366 # Configure managementAddress
367 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
368 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
369 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
370 # Configure device id
371 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
372 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
373 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
374 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800375 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 -0700376 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
377 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700378 node = main.Cluster.active(0)
379 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
380 dstPath,
381 dstFileName,
382 user=node.REST.user_name,
383 password=node.REST.pwd )
384 # Stop test if we fail to push switch netcfg
385 utilities.assert_equals( expect=main.TRUE,
386 actual=switchNetCfg,
387 onpass="Successfully pushed switch netcfg",
388 onfail="Failed to configure switches in onos" )
389 if not switchNetCfg:
390 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700391 # Make sure hosts make some noise
392 Testcaselib.discoverHosts( main )
393
394 @staticmethod
395 def discoverHosts( main ):
396 # TODO add option to only select specific hosts
397 if hasattr( main, "Mininet1" ):
398 network = main.Mininet1
399 elif hasattr( main, "NetworkBench" ):
400 network = main.NetworkBench
401 else:
402 main.log.warn( "Could not find component for test network, skipping host discovery" )
403 return
404 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700405
406 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800407 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800408 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700409 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800410 topoResult = main.NetworkBench.connectToNet()
411 stepResult = topoResult
412 utilities.assert_equals( expect=main.TRUE,
413 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700414 onpass="Successfully connected to topology",
415 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800416 # Exit if topology did not load properly
417 if not topoResult:
418 main.cleanAndExit()
419
Jon Hall627b1572020-12-01 12:01:15 -0800420 if not main.persistentSetup:
421 # Perform any optional setup
422 for switch in main.NetworkBench.switches:
423 if hasattr( switch, "setup" ):
424 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700425
Jon Hall627b1572020-12-01 12:01:15 -0800426 main.step( "Assign switches to controllers." )
427 stepResult = main.TRUE
428 switches = main.NetworkBench.getSwitches()
429 pool = []
430 for name in switches.keys():
431 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
432 # e.g. push onos net-cfg for stratum switches
433 thread = main.Thread( target=main.NetworkBench.assignSwController,
434 name="assignSwitchToController",
435 args=[ name, main.Cluster.getIps(), '6653' ] )
436 pool.append( thread )
437 thread.start()
438 for thread in pool:
439 thread.join( 300 )
440 if not thread.result:
441 stepResult = main.FALSE
442 utilities.assert_equals( expect=main.TRUE,
443 actual=stepResult,
444 onpass="Successfully assign switches to controllers",
445 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800446
You Wang4cc61912018-08-28 10:10:58 -0700447 # Check devices
448 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700449 # Connecting to hosts that only have data plane connectivity
450 main.step( "Connecting inband hosts" )
451 stepResult = main.Network.connectInbandHosts()
452 utilities.assert_equals( expect=main.TRUE,
453 actual=stepResult,
454 onpass="Successfully connected inband hosts",
455 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800456 if hostDiscovery:
457 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700458
You Wang84f981d2018-01-12 16:11:50 -0800459 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700460 def saveOnosDiagnostics( main ):
461 """
462 Get onos-diags.tar.gz and save it to the log directory.
463 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
464 """
465 main.log.info( "Collecting onos-diags..." )
Jon Halla8cf76a2021-10-05 14:31:47 -0700466 podNames = []
Siddesha2938fe2021-04-06 02:46:06 +0000467 for ctrl in main.Cluster.runningNodes:
Jon Halla8cf76a2021-10-05 14:31:47 -0700468 if ctrl.k8s:
469 podNames.append( ctrl.k8s.podName )
470 else:
471 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress], main.logdir, "-CASE%d" % main.CurrentTestCaseNumber, onosPortnumber=ctrl.REST.port )
472 if podNames:
473 main.ONOSbench.onosDiagnosticsK8s( podNames, main.logdir, "-CASE%d" % main.CurrentTestCaseNumber )
You Wang5df1c6d2018-04-06 18:02:02 -0700474
475 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700476 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700477 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700478
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700479 main.failures = int( main.params[ 'failures' ] )
480 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700481
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700482 if main.cfgName == '2x2':
483 spine = {}
484 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
485 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
486 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700487
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700488 spine = {}
489 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
490 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
491 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700492
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700493 elif main.cfgName == '4x4':
494 spine = {}
495 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
496 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
497 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700498
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700499 spine = {}
500 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
501 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
502 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700503
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700504 spine = {}
505 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
506 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
507 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700508
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700509 spine = {}
510 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
511 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
512 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700513
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700514 else:
Piera2a7e1b2016-10-04 11:51:43 -0700515 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700516 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800517
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800518 @staticmethod
519 def addStaticOnosRoute( main, subnet, intf):
520 """
521 Adds an ONOS static route with the use route-add command.
522 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800523 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
524
Piera2a7e1b2016-10-04 11:51:43 -0700525 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700526 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700527 """
528 Check number of groups for each subnet on device deviceId and matches
529 it with an expected value. subnetDict is a dictionarty containing values
530 of the type "10.0.1.0/24" : 5.
531 """
You Wangc02f3be2018-05-18 12:14:23 -0700532 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
533 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
534 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700535
You Wangc02f3be2018-05-18 12:14:23 -0700536 result = main.TRUE
537 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700538 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700539 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700540 # this will match the group id that this flow entry points to, for example :
541 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700542 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700543 count = 0
544 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700545 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700546 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700547 if count - 1 != numberInSelect:
548 result = main.FALSE
549 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 ) )
550 utilities.assert_equals( expect=main.TRUE, actual=result,
551 onpass="All bucket numbers are as expected",
552 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700553
554 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700555 def checkFlows( main, minFlowCount, tag="", dumpFlows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700556 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800557 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900558 if tag == "":
559 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700560 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700561 main.FALSE,
562 kwargs={ 'min': minFlowCount },
563 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800564 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800565 if count == main.FALSE:
566 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700567 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700568 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800569 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700570 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
571 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700572
573 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700574 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700575 main.FALSE,
576 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800577 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800578 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700579 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700580 expect=main.TRUE,
581 actual=flowCheck,
582 onpass="Flow status is correct!",
583 onfail="Flow status is wrong!" )
Jon Hall32c90f32021-06-24 16:32:44 -0700584 if dumpFlows:
Devin Lim142b5342017-07-20 15:22:39 -0700585 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700586 "flows",
587 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800588 tag + "_FlowsBefore",
589 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700590 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700591 "groups",
592 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800593 tag + "_GroupsBefore",
594 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700595
596 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700597 def checkDevices( main, switches, tag="", sleep=10 ):
598 main.step(
599 "Check whether the switches count is equal to %s" % switches )
600 if tag == "":
601 tag = 'CASE%d' % main.CurrentTestCaseNumber
602 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
603 main.FALSE,
604 kwargs={ 'numoswitch': switches},
605 attempts=10,
606 sleep=sleep )
607 utilities.assert_equals( expect=main.TRUE, actual=result,
608 onpass="Device up successful",
609 onfail="Failed to boot up devices?" )
610
611 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800612 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
613 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800614 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800615 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
616 main.FALSE,
617 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800618 attempts=5,
619 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800620 if count == main.FALSE:
621 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800622 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800623 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800624 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800625 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800626 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800627
628 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700629 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800630 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700631 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800632 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
633 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700634 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800635 attempts=5,
636 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800637 if count == main.FALSE:
638 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800639 utilities.assertEquals(
640 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800641 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700642 onpass="Flow count looks correct: " + str( count ) ,
643 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800644
645 @staticmethod
646 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
647 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700648 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800649 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
650 main.FALSE,
651 args=( dpid, groupCount, False, 1),
652 attempts=5,
653 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800654 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800655 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800656 utilities.assertEquals(
657 expect=True,
658 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700659 onpass="Group count looks correct: " + str( count ) ,
660 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800661
662 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700663 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800664
665 for dpid, values in main.count.items():
666 flowCount = values["flows"]
667 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700668 main.log.report( "Check flow count for dpid " + str( dpid ) +
669 ", should be " + str( flowCount ) )
670 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800671
Jon Hall9677ed32018-04-24 11:16:23 -0700672 main.log.report( "Check group count for dpid " + str( dpid ) +
673 ", should be " + str( groupCount ) )
674 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800675
676 return
677
678 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700679 def pingAll( main, tag="", dumpFlows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800680 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800681 '''
You Wangba231e72018-03-01 13:18:21 -0800682 Verify connectivity between hosts according to the ping chart
683 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800684 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800685 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800686 '''
You Wangba231e72018-03-01 13:18:21 -0800687 main.log.report( "Check host connectivity" )
688 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800689 if tag == "":
690 tag = 'CASE%d' % main.CurrentTestCaseNumber
691 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800692 main.log.debug( "Entry in ping chart: %s" % entry )
693 expect = entry[ 'expect' ]
694 if expect == "Unidirectional":
695 # Verify ping from each src host to each dst host
696 src = entry[ 'src' ]
697 dst = entry[ 'dst' ]
698 expect = main.TRUE
699 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
700 if basedOnIp:
701 if ("v4" in src[0]):
702 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
703 utilities.assert_equals( expect=expect, actual=pa,
704 onpass="IPv4 connectivity successfully tested",
705 onfail="IPv4 connectivity failed" )
706 if ("v6" in src[0]):
707 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
708 utilities.assert_equals( expect=expect, actual=pa,
709 onpass="IPv6 connectivity successfully tested",
710 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700711 elif main.physicalNet:
712 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
713 utilities.assert_equals( expect=expect, actual=pa,
714 onpass="IP connectivity successfully tested",
715 onfail="IP connectivity failed" )
716
You Wangba231e72018-03-01 13:18:21 -0800717 else:
718 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
719 utilities.assert_equals( expect=expect, actual=pa,
720 onpass="IP connectivity successfully tested",
721 onfail="IP connectivity failed" )
722 else:
723 # Verify ping between each host pair
724 hosts = entry[ 'hosts' ]
725 try:
726 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
727 except:
728 expect = main.FALSE
729 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
730 if basedOnIp:
731 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800732 pa = utilities.retry( main.Network.pingallHosts,
733 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700734 args=(hosts, ),
735 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800736 attempts=retryAttempts,
737 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800738 utilities.assert_equals( expect=expect, actual=pa,
739 onpass="IPv4 connectivity successfully tested",
740 onfail="IPv4 connectivity failed" )
741 if ("v6" in hosts[0]):
742 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
743 utilities.assert_equals( expect=expect, actual=pa,
744 onpass="IPv6 connectivity successfully tested",
745 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700746 elif main.physicalNet:
Siddesh559d7412021-10-01 06:01:55 +0000747 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy, returnResult=True )
748 combinedResult = True
749 for result in pa:
750 expectedResult = None
751 for ping in main.pingChart.values():
752 if result["src"] in ping["hosts"] and result["dst"] in ping["hosts"]:
753 # Check if the vlan in ping is the same as in the result. If true, set the expected result to result at expect
754 # If expected result is not the same as the actual result, then the combined result is false
755 # if we cannot find the expected result, then expect should be the default between the hosts
756 if str(result["vlan"]) in ping.get("vlans", [] ):
757 expectedResult = ping["vlans"].get(str(result["vlan"]))
758 if expectedResult is None:
759 expectedRresult = expect
Siddeshb86c0e92021-10-05 22:14:45 +0000760 if expectedResult.lower() == "true":
761 expectedResult = main.TRUE
762 else:
763 expectedResult = main.FALSE
Siddesh559d7412021-10-01 06:01:55 +0000764 if expectedResult != result["result"]:
765 combinedResult = False
766 utilities.assert_equals( expect=True, actual=combinedResult,
Jon Hall43060f62020-06-23 13:13:33 -0700767 onpass="IP connectivity successfully tested",
768 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800769 else:
You Wangf19d9f42018-02-23 16:34:19 -0800770 pa = main.Network.pingallHosts( hosts )
771 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800772 onpass="IP connectivity successfully tested",
773 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700774 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700775 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700776 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700777 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700778 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800779
Jon Hall32c90f32021-06-24 16:32:44 -0700780 if dumpFlows:
781 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
782 "flows",
783 main.logdir,
784 tag + "_FlowsOn",
785 cliPort=main.Cluster.active(0).CLI.karafPort )
786 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
787 "groups",
788 main.logdir,
789 tag + "_GroupsOn",
790 cliPort=main.Cluster.active(0).CLI.karafPort )
791
792 @staticmethod
793 def pingAllFabricIntfs( main, srcList, tag="", dumpFlows=True, skipOnFail=False ):
794 '''
795 Verify connectivity between hosts and their fabric interfaces
796 '''
797 main.log.report( "Check host connectivity with fabric" )
798 if tag == "":
799 tag = 'CASE%d' % main.CurrentTestCaseNumber
800 expect = main.TRUE
801 import json
802 import re
803 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
804 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
805 for hostname in srcList:
806 try:
807 hostComponent = main.Network.hosts[ str( hostname ) ]
808 srcIface = hostComponent.interfaces[0].get( 'name' )
809 main.step( "Verify fabric connectivity for %s with tag %s" % ( str( hostname ), tag ) )
810 #Get host location, check netcfg for that port's ip
811 hostIp = hostComponent.getIPAddress( iface=srcIface )
812 main.log.warn( "Looking for %s" % hostIp )
813 ips = []
814 for obj in hostsJson:
815 if hostIp in obj['ipAddresses']:
816 for location in obj['locations']:
817 main.log.debug( location )
818 did = location['elementId'].encode( 'utf-8' )
819 port = location['port'].encode( 'utf-8' )
820 m = re.search( '\((\d+)\)', port )
821 if m:
822 port = m.group(1)
823 portId = "%s/%s" % ( did, port )
824 # Lookup ip assigned to this network port
825 ips.extend( [ x.encode( 'utf-8' ) for x in netcfgJson[ portId ][ 'interfaces' ][0][ 'ips' ] ] )
826 ips = set( ips )
827 ipRE = r'(\d+\.\d+\.\d+\.\d+)/\d+|([\w,:]*)/\d+'
828 for ip in ips:
829 ipMatch = re.search( ipRE, ip )
830 if ipMatch:
831 fabricIntfIp = ipMatch.group(1)
832 main.log.debug( "Found %s as gateway ip for %s" % ( fabricIntfIp, hostname ) )
833 pa = hostComponent.ping( fabricIntfIp, interface=srcIface )
834 utilities.assert_equals( expect=expect, actual=pa,
835 onpass="IP connectivity successfully tested",
836 onfail="IP connectivity failed" )
837 if pa != expect:
838 Testcaselib.saveOnosDiagnostics( main )
839 if skipOnFail:
840 Testcaselib.cleanup( main, copyKarafLog=False )
841 main.skipCase()
842 except ValueError:
843 main.log.exception( "Could not get gateway ip for %s" % hostname )
844
845 if dumpFlows:
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800846 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
847 "flows",
848 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800849 tag + "_FlowsOn",
850 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800851 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
852 "groups",
853 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800854 tag + "_GroupsOn",
855 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800856
857 @staticmethod
Jon Hall326501b2021-08-31 10:14:55 -0700858 def populateHostsVlan( main, hostList ):
859 """
860 Set the vlan for each host.
861 Checks what interface the host is configured on and reads the netcfg for that interface
862 """
863 import json
864 import re
865 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
866 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
867 for hostname in hostList:
868 try:
869 hostComponent = main.Network.hosts[ str( hostname ) ]
870 srcIface = hostComponent.interfaces[0].get( 'name' )
871 #Get host location, check netcfg for that port's ip
872 hostIp = hostComponent.getIPAddress( iface=srcIface )
Siddeshde1d1692021-09-15 18:12:57 +0000873 if not hostIp:
874 hostIp=hostComponent.interfaces[0].get( 'ips' )[0]
Jon Hall326501b2021-08-31 10:14:55 -0700875 main.log.warn( "Looking for allowed vlans for %s" % hostIp )
876 vlans = []
877 for obj in hostsJson:
878 if hostIp in obj['ipAddresses']:
879 for location in obj['locations']:
880 did = location['elementId'].encode( 'utf-8' )
881 port = location['port'].encode( 'utf-8' )
882 m = re.search( '\((\d+)\)', port )
883 if m:
884 port = m.group(1)
885 portId = "%s/%s" % ( did, port )
886 # Lookup ip assigned to this network port
887 # Valid host vlans:
888 # None if vlan-untagged
889 # vlanid if vlan-tagged: vlanid
890 # None if vlan-native + any vlan ids from vlan-tagged
891 intf = netcfgJson[ portId ][ 'interfaces' ][0]
Siddeshde1d1692021-09-15 18:12:57 +0000892 main.log.debug( intf )
Jon Hall326501b2021-08-31 10:14:55 -0700893 for field in intf.keys():
894 if "vlan-untagged" in field:
895 vlans.append( None )
896 if "vlan-tagged" in field:
Siddeshde1d1692021-09-15 18:12:57 +0000897 for VLAN in intf[ field ]:
898 vlans.append( VLAN )
Jon Hall326501b2021-08-31 10:14:55 -0700899 if "vlan-native" in field:
900 vlans.append( None )
901 if len( vlans ) == 0:
902 main.log.debug( "Could not find vlan setting for %s" % hostname )
903 vlans = set( vlans )
Siddeshd9840842021-08-06 19:26:05 +0000904 hostComponent.interfaces[0][ 'vlan' ] = list( vlans )
Jon Hall326501b2021-08-31 10:14:55 -0700905 main.log.debug( repr( hostComponent.interfaces[0] ) )
906 main.log.debug( repr( hostComponent.interfaces[0].get( 'vlan' ) ) )
907 except ValueError:
908 main.log.exception( "Error getting vlans for %s" % hostname )
909
910
911 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700912 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700913 """
914 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
915 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
916 Kill a link and verify ONOS can see the proper link change
917 """
Jon Halla604fd42018-05-04 14:27:27 -0700918 if sleep is None:
919 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
920 else:
921 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700922 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700923 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
924 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700925 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
926 onpass="Link down successful",
927 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700928 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700929 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700930 "Waiting %s seconds for link down to be discovered" % sleep )
931 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700932 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700933 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700934 main.FALSE,
935 kwargs={ 'numoswitch': switches,
936 'numolink': links },
937 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700938 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700939 utilities.assert_equals( expect=main.TRUE, actual=topology,
940 onpass="Topology after link down is correct",
941 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700942
943 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700944 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800945 """
946 links = list of links (src, dst) to bring down.
947 """
948
949 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700950 if sleep is None:
951 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
952 else:
953 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800954
955 for end1, end2 in links:
956 main.Network.link( END1=end1, END2=end2, OPTION="down")
957 main.Network.link( END1=end2, END2=end1, OPTION="down")
958
Jon Halla604fd42018-05-04 14:27:27 -0700959 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800960 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700961 "Waiting %s seconds for links down to be discovered" % sleep )
962 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800963
964 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
965 main.FALSE,
966 kwargs={ 'numoswitch': switches,
967 'numolink': linksAfter },
968 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700969 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800970
You Wang2854bce2018-03-30 10:15:32 -0700971 utilities.assert_equals( expect=main.TRUE, actual=topology,
972 onpass="Link batch down successful",
973 onfail="Link batch down failed" )
974
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800975 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700976 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800977 """
978 links = list of link (src, dst) to bring up again.
979 """
980
981 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700982 if sleep is None:
983 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
984 else:
985 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800986
987 for end1, end2 in links:
988 main.Network.link( END1=end1, END2=end2, OPTION="up")
989 main.Network.link( END1=end2, END2=end1, OPTION="up")
990
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800991 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700992 "Waiting %s seconds for links up to be discovered" % sleep )
993 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800994
995 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
996 main.FALSE,
997 kwargs={ 'numoswitch': switches,
998 'numolink': linksAfter },
999 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001000 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001001
You Wang2854bce2018-03-30 10:15:32 -07001002 utilities.assert_equals( expect=main.TRUE, actual=topology,
1003 onpass="Link batch up successful",
1004 onfail="Link batch up failed" )
1005
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001006 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001007 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
1008 """
1009 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1010 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
1011 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1012 """
1013 if sleep is None:
1014 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1015 else:
1016 sleep = float( sleep )
1017 main.step( "Disable a batch of ports" )
1018 for dpid, port in ports:
1019 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
1020 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
1021 time.sleep( sleep )
1022 if switches and links:
1023 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1024 numolink=links )
1025 utilities.assert_equals( expect=main.TRUE, actual=result,
1026 onpass="Port down successful",
1027 onfail="Port down failed" )
1028
1029 @staticmethod
1030 def enablePortBatch( main, ports, switches, links, sleep=None ):
1031 """
1032 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1033 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
1034 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1035 """
1036 if sleep is None:
1037 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1038 else:
1039 sleep = float( sleep )
1040 main.step( "Enable a batch of ports" )
1041 for dpid, port in ports:
1042 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
1043 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
1044 time.sleep( sleep )
1045 if switches and links:
1046 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1047 numolink=links )
1048 utilities.assert_equals( expect=main.TRUE, actual=result,
1049 onpass="Port up successful",
1050 onfail="Port up failed" )
1051
1052 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -07001053 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -07001054 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001055 """
1056 Params:
1057 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -07001058 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -07001059 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
1060 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
1061 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
1062 Kill a link and verify ONOS can see the proper link change
1063 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001064 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -07001065 if sleep is None:
1066 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1067 else:
1068 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001069 result = False
1070 count = 0
1071 while True:
1072 count += 1
Jon Halla604fd42018-05-04 14:27:27 -07001073 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -08001074 main.Network.link( END1=end1, END2=end2, OPTION="up" )
1075 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001076 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -07001077 "Waiting %s seconds for link up to be discovered" % sleep )
1078 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -07001079
You Wangc02d8352018-04-17 16:42:10 -07001080 if portUp:
1081 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
1082 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -07001083 main.log.info(
1084 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -07001085 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001086
Jon Halla604fd42018-05-04 14:27:27 -07001087 result = ctrl.CLI.checkStatus( numoswitch=switches,
1088 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001089 if count > 5 or result:
1090 break
1091 utilities.assert_equals( expect=main.TRUE, actual=result,
1092 onpass="Link up successful",
1093 onfail="Failed to bring link up" )
1094
1095 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001096 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001097 """
1098 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
1099 Completely kill a switch and verify ONOS can see the proper change
1100 """
Jon Halla604fd42018-05-04 14:27:27 -07001101 if sleep is None:
1102 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1103 else:
1104 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -07001105 switch = switch if isinstance( switch, list ) else [ switch ]
1106 main.step( "Kill " + str( switch ) )
1107 for s in switch:
1108 main.log.info( "Stopping " + s )
1109 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001110 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -07001111
1112 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -07001113 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001114 sleep ) )
1115 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001116 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001117 main.FALSE,
1118 kwargs={ 'numoswitch': switches,
1119 'numolink': links },
1120 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001121 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001122 utilities.assert_equals( expect=main.TRUE, actual=topology,
1123 onpass="Kill switch successful",
1124 onfail="Failed to kill switch?" )
1125
1126 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001127 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001128 """
1129 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
1130 Recover a switch and verify ONOS can see the proper change
1131 """
Jon Halla604fd42018-05-04 14:27:27 -07001132 if sleep is None:
1133 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1134 else:
1135 sleep = float( sleep )
1136 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -07001137 switch = switch if isinstance( switch, list ) else [ switch ]
1138 main.step( "Recovering " + str( switch ) )
1139 for s in switch:
1140 main.log.info( "Starting " + s )
1141 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001142 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001143 sleep ) )
1144 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001145 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -07001146 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001147 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001148 sleep ) )
1149 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001150
Devin Lim142b5342017-07-20 15:22:39 -07001151 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001152 main.FALSE,
1153 kwargs={ 'numoswitch': switches,
1154 'numolink': links },
1155 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001156 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001157 utilities.assert_equals( expect=main.TRUE, actual=topology,
1158 onpass="Switch recovery successful",
1159 onfail="Failed to recover switch?" )
1160
Jonghwan Hyun25c98a62018-05-04 13:59:09 -07001161 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -07001162 def killRouter( main, router, sleep=None ):
1163 """
1164 Kill bgpd process on a quagga router
1165 router: name of the router to be killed. E.g. "bgp1"
1166 """
1167 sleep = float( sleep )
1168 main.step( "Kill " + str( router ) )
1169 if hasattr( main, 'Mininet1' ):
1170 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
1171 main.Mininet1.handle.expect( "mininet>" )
1172 else:
1173 # TODO: support killing router in physical network
1174 pass
1175 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
1176 time.sleep( sleep )
1177
1178 @staticmethod
1179 def recoverRouter( main, router, sleep=None ):
1180 """
1181 Restart bgpd process on a quagga router
1182 router: name of the router to be recovered. E.g. "bgp1"
1183 """
1184 sleep = float( sleep )
1185 main.step( "Recovering " + str( router ) )
1186 if hasattr( main, 'Mininet1' ):
1187 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1188 main.Mininet1.handle.expect( "mininet>" )
1189 else:
1190 # TODO: support recovering router in physical network
1191 pass
1192 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1193 time.sleep( sleep )
1194
1195 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001196 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001197 """
1198 Stop Onos-cluster.
1199 Stops Mininet
1200 Copies ONOS log
1201 """
You Wang4cc61912018-08-28 10:10:58 -07001202 from tests.dependencies.utils import Utils
1203 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001204 if not main.persistentSetup:
1205 for ctrl in main.Cluster.active():
1206 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001207 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001208 if hasattr( main, "scapyHosts" ):
1209 scapyResult = main.TRUE
1210 for host in main.scapyHosts:
1211 scapyResult = host.stopScapy() and scapyResult
1212 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1213 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001214 if hasattr( main, 'Mininet1' ):
1215 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1216 else:
1217 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001218 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1219 main.scapyHosts = []
1220
You Wang5da39c82018-04-26 22:55:08 -07001221 if removeHostComponent:
Jon Hall22a3bcf2021-07-23 11:40:11 -07001222 try:
1223 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1224 if hasattr( main, host ):
1225 if hasattr( main, 'Mininet1' ):
1226 pass
1227 else:
1228 getattr( main, host ).disconnectInband()
1229 main.Network.removeHostComponent( host )
1230 except AttributeError as e:
1231 main.log.warn( "Could not cleanup host components: " + repr( e ) )
You Wang5da39c82018-04-26 22:55:08 -07001232
You Wang5df1c6d2018-04-06 18:02:02 -07001233 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001234 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001235 else:
1236 main.Network.disconnectInbandHosts()
1237 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001238
You Wang5df1c6d2018-04-06 18:02:02 -07001239 if copyKarafLog:
1240 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001241
Jon Hall627b1572020-12-01 12:01:15 -08001242 if not main.persistentSetup:
1243 for ctrl in main.Cluster.active():
1244 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001245 else:
1246 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001247 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001248
1249 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001250 def verifyNodes( main ):
1251 """
1252 Verifies Each active node in the cluster has an accurate view of other node's and their status
1253
1254 Params:
1255 nodes, integer array with position of the ONOS nodes in the CLIs array
1256 """
1257 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1258 False,
1259 attempts=10,
1260 sleep=10 )
1261 utilities.assert_equals( expect=True, actual=nodeResults,
1262 onpass="Nodes check successful",
1263 onfail="Nodes check NOT successful" )
1264
1265 if not nodeResults:
1266 for ctrl in main.Cluster.runningNodes:
1267 main.log.debug( "{} components not ACTIVE: \n{}".format(
1268 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001269 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001270 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001271 main.cleanAndExit()
1272
1273 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001274 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001275 """
1276 Verifies that the ONOS cluster has an acuurate view of the topology
1277
1278 Params:
1279 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 -08001280 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001281 """
1282 main.step( "Check number of topology elements" )
1283 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1284 main.FALSE,
1285 kwargs={ 'numoswitch': switches,
1286 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001287 'numoctrl': expNodes,
1288 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001289 attempts=10,
1290 sleep=12 )
1291 utilities.assert_equals( expect=main.TRUE, actual=topology,
1292 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001293 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001294
1295 @staticmethod
1296 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001297 """
1298 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1299 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1300 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1301 """
Jon Halla604fd42018-05-04 14:27:27 -07001302 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001303 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001304 if sleep is None:
1305 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1306 else:
1307 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001308
Jon Hall214f88b2020-09-21 10:21:42 -07001309 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001310 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001311 node = main.Cluster.runningNodes[ i ]
1312 if node.inDocker:
1313 killResult = node.server.dockerStop( node.name )
1314 else:
1315 killResult = main.ONOSbench.onosDie( node.ipAddress )
1316 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001317 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001318 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1319 onpass="ONOS instance Killed",
1320 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001321 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001322 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001323 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001324
Devin Lim142b5342017-07-20 15:22:39 -07001325 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001326 Testcaselib.verifyNodes( main )
1327 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001328
1329 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001330 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001331 """
1332 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1333 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1334 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1335 """
Jon Hall3c910162018-03-07 14:42:16 -08001336 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001337 if sleep is None:
1338 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1339 else:
1340 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001341 for i in nodes:
1342 node = main.Cluster.runningNodes[ i ]
1343 if node.inDocker:
1344 main.Cluster.startONOSDockerNode( i )
1345 else:
1346 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001347 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001348 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001349 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001350 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001351 if node.inDocker:
1352 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1353 isUp = isUp and node.CLI.prepareForCLI()
1354 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1355 else:
1356 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001357 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1358 onpass="ONOS service is ready",
1359 onfail="ONOS service did not start properly" )
1360 for i in nodes:
1361 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001362 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001363 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001364 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1365 commandlineTimeout=60,
1366 onosStartTimeout=100 )
1367 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001368 utilities.assert_equals( expect=main.TRUE,
1369 actual=cliResult,
1370 onpass="ONOS CLI is ready",
1371 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001372
Jon Halla604fd42018-05-04 14:27:27 -07001373 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001374 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001375 Testcaselib.verifyNodes( main )
1376 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001377
Devin Lim142b5342017-07-20 15:22:39 -07001378 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001379 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001380 attempts=10,
1381 sleep=12 )
1382 if ready:
1383 ready = main.TRUE
1384 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001385 onpass="ONOS summary command succeded",
1386 onfail="ONOS summary command failed" )
1387 if not ready:
1388 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001389 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001390
1391 @staticmethod
1392 def addHostCfg( main ):
1393 """
1394 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001395 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001396 """
1397 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001398 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001399 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001400 hostCfg = json.load( template )
1401 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1402 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001403 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001404 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1405 subjectClass="hosts",
1406 subjectKey=urllib.quote( mac,
1407 safe='' ),
1408 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001409 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1410 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001411 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001412 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1413 subjectClass="hosts",
1414 subjectKey=urllib.quote( mac,
1415 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001416 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001417 main.pingChart.update( { 'vlan1': { "expect": "True",
1418 "hosts": [ "olt1", "vsg1" ] } } )
1419 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1420 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001421 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1422 vlanId=1,
1423 port1=5,
1424 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001425
1426 @staticmethod
1427 def delHostCfg( main ):
1428 """
1429 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001430 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001431 """
1432 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001433 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001434 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001435 hostCfg = json.load( template )
1436 main.step( "Removing host configuration" )
1437 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001438 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001439 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1440 subjectKey=urllib.quote(
1441 mac,
1442 safe='' ),
1443 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001444 main.step( "Removing configuration" )
1445 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001446 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001447 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1448 subjectKey=urllib.quote(
1449 mac,
1450 safe='' ),
1451 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001452 main.step( "Removing vlan configuration" )
1453 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001454 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1455 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001456
1457 @staticmethod
1458 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1459 """
1460 Verifies IP address assignment from the hosts
1461 """
1462 main.step( "Verify IP address assignment from hosts" )
1463 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001464 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001465 # Find out names of disconnected hosts
1466 disconnectedHosts = []
1467 if hasattr( main, "disconnectedIpv4Hosts" ):
1468 for host in main.disconnectedIpv4Hosts:
1469 disconnectedHosts.append( host )
1470 if hasattr( main, "disconnectedIpv6Hosts" ):
1471 for host in main.disconnectedIpv6Hosts:
1472 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001473 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001474 # Exclude disconnected hosts
1475 if hostName in disconnectedHosts:
1476 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1477 continue
You Wang53dba1e2018-02-02 17:45:44 -08001478 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1479 main.FALSE,
1480 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001481 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001482 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001483 attempts=attempts,
1484 sleep=sleep )
1485 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1486 onpass="Verify network host IP succeded",
1487 onfail="Verify network host IP failed" )
1488
1489 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001490 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001491 """
1492 Verifies host IP address assignment from ONOS
1493 """
1494 main.step( "Verify host IP address assignment in ONOS" )
1495 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001496 # Find out IPs of disconnected hosts
1497 disconnectedIps = []
1498 if hasattr( main, "disconnectedIpv4Hosts" ):
1499 for host in main.disconnectedIpv4Hosts:
1500 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1501 if hasattr( main, "disconnectedIpv6Hosts" ):
1502 for host in main.disconnectedIpv6Hosts:
1503 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001504 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001505 # Exclude disconnected hosts
1506 if ip in disconnectedIps:
1507 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1508 continue
You Wang53dba1e2018-02-02 17:45:44 -08001509 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1510 main.FALSE,
1511 kwargs={ 'hostList': [ hostName ],
1512 'prefix': ip },
1513 attempts=attempts,
1514 sleep=sleep )
1515 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1516 onpass="Verify ONOS host IP succeded",
1517 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001518 if not ipResult and skipOnFail:
1519 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001520 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001521 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001522
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001523 @staticmethod
1524 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1525 """
1526 Description:
1527 Updates interface configuration in ONOS, with given IP and vlan parameters
1528 Required:
1529 * connectPoint: connect point to update configuration
1530 Optional:
1531 * ips: list of IP addresses, combined with '/xx' subnet representation,
1532 corresponding to 'ips' field in the configuration
1533 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1534 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1535 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1536 """
1537 cfg = dict()
1538 cfg[ "ports" ] = dict()
1539 cfg[ "ports" ][ connectPoint ] = dict()
1540 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1541 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1542 if untagged > 0:
1543 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1544 else:
1545 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1546 if native > 0:
1547 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1548
1549 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001550
1551 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001552 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001553 """
1554 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001555 scapyNames: list of names that will be used as component names for scapy hosts
1556 mininetNames: used when scapy host names are different from the host names
1557 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1558 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001559 """
1560 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001561 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1562 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001563 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001564 if hasattr( main, 'Mininet1' ):
1565 main.Scapy.createHostComponent( scapyName )
1566 scapyHandle = getattr( main, scapyName )
1567 if mininetNames:
1568 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1569 else:
1570 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001571 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1572 scapyHandle.mExecDir = "/tmp"
1573 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1574 main.log.debug( "start mn host component in docker" )
1575 scapyHandle.startHostCli( mininetName,
1576 execDir="/tmp",
1577 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1578 else:
1579 main.log.debug( "start mn host component" )
1580 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001581 else:
You Wang0fc21702018-11-02 17:49:18 -07001582 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001583 scapyHandle = getattr( main, scapyName )
1584 scapyHandle.connectInband()
1585 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001586 scapyHandle.startScapy()
1587 scapyHandle.updateSelf()
1588 main.log.debug( scapyHandle.name )
1589 main.log.debug( scapyHandle.hostIp )
1590 main.log.debug( scapyHandle.hostMac )
1591
1592 @staticmethod
1593 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1594 """
1595 Verify unicast traffic by pinging from source hosts to the destination IP
1596 and capturing the packets at the destination host using Scapy.
1597 srcHosts: List of host names to send the ping packets
1598 dstIp: destination IP of the ping packets
1599 dstHost: host that runs Scapy to capture the packets
1600 dstIntf: name of the interface on the destination host
1601 expect: use True if the ping is expected to be captured at destination;
1602 Otherwise False
1603 skipOnFail: skip the rest of this test case if result is not expected
1604 maxRetry: number of retries allowed
1605 """
1606 from tests.dependencies.topology import Topology
1607 try:
1608 main.topo
1609 except ( NameError, AttributeError ):
1610 main.topo = Topology()
1611 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1612 result = main.TRUE
1613 for srcHost in srcHosts:
1614 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1615 expect, maxRetry, True )
1616 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001617 result = main.FALSE
1618 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1619 utilities.assert_equals( expect=main.TRUE,
1620 actual=result,
1621 onpass="Verify traffic to {}: Pass".format( dstIp ),
1622 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1623 if skipOnFail and result != main.TRUE:
1624 Testcaselib.saveOnosDiagnostics( main )
1625 Testcaselib.cleanup( main, copyKarafLog=False )
1626 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001627
1628 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001629 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001630 """
1631 Verify multicast traffic using scapy
1632 """
You Wangc564c6f2018-05-01 15:24:57 -07001633 from tests.dependencies.topology import Topology
1634 try:
1635 main.topo
1636 except ( NameError, AttributeError ):
1637 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001638 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001639 routeData = main.multicastConfig[ routeName ]
1640 srcs = main.mcastRoutes[ routeName ][ "src" ]
1641 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1642 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1643 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001644 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001645 for src in srcs:
1646 srcEntry = routeData[ "src" ][ src ]
1647 for dst in dsts:
1648 dstEntry = routeData[ "dst" ][ dst ]
1649 sender = getattr( main, srcEntry[ "host" ] )
1650 receiver = getattr( main, dstEntry[ "host" ] )
1651 main.Network.addRoute( str( srcEntry[ "host" ] ),
1652 str( routeData[ "group" ] ),
1653 str( srcEntry[ "interface" ] ),
1654 True if routeData[ "ipVersion" ] == 6 else False )
1655 # Build the packet
1656 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1657 if routeData[ "ipVersion" ] == 4:
1658 sender.buildIP( dst=str( routeData[ "group" ] ) )
1659 elif routeData[ "ipVersion" ] == 6:
1660 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1661 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1662 sIface = srcEntry[ "interface" ]
1663 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1664 pktFilter = srcEntry[ "filter" ]
1665 pkt = srcEntry[ "packet" ]
1666 # Send packet and check received packet
1667 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001668 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001669 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001670 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1671 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001672 if not trafficResult:
1673 result = main.FALSE
1674 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1675 dstEntry[ "host" ] ) )
1676 utilities.assert_equals( expect=main.TRUE,
1677 actual=result,
1678 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1679 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001680 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001681 Testcaselib.saveOnosDiagnostics( main )
1682 Testcaselib.cleanup( main, copyKarafLog=False )
1683 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001684
1685 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001686 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001687 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1688 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001689 """
1690 Verify reachability from each host in srcList to each host in dstList
1691 """
1692 from tests.dependencies.topology import Topology
1693 try:
1694 main.topo
1695 except ( NameError, AttributeError ):
1696 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001697 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001698 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001699 utilities.assert_equals( expect=main.TRUE,
1700 actual=pingResult,
1701 onpass="{}: Pass".format( stepMsg ),
1702 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001703 if not pingResult and skipOnFail:
1704 Testcaselib.saveOnosDiagnostics( main )
1705 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1706 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001707
1708 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001709 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001710 """
1711 Verify if the specified host is discovered by ONOS on the given locations
1712 Required:
You Wang85747762018-05-11 15:51:50 -07001713 locationDict: a dictionary that maps host names to expected locations.
1714 locations could be a string or a list.
1715 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001716 Returns:
1717 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1718 """
You Wang85747762018-05-11 15:51:50 -07001719 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1720 result = main.TRUE
1721 for hostName, locations in locationDict.items():
1722 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1723 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1724 if not hostIp:
1725 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1726 if not hostIp:
1727 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1728 result = main.FALSE
1729 continue
1730 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1731 main.FALSE,
1732 args=( hostIp, locations ),
1733 attempts=retry + 1,
1734 sleep=10 )
1735 if not locationResult:
1736 result = main.FALSE
1737 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001738 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001739 onpass="Location verification passed",
1740 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001741
1742 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001743 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001744 """
1745 Move specified host from srcSw to dstSw.
1746 If srcSw and dstSw are same, the host will be moved from current port to
1747 next available port.
1748 Required:
1749 hostName: name of the host. e.g., "h1"
1750 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1751 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1752 gw: ip address of the gateway of the new location
1753 Optional:
1754 macAddr: if specified, change MAC address of the host to the specified MAC address.
1755 prefixLen: prefix length
1756 cfg: port configuration as JSON string
1757 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001758 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001759 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001760 if not hasattr( main, 'Mininet1' ):
1761 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1762 return
1763
You Wang6e5b48e2018-07-23 16:17:38 -07001764 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1765 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1766 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001767 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001768 if cfg:
1769 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1770 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001771 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001772 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001773 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001774
1775 main.Mininet1.discoverHosts( [ hostName, ] )
1776
1777 # Update expectedHost when MAC address is changed.
1778 if macAddr is not None:
1779 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1780 if ipAddr is not None:
1781 for hostName, ip in main.expectedHosts[ "onos" ].items():
1782 if ip == ipAddr:
1783 vlan = hostName.split( "/" )[ -1 ]
1784 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001785 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001786 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001787
1788 @staticmethod
1789 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001790 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001791 """
1792 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1793 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1794 to next available port.
1795 Required:
1796 hostName: name of the host. e.g., "h1"
1797 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1798 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1799 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1800 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1801 gw: ip address of the gateway of the new location
1802 Optional:
1803 macAddr: if specified, change MAC address of the host to the specified MAC address.
1804 prefixLen: prefix length
1805 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001806 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001807 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001808 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001809 if not hasattr( main, 'Mininet1' ):
1810 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1811 return
1812
You Wang6e5b48e2018-07-23 16:17:38 -07001813 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1814 srcSw, srcPairSw, dstSw, dstPairSw ) )
1815 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1816 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1817 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001818 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001819 if cfg:
1820 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1821 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001822 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001823 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001824 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001825
1826 main.Mininet1.discoverHosts( [ hostName, ] )
1827
1828 # Update expectedHost when MAC address is changed.
1829 if macAddr is not None:
1830 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1831 if ipAddr is not None:
1832 for hostName, ip in main.expectedHosts[ "onos" ].items():
1833 if ip == ipAddr:
1834 vlan = hostName.split( "/" )[ -1 ]
1835 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001836 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001837
1838 @staticmethod
1839 def mnDockerSetup( main ):
1840 """
1841 Optionally start and setup docker image for mininet
1842 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001843 try:
1844 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001845
Jon Hall9b0de1f2020-08-24 15:38:04 -07001846 main.log.info( "Creating Mininet Docker" )
1847 handle = main.Mininet1.handle
1848 # build docker image
1849 dockerFilePath = "%s/../dependencies/" % main.testDir
1850 dockerName = "trellis_mininet"
1851 # Stop any leftover container
1852 main.Mininet1.dockerStop( dockerName )
1853 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001854 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001855
Jon Hall9b0de1f2020-08-24 15:38:04 -07001856 confDir = "/tmp/mn_conf/"
1857 # Try to ensure the destination exists
1858 main.log.info( "Create folder for network config files" )
1859 handle.sendline( "rm -rf %s" % confDir )
1860 handle.expect( main.Mininet1.Prompt() )
1861 main.log.debug( handle.before + handle.after )
1862 handle.sendline( "mkdir -p %s" % confDir )
1863 handle.expect( main.Mininet1.Prompt() )
1864 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001865 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1866 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001867 # Make sure permissions are correct
1868 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1869 handle.expect( main.Mininet1.Prompt() )
1870 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1871 handle.expect( main.Mininet1.Prompt() )
1872 main.log.debug( handle.before + handle.after )
1873 # Start docker container
1874 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1875 dockerName,
1876 main.params[ 'MN_DOCKER' ][ 'args' ] )
1877 if runResponse == main.FALSE:
1878 main.log.error( "Docker container already running, aborting test" )
1879 main.cleanup()
1880 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001881
Jon Hall9b0de1f2020-08-24 15:38:04 -07001882 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1883 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001884
Jon Hall9b0de1f2020-08-24 15:38:04 -07001885 # Fow when we create component handles
1886 main.Mininet1.mExecDir = "/tmp"
1887 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1888 main.Mininet1.hostPrompt = "/home/root#"
1889
1890 # For some reason docker isn't doing this
1891 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1892 main.Mininet1.handle.expect( "etc/hosts" )
1893 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1894 except Exception as e:
1895 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001896 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001897
1898 @staticmethod
1899 def mnDockerTeardown( main ):
1900 """
1901 Optionally stop and cleanup docker image for mininet
1902 """
1903
1904 if hasattr( main, 'Mininet1' ):
1905 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001906 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001907
1908 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001909 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001910 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001911 main.Mininet1.sudoRequired = True
1912 except Exception as e:
1913 main.log.error( e )
1914
Jon Hall39570262020-11-17 12:18:19 -08001915 # Save docker logs
1916 copyResult = main.ONOSbench.scp( main.Mininet1,
1917 "/tmp/mn-stratum/*",
1918 main.logdir,
1919 direction="from",
1920 options="-rp" )
1921
1922
Jon Hall43060f62020-06-23 13:13:33 -07001923 @staticmethod
1924 def setOnosConfig( main ):
1925 """
1926 Read and Set onos configurations from the params file
1927 """
1928 main.step( "Set ONOS configurations" )
1929 config = main.params.get( 'ONOS_Configuration' )
1930 if config:
1931 main.log.debug( config )
1932 checkResult = main.TRUE
1933 for component in config:
1934 for setting in config[ component ]:
1935 value = config[ component ][ setting ]
1936 check = main.Cluster.next().setCfg( component, setting, value )
1937 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1938 checkResult = check and checkResult
1939 utilities.assert_equals( expect=main.TRUE,
1940 actual=checkResult,
1941 onpass="Successfully set config",
1942 onfail="Failed to set config" )
1943 else:
1944 main.log.warn( "No configurations were specified to be changed after startup" )
1945
1946 @staticmethod
1947 def setOnosLogLevels( main ):
1948 """
1949 Read and Set onos log levels from the params file
1950 """
1951 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001952 # Get original values incase we want to reset them
1953 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001954 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001955 ctrl.CLI.logList()
1956
Jon Hall43060f62020-06-23 13:13:33 -07001957 logging = True
1958 try:
1959 logs = main.params.get( 'ONOS_Logging', False )
1960 if logs:
1961 for namespace, level in logs.items():
1962 for ctrl in main.Cluster.active():
1963 ctrl.CLI.logSet( level, namespace )
1964 except AttributeError:
1965 logging = False
1966 utilities.assert_equals( expect=True, actual=logging,
1967 onpass="Set log levels",
1968 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001969
1970 @staticmethod
1971 def resetOnosLogLevels( main ):
1972 """
1973 Read and reset onos log levels to a previously read set of values
1974 """
1975 main.step( 'Reset logging levels' )
1976 # Get original values incase we want to reset them
1977 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001978 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001979 currentLevels = ctrl.CLI.logList( saveValues=False )
1980 origLevels = ctrl.CLI.logLevels
1981 toBeSet = {}
1982 for logger, level in currentLevels.iteritems():
1983 if logger not in origLevels:
1984 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1985 else:
1986 oldLevel = origLevels[ logger ]
1987 if level != oldLevel:
1988 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07001989 # In case a previous test didn't reset
1990 logs = main.params.get( 'ONOS_Logging_Reset', False )
1991 if logs:
1992 for namespace, level in logs.items():
1993 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08001994 logging = True
1995 try:
1996 for logger, level in toBeSet.iteritems():
1997 for ctrl in main.Cluster.active():
1998 ctrl.CLI.logSet( level, logger )
1999 except AttributeError:
2000 logging = False
2001 utilities.assert_equals( expect=True, actual=logging,
2002 onpass="Reset log levels",
2003 onfail="Failed to reset log levels" )