blob: 54e7d0fdb60238ee27315b1ddf5891c1c11b1a37 [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
Jon Hall7eb38402015-01-08 17:19:54 -08002"""
adminbae64d82013-08-01 10:50:15 -07003Created on 26-Oct-2012
4
Jon Hallbe6dfc42015-01-12 17:37:25 -08005author: Anil Kumar ( anilkumar.s@paxterrasolutions.com )
adminbae64d82013-08-01 10:50:15 -07006
7
Jon Hall7eb38402015-01-08 17:19:54 -08008TestON is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 of the License, or
11( at your option ) any later version.
adminbae64d82013-08-01 10:50:15 -070012
Jon Hall7eb38402015-01-08 17:19:54 -080013TestON is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
adminbae64d82013-08-01 10:50:15 -070017
Jon Hall7eb38402015-01-08 17:19:54 -080018You should have received a copy of the GNU General Public License
19along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070020
Jon Hallbe6dfc42015-01-12 17:37:25 -080021MininetCliDriver is the basic driver which will handle the Mininet functions
22
23Some functions rely on a modified version of Mininet. These functions
24should all be noted in the comments. To get this MN version run these commands
25from within your Mininet folder:
Jon Hall272a4db2015-01-12 17:43:48 -080026 git remote add jhall11 https://github.com/jhall11/mininet.git
Jon Hallbe6dfc42015-01-12 17:37:25 -080027 git fetch jhall11
Jon Hall272a4db2015-01-12 17:43:48 -080028 git checkout -b dynamic_topo remotes/jhall11/dynamic_topo
Jon Hallbe6dfc42015-01-12 17:37:25 -080029 git pull
30
Jon Hall272a4db2015-01-12 17:43:48 -080031
32 Note that you may need to run 'sudo make develop' if your mnexec.c file
Jon Hallbe6dfc42015-01-12 17:37:25 -080033changed when switching branches."""
adminbae64d82013-08-01 10:50:15 -070034import pexpect
adminbae64d82013-08-01 10:50:15 -070035import re
36import sys
kelvin-onlabfa6ada82015-06-11 13:06:24 -070037import types
kelvin-onlaba4074292015-07-09 15:19:49 -070038import os
Jon Hall1ccf82c2014-10-15 14:55:16 -040039from math import pow
adminbae64d82013-08-01 10:50:15 -070040from drivers.common.cli.emulatordriver import Emulator
adminbae64d82013-08-01 10:50:15 -070041
Jon Hall7eb38402015-01-08 17:19:54 -080042
kelvin-onlab50907142015-04-01 13:37:45 -070043class MininetCliDriver( Emulator ):
Jon Hall7eb38402015-01-08 17:19:54 -080044
45 """
46 MininetCliDriver is the basic driver which will handle
47 the Mininet functions"""
48 def __init__( self ):
49 super( Emulator, self ).__init__()
adminbae64d82013-08-01 10:50:15 -070050 self.handle = self
Jon Hallefbd9792015-03-05 16:11:36 -080051 self.name = None
kelvin-onlabd9e23de2015-08-06 10:34:44 -070052 self.home = None
Jon Hall7eb38402015-01-08 17:19:54 -080053 self.wrapped = sys.modules[ __name__ ]
adminbae64d82013-08-01 10:50:15 -070054 self.flag = 0
Jon Hall892818c2015-10-20 17:58:34 -070055 # TODO: Refactor driver to use these everywhere
56 self.mnPrompt = "mininet>"
57 self.hostPrompt = "~#"
58 self.bashPrompt = "\$"
59 self.scapyPrompt = ">>>"
adminbae64d82013-08-01 10:50:15 -070060
Jon Hall7eb38402015-01-08 17:19:54 -080061 def connect( self, **connectargs ):
62 """
63 Here the main is the TestON instance after creating
64 all the log handles."""
kelvin-onlaba1484582015-02-02 15:46:20 -080065 try:
66 for key in connectargs:
67 vars( self )[ key ] = connectargs[ key ]
kelvin-onlabd9e23de2015-08-06 10:34:44 -070068 self.home = "~/mininet"
kelvin-onlaba1484582015-02-02 15:46:20 -080069 self.name = self.options[ 'name' ]
kelvin-onlabd9e23de2015-08-06 10:34:44 -070070 for key in self.options:
71 if key == "home":
72 self.home = self.options[ 'home' ]
73 break
74 if self.home is None or self.home == "":
75 self.home = "~/mininet"
kelvin-onlaba4074292015-07-09 15:19:49 -070076
77 try:
Jon Hall892818c2015-10-20 17:58:34 -070078 if os.getenv( str( self.ip_address ) ) is not None:
kelvin-onlaba4074292015-07-09 15:19:49 -070079 self.ip_address = os.getenv( str( self.ip_address ) )
80 else:
81 main.log.info( self.name +
82 ": Trying to connect to " +
83 self.ip_address )
84
85 except KeyError:
86 main.log.info( "Invalid host name," +
87 " connecting to local host instead" )
88 self.ip_address = 'localhost'
89 except Exception as inst:
90 main.log.error( "Uncaught exception: " + str( inst ) )
91
kelvin-onlaba1484582015-02-02 15:46:20 -080092 self.handle = super(
kelvin-onlab50907142015-04-01 13:37:45 -070093 MininetCliDriver,
kelvin-onlaba1484582015-02-02 15:46:20 -080094 self ).connect(
95 user_name=self.user_name,
96 ip_address=self.ip_address,
97 port=None,
98 pwd=self.pwd )
Jon Hallfbc828e2015-01-06 17:30:19 -080099
kelvin-onlaba1484582015-02-02 15:46:20 -0800100 if self.handle:
Jon Hallefbd9792015-03-05 16:11:36 -0800101 main.log.info( "Connection successful to the host " +
102 self.user_name +
103 "@" +
104 self.ip_address )
kelvin-onlaba1484582015-02-02 15:46:20 -0800105 return main.TRUE
106 else:
107 main.log.error( "Connection failed to the host " +
Jon Hallefbd9792015-03-05 16:11:36 -0800108 self.user_name +
109 "@" +
110 self.ip_address )
Jon Hallfebb1c72015-03-05 13:30:09 -0800111 main.log.error( "Failed to connect to the Mininet CLI" )
kelvin-onlaba1484582015-02-02 15:46:20 -0800112 return main.FALSE
113 except pexpect.EOF:
114 main.log.error( self.name + ": EOF exception found" )
115 main.log.error( self.name + ": " + self.handle.before )
116 main.cleanup()
117 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -0800118 except Exception:
119 main.log.exception( self.name + ": Uncaught exception!" )
kelvin-onlaba1484582015-02-02 15:46:20 -0800120 main.cleanup()
121 main.exit()
122
kelvin-onlab10e8d392015-06-03 13:53:45 -0700123 def startNet( self, topoFile='', args='', mnCmd='', timeout=120 ):
kelvin-onlab00ac67b2015-02-04 09:52:02 -0800124 """
kelvin-onlabf512e942015-06-08 19:42:59 -0700125 Description:
126 Starts Mininet accepts a topology(.py) file and/or an optional
127 argument, to start the mininet, as a parameter.
128 Can also send regular mininet command to load up desired topology.
129 Eg. Pass in a string 'sudo mn --topo=tree,3,3' to mnCmd
130 Options:
131 topoFile = file path for topology file (.py)
132 args = extra option added when starting the topology from the file
133 mnCmd = Mininet command use to start topology
134 Returns:
135 main.TRUE if the mininet starts successfully, main.FALSE
136 otherwise
kelvin-onlab00ac67b2015-02-04 09:52:02 -0800137 """
Jon Hall7eb38402015-01-08 17:19:54 -0800138 if self.handle:
Jon Hall689d8e42015-04-03 13:59:24 -0700139 # make sure old networks are cleaned up
140 main.log.info( self.name +
141 ": Clearing any residual state or processes" )
Jon Hall7eb38402015-01-08 17:19:54 -0800142 self.handle.sendline( "sudo mn -c" )
143 i = self.handle.expect( [ 'password\sfor\s',
144 'Cleanup\scomplete',
145 pexpect.EOF,
146 pexpect.TIMEOUT ],
kelvin-onlaba1484582015-02-02 15:46:20 -0800147 timeout )
Jon Hall7eb38402015-01-08 17:19:54 -0800148 if i == 0:
Jon Hall689d8e42015-04-03 13:59:24 -0700149 # Sudo asking for password
Jon Hall7eb38402015-01-08 17:19:54 -0800150 main.log.info( self.name + ": Sending sudo password" )
151 self.handle.sendline( self.pwd )
Jon Hallefbd9792015-03-05 16:11:36 -0800152 i = self.handle.expect( [ '%s:' % self.user,
Jon Hall7eb38402015-01-08 17:19:54 -0800153 '\$',
154 pexpect.EOF,
155 pexpect.TIMEOUT ],
kelvin-onlaba1484582015-02-02 15:46:20 -0800156 timeout )
Jon Hall7eb38402015-01-08 17:19:54 -0800157 if i == 1:
158 main.log.info( self.name + ": Clean" )
159 elif i == 2:
160 main.log.error( self.name + ": Connection terminated" )
161 elif i == 3: # timeout
Jon Hall689d8e42015-04-03 13:59:24 -0700162 main.log.error( self.name + ": Something while cleaning " +
163 "Mininet took too long... " )
164 # Craft the string to start mininet
165 cmdString = "sudo "
kelvin-onlab10e8d392015-06-03 13:53:45 -0700166 if not mnCmd:
167 if topoFile is None or topoFile == '': # If no file is given
168 main.log.info( self.name + ": building fresh Mininet" )
169 cmdString += "mn "
170 if args is None or args == '':
171 # If no args given, use args from .topo file
172 args = self.options[ 'arg1' ] +\
Jon Halld80cc142015-07-06 13:36:05 -0700173 " " + self.options[ 'arg2' ] +\
174 " --mac --controller " +\
175 self.options[ 'controller' ] + " " +\
176 self.options[ 'arg3' ]
kelvin-onlab10e8d392015-06-03 13:53:45 -0700177 else: # else only use given args
178 pass
179 # TODO: allow use of topo args and method args?
180 else: # Use given topology file
Jon Halld80cc142015-07-06 13:36:05 -0700181 main.log.info(
182 "Starting Mininet from topo file " +
183 topoFile )
kelvin-onlab10e8d392015-06-03 13:53:45 -0700184 cmdString += topoFile + " "
185 if args is None:
186 args = ''
187 # TODO: allow use of args from .topo file?
188 cmdString += args
189 else:
190 main.log.info( "Starting Mininet topology using '" + mnCmd +
191 "' command" )
192 cmdString += mnCmd
Jon Hall689d8e42015-04-03 13:59:24 -0700193 # Send the command and check if network started
194 self.handle.sendline( "" )
195 self.handle.expect( '\$' )
196 main.log.info( "Sending '" + cmdString + "' to " + self.name )
197 self.handle.sendline( cmdString )
198 while True:
Jon Hall7eb38402015-01-08 17:19:54 -0800199 i = self.handle.expect( [ 'mininet>',
Jon Hall689d8e42015-04-03 13:59:24 -0700200 'Exception',
201 '\*\*\*',
Jon Hallefbd9792015-03-05 16:11:36 -0800202 pexpect.EOF,
203 pexpect.TIMEOUT ],
Jon Hall689d8e42015-04-03 13:59:24 -0700204 timeout )
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800205 if i == 0:
Jon Hall689d8e42015-04-03 13:59:24 -0700206 main.log.info( self.name + ": Mininet built" )
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800207 return main.TRUE
kelvin-onlabec228b82015-02-09 15:45:55 -0800208 elif i == 1:
Jon Hall689d8e42015-04-03 13:59:24 -0700209 response = str( self.handle.before +
210 self.handle.after )
211 self.handle.expect( '\$' )
212 response += str( self.handle.before +
Jon Halld80cc142015-07-06 13:36:05 -0700213 self.handle.after )
Jon Hall689d8e42015-04-03 13:59:24 -0700214 main.log.error(
215 self.name +
216 ": Launching Mininet failed: " + response )
217 return main.FALSE
218 elif i == 2:
219 self.handle.expect( [ "\n",
220 pexpect.EOF,
221 pexpect.TIMEOUT ],
222 timeout )
223 main.log.info( self.handle.before )
224 elif i == 3:
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800225 main.log.error( self.name + ": Connection timeout" )
226 return main.FALSE
Jon Hall689d8e42015-04-03 13:59:24 -0700227 elif i == 4: # timeout
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800228 main.log.error(
229 self.name +
230 ": Something took too long... " )
231 return main.FALSE
Jon Hall689d8e42015-04-03 13:59:24 -0700232 # Why did we hit this part?
233 main.log.error( "startNet did not return correctly" )
234 return main.FASLE
Jon Hall7eb38402015-01-08 17:19:54 -0800235 else: # if no handle
Jon Hall689d8e42015-04-03 13:59:24 -0700236 main.log.error( self.name + ": Connection failed to the host " +
237 self.user_name + "@" + self.ip_address )
Jon Hall7eb38402015-01-08 17:19:54 -0800238 main.log.error( self.name + ": Failed to connect to the Mininet" )
adminbae64d82013-08-01 10:50:15 -0700239 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800240
kelvin-onlabfccaafa2015-01-20 13:50:44 -0800241 def numSwitchesNlinks( self, topoType, depth, fanout ):
Jon Hall1ccf82c2014-10-15 14:55:16 -0400242 if topoType == 'tree':
Jon Hall7eb38402015-01-08 17:19:54 -0800243 # In tree topology, if fanout arg is not given, by default it is 2
244 if fanout is None:
Jon Hall1ccf82c2014-10-15 14:55:16 -0400245 fanout = 2
246 k = 0
Jon Hall38481722014-11-04 16:50:05 -0500247 count = 0
Jon Hall7eb38402015-01-08 17:19:54 -0800248 while( k <= depth - 1 ):
249 count = count + pow( fanout, k )
250 k = k + 1
kelvin-onlabd3b64892015-01-20 13:26:24 -0800251 numSwitches = count
Jon Hall7eb38402015-01-08 17:19:54 -0800252 while( k <= depth - 2 ):
253 # depth-2 gives you only core links and not considering
254 # edge links as seen by ONOS. If all the links including
255 # edge links are required, do depth-1
256 count = count + pow( fanout, k )
257 k = k + 1
kelvin-onlabd3b64892015-01-20 13:26:24 -0800258 numLinks = count * fanout
Jon Hall7eb38402015-01-08 17:19:54 -0800259 # print "num_switches for %s(%d,%d) = %d and links=%d" %(
kelvin-onlabd3b64892015-01-20 13:26:24 -0800260 # topoType,depth,fanout,numSwitches,numLinks )
Jon Hallfbc828e2015-01-06 17:30:19 -0800261
Jon Hall7eb38402015-01-08 17:19:54 -0800262 elif topoType == 'linear':
kelvin-onlabd3b64892015-01-20 13:26:24 -0800263 # In linear topology, if fanout or numHostsPerSw is not given,
Jon Hall7eb38402015-01-08 17:19:54 -0800264 # by default it is 1
265 if fanout is None:
Jon Hall1ccf82c2014-10-15 14:55:16 -0400266 fanout = 1
kelvin-onlabd3b64892015-01-20 13:26:24 -0800267 numSwitches = depth
268 numHostsPerSw = fanout
269 totalNumHosts = numSwitches * numHostsPerSw
270 numLinks = totalNumHosts + ( numSwitches - 1 )
Jon Hall7eb38402015-01-08 17:19:54 -0800271 print "num_switches for %s(%d,%d) = %d and links=%d" %\
kelvin-onlabd3b64892015-01-20 13:26:24 -0800272 ( topoType, depth, fanout, numSwitches, numLinks )
Jon Hallefbd9792015-03-05 16:11:36 -0800273 topoDict = { "num_switches": int( numSwitches ),
274 "num_corelinks": int( numLinks ) }
Jon Hall1ccf82c2014-10-15 14:55:16 -0400275 return topoDict
276
kelvin-onlabd3b64892015-01-20 13:26:24 -0800277 def calculateSwAndLinks( self ):
Jon Hall689d8e42015-04-03 13:59:24 -0700278 """
279 Calculate the number of switches and links in a topo."""
280 # TODO: combine this function and numSwitchesNlinks
281 argList = self.options[ 'arg1' ].split( "," )
282 topoArgList = argList[ 0 ].split( " " )
283 argList = map( int, argList[ 1: ] )
284 topoArgList = topoArgList[ 1: ] + argList
285
286 topoDict = self.numSwitchesNlinks( *topoArgList )
Jon Hall1ccf82c2014-10-15 14:55:16 -0400287 return topoDict
288
GlennRCf07c44a2015-09-18 13:33:46 -0700289 def pingall( self, protocol="IPv4", timeout=300, shortCircuit=False, acceptableFailed=0 ):
Jon Hall7eb38402015-01-08 17:19:54 -0800290 """
291 Verifies the reachability of the hosts using pingall command.
292 Optional parameter timeout allows you to specify how long to
293 wait for pingall to complete
kelvin-onlabfbcd82f2015-04-02 12:06:00 -0700294 Optional:
Jon Halld80cc142015-07-06 13:36:05 -0700295 timeout( seconds ) - How long to wait before breaking the pingall
kelvin-onlabfbcd82f2015-04-02 12:06:00 -0700296 shortCircuit - Break the pingall based on the number of failed hosts
kelvin-onlabc44f0192015-04-02 22:08:41 -0700297 ping
298 acceptableFailed - Set the number of acceptable failed pings for the
299 function to still return main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -0800300 Returns:
301 main.TRUE if pingall completes with no pings dropped
Jon Hall390696c2015-05-05 17:13:41 -0700302 otherwise main.FALSE
303 """
304 import time
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700305 try:
Jon Hallfb760a02015-04-13 15:35:03 -0700306 timeout = int( timeout )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700307 if self.handle:
308 main.log.info(
309 self.name +
310 ": Checking reachabilty to the hosts using pingall" )
311 response = ""
312 failedPings = 0
313 returnValue = main.TRUE
GlennRCf07c44a2015-09-18 13:33:46 -0700314 cmd = "pingall"
315 if protocol == "IPv6":
316 cmd = "py net.pingAll6()"
317 self.handle.sendline( cmd )
Jon Hall390696c2015-05-05 17:13:41 -0700318 startTime = time.time()
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700319 while True:
Jon Halld80cc142015-07-06 13:36:05 -0700320 i = self.handle.expect( [ "mininet>", "X",
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700321 pexpect.EOF,
322 pexpect.TIMEOUT ],
Jon Halld80cc142015-07-06 13:36:05 -0700323 timeout )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700324 if i == 0:
Jon Halld80cc142015-07-06 13:36:05 -0700325 main.log.info( self.name + ": pingall finished" )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700326 response += self.handle.before
327 break
328 elif i == 1:
329 response += self.handle.before + self.handle.after
330 failedPings = failedPings + 1
kelvin-onlabd26a3742015-04-06 15:31:16 -0700331 if failedPings > acceptableFailed:
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700332 returnValue = main.FALSE
333 if shortCircuit:
334 main.log.error( self.name +
335 ": Aborting pingall - "
336 + str( failedPings ) +
337 " pings failed" )
338 break
Jon Hall390696c2015-05-05 17:13:41 -0700339 if ( time.time() - startTime ) > timeout:
340 returnValue = main.FALSE
341 main.log.error( self.name +
342 ": Aborting pingall - " +
343 "Function took too long " )
344 break
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700345 elif i == 2:
346 main.log.error( self.name +
347 ": EOF exception found" )
348 main.log.error( self.name + ": " +
349 self.handle.before )
350 main.cleanup()
351 main.exit()
352 elif i == 3:
353 response += self.handle.before
354 main.log.error( self.name +
355 ": TIMEOUT exception found" )
356 main.log.error( self.name +
357 ": " +
358 str( response ) )
359 # NOTE: Send ctrl-c to make sure pingall is done
You Wangaf684312016-01-27 14:44:38 -0800360 self.handle.send( "\x03" )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700361 self.handle.expect( "Interrupt" )
362 self.handle.expect( "mininet>" )
363 break
364 pattern = "Results\:"
365 main.log.info( "Pingall output: " + str( response ) )
366 if re.search( pattern, response ):
367 main.log.info( self.name + ": Pingall finished with "
368 + str( failedPings ) + " failed pings" )
369 return returnValue
370 else:
kelvin-onlabc44f0192015-04-02 22:08:41 -0700371 # NOTE: Send ctrl-c to make sure pingall is done
You Wangaf684312016-01-27 14:44:38 -0800372 self.handle.send( "\x03" )
kelvin-onlabc44f0192015-04-02 22:08:41 -0700373 self.handle.expect( "Interrupt" )
kelvin-onlabc44f0192015-04-02 22:08:41 -0700374 self.handle.expect( "mininet>" )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700375 return main.FALSE
adminbae64d82013-08-01 10:50:15 -0700376 else:
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700377 main.log.error( self.name + ": Connection failed to the host" )
378 main.cleanup()
379 main.exit()
380 except pexpect.TIMEOUT:
381 if response:
382 main.log.info( "Pingall output: " + str( response ) )
383 main.log.error( self.name + ": pexpect.TIMEOUT found" )
384 return main.FALSE
385 except pexpect.EOF:
386 main.log.error( self.name + ": EOF exception found" )
387 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -0500388 main.cleanup()
389 main.exit()
adminaeedddd2013-08-02 15:14:15 -0700390
Jon Hall7eb38402015-01-08 17:19:54 -0800391 def fpingHost( self, **pingParams ):
392 """
393 Uses the fping package for faster pinging...
394 *requires fping to be installed on machine running mininet"""
kelvin-onlab7d0c9672015-01-20 15:56:22 -0800395 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
Jon Hall7eb38402015-01-08 17:19:54 -0800396 command = args[ "SRC" ] + \
397 " fping -i 100 -t 20 -C 1 -q " + args[ "TARGET" ]
398 self.handle.sendline( command )
399 self.handle.expect(
400 [ args[ "TARGET" ], pexpect.EOF, pexpect.TIMEOUT ] )
401 self.handle.expect( [ "mininet", pexpect.EOF, pexpect.TIMEOUT ] )
402 response = self.handle.before
403 if re.search( ":\s-", response ):
404 main.log.info( self.name + ": Ping fail" )
adminaeedddd2013-08-02 15:14:15 -0700405 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800406 elif re.search( ":\s\d{1,2}\.\d\d", response ):
407 main.log.info( self.name + ": Ping good!" )
adminaeedddd2013-08-02 15:14:15 -0700408 return main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -0800409 main.log.info( self.name + ": Install fping on mininet machine... " )
410 main.log.info( self.name + ": \n---\n" + response )
adminaeedddd2013-08-02 15:14:15 -0700411 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800412
Jon Hall3b489db2015-10-05 14:38:37 -0700413 def pingallHosts( self, hostList, wait=1 ):
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400414 """
Hari Krishna9592fc82015-07-31 15:11:15 -0700415 Ping all specified IPv4 hosts
kelvin-onlab2ff57022015-05-29 10:48:51 -0700416
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400417 Acceptable hostList:
Jon Halld80cc142015-07-06 13:36:05 -0700418 - [ 'h1','h2','h3','h4' ]
kelvin-onlab2ff57022015-05-29 10:48:51 -0700419
420 Returns main.TRUE if all hosts specified can reach
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400421 each other
kelvin-onlab2ff57022015-05-29 10:48:51 -0700422
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400423 Returns main.FALSE if one or more of hosts specified
424 cannot reach each other"""
Jon Hall3b489db2015-10-05 14:38:37 -0700425 wait = int( wait )
426 cmd = " ping -c 1 -i 1 -W " + str( wait ) + " "
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400427
428 try:
429 main.log.info( "Testing reachability between specified hosts" )
kelvin-onlab2ff57022015-05-29 10:48:51 -0700430
andrew@onlab.usdefe38c2015-05-14 19:18:18 -0400431 isReachable = main.TRUE
GlennRC6d506272015-09-25 11:36:07 -0700432 pingResponse = "IPv4 ping across specified hosts\n"
433 failedPings = 0
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400434 for host in hostList:
Jon Halld80cc142015-07-06 13:36:05 -0700435 listIndex = hostList.index( host )
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400436 # List of hosts to ping other than itself
Jon Halld80cc142015-07-06 13:36:05 -0700437 pingList = hostList[ :listIndex ] + \
438 hostList[ ( listIndex + 1 ): ]
GlennRCd10d3cc2015-09-24 12:47:16 -0700439
440 pingResponse += str(str(host) + " -> ")
441
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400442 for temp in pingList:
443 # Current host pings all other hosts specified
Jon Halld80cc142015-07-06 13:36:05 -0700444 pingCmd = str( host ) + cmd + str( temp )
Jon Hall934576d2015-10-09 10:12:22 -0700445 self.handle.sendline( pingCmd )
446 self.handle.expect( "mininet>", timeout=wait + 1 )
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400447 response = self.handle.before
448 if re.search( ',\s0\%\spacket\sloss', response ):
GlennRCd10d3cc2015-09-24 12:47:16 -0700449 pingResponse += str(" h" + str( temp[1:] ))
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400450 else:
GlennRCd10d3cc2015-09-24 12:47:16 -0700451 pingResponse += " X"
andrew@onlab.usdefe38c2015-05-14 19:18:18 -0400452 # One of the host to host pair is unreachable
453 isReachable = main.FALSE
GlennRC6d506272015-09-25 11:36:07 -0700454 failedPings += 1
GlennRCd10d3cc2015-09-24 12:47:16 -0700455 pingResponse += "\n"
GlennRC6d506272015-09-25 11:36:07 -0700456 main.log.info( pingResponse + "Failed pings: " + str(failedPings) )
kelvin-onlab2ff57022015-05-29 10:48:51 -0700457 return isReachable
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700458 except pexpect.TIMEOUT:
459 main.log.exception( self.name + ": TIMEOUT exception" )
Hari Krishna4223dbd2015-08-13 16:29:53 -0700460 return main.FALSE
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400461 except pexpect.EOF:
462 main.log.error( self.name + ": EOF exception found" )
463 main.log.error( self.name + ": " + self.handle.before )
464 main.cleanup()
465 main.exit()
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700466 except Exception:
467 main.log.exception( self.name + ": Uncaught exception!" )
468 main.cleanup()
469 main.exit()
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400470
Jon Hall3b489db2015-10-05 14:38:37 -0700471 def pingIpv6Hosts( self, hostList, prefix='1000::', wait=1 ):
Hari Krishna9592fc82015-07-31 15:11:15 -0700472 """
Jon Hall3b489db2015-10-05 14:38:37 -0700473 IPv6 ping all hosts in hostList. If no prefix passed this will use
474 default prefix of 1000::
Hari Krishna9592fc82015-07-31 15:11:15 -0700475
Jon Hall3b489db2015-10-05 14:38:37 -0700476 Returns main.TRUE if all hosts specified can reach each other
Hari Krishna9592fc82015-07-31 15:11:15 -0700477
Jon Hall3b489db2015-10-05 14:38:37 -0700478 Returns main.FALSE if one or more of hosts specified cannot reach each other
Hari Krishna9592fc82015-07-31 15:11:15 -0700479 """
480 try:
481 main.log.info( "Testing reachability between specified IPv6 hosts" )
482 isReachable = main.TRUE
Jon Hall3b489db2015-10-05 14:38:37 -0700483 wait = int( wait )
484 cmd = " ping6 -c 1 -i 1 -W " + str( wait ) + " "
GlennRC6d506272015-09-25 11:36:07 -0700485 pingResponse = "IPv6 Pingall output:\n"
486 failedPings = 0
Hari Krishna9592fc82015-07-31 15:11:15 -0700487 for host in hostList:
488 listIndex = hostList.index( host )
489 # List of hosts to ping other than itself
490 pingList = hostList[ :listIndex ] + \
491 hostList[ ( listIndex + 1 ): ]
492
GlennRC2cf7d952015-09-11 16:32:13 -0700493 pingResponse += str(str(host) + " -> ")
494
Hari Krishna9592fc82015-07-31 15:11:15 -0700495 for temp in pingList:
496 # Current host pings all other hosts specified
497 pingCmd = str( host ) + cmd + prefix + str( temp[1:] )
Jon Hall934576d2015-10-09 10:12:22 -0700498 self.handle.sendline( pingCmd )
499 self.handle.expect( "mininet>", timeout=wait + 1 )
Hari Krishna9592fc82015-07-31 15:11:15 -0700500 response = self.handle.before
501 if re.search( ',\s0\%\spacket\sloss', response ):
GlennRC2cf7d952015-09-11 16:32:13 -0700502 pingResponse += str(" h" + str( temp[1:] ))
Hari Krishna9592fc82015-07-31 15:11:15 -0700503 else:
GlennRC2cf7d952015-09-11 16:32:13 -0700504 pingResponse += " X"
Hari Krishna9592fc82015-07-31 15:11:15 -0700505 # One of the host to host pair is unreachable
506 isReachable = main.FALSE
GlennRC6d506272015-09-25 11:36:07 -0700507 failedPings += 1
GlennRCd10d3cc2015-09-24 12:47:16 -0700508 pingResponse += "\n"
GlennRC6d506272015-09-25 11:36:07 -0700509 main.log.info( pingResponse + "Failed pings: " + str(failedPings) )
Hari Krishna9592fc82015-07-31 15:11:15 -0700510 return isReachable
511
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700512 except pexpect.TIMEOUT:
513 main.log.exception( self.name + ": TIMEOUT exception" )
514 return main.FALSE
Hari Krishna9592fc82015-07-31 15:11:15 -0700515 except pexpect.EOF:
516 main.log.error( self.name + ": EOF exception found" )
517 main.log.error( self.name + ": " + self.handle.before )
518 main.cleanup()
519 main.exit()
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700520 except Exception:
521 main.log.exception( self.name + ": Uncaught exception!" )
522 main.cleanup()
523 main.exit()
Hari Krishna9592fc82015-07-31 15:11:15 -0700524
Jon Hall7eb38402015-01-08 17:19:54 -0800525 def pingHost( self, **pingParams ):
526 """
Jon Hall3b489db2015-10-05 14:38:37 -0700527 Ping from one mininet host to another
528 Currently the only supported Params: SRC, TARGET, and WAIT
529 """
530 args = utilities.parse_args( [ "SRC", "TARGET", 'WAIT' ], **pingParams )
531 wait = args['WAIT']
532 wait = int( wait if wait else 1 )
Jon Hall7eb38402015-01-08 17:19:54 -0800533 command = args[ "SRC" ] + " ping " + \
Jon Hall3b489db2015-10-05 14:38:37 -0700534 args[ "TARGET" ] + " -c 1 -i 1 -W " + str( wait ) + " "
Jon Hall6094a362014-04-11 14:46:56 -0700535 try:
Jon Hall61282e32015-03-19 11:34:11 -0700536 main.log.info( "Sending: " + command )
Jon Hall7eb38402015-01-08 17:19:54 -0800537 self.handle.sendline( command )
Jon Hall3b489db2015-10-05 14:38:37 -0700538 i = self.handle.expect( [ command, pexpect.TIMEOUT ],
539 timeout=wait + 1 )
Jon Hall6e18c7b2014-04-23 16:26:33 -0700540 if i == 1:
Jon Hall7eb38402015-01-08 17:19:54 -0800541 main.log.error(
542 self.name +
543 ": timeout when waiting for response from mininet" )
544 main.log.error( "response: " + str( self.handle.before ) )
545 i = self.handle.expect( [ "mininet>", pexpect.TIMEOUT ] )
Jon Hall6e18c7b2014-04-23 16:26:33 -0700546 if i == 1:
Jon Hall7eb38402015-01-08 17:19:54 -0800547 main.log.error(
548 self.name +
549 ": timeout when waiting for response from mininet" )
550 main.log.error( "response: " + str( self.handle.before ) )
Jon Hall6e18c7b2014-04-23 16:26:33 -0700551 response = self.handle.before
Hari Krishna012a1c12015-08-25 14:23:58 -0700552 if re.search( ',\s0\%\spacket\sloss', response ):
553 main.log.info( self.name + ": no packets lost, host is reachable" )
554 return main.TRUE
555 else:
556 main.log.error(
557 self.name +
558 ": PACKET LOST, HOST IS NOT REACHABLE" )
559 return main.FALSE
560
Jon Hallfbc828e2015-01-06 17:30:19 -0800561 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800562 main.log.error( self.name + ": EOF exception found" )
563 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700564 main.cleanup()
565 main.exit()
Hari Krishna012a1c12015-08-25 14:23:58 -0700566 except Exception:
567 main.log.exception( self.name + ": Uncaught exception!" )
568 main.cleanup()
569 main.exit()
570
571 def ping6pair( self, **pingParams ):
572 """
GlennRC2cf7d952015-09-11 16:32:13 -0700573 IPv6 Ping between a pair of mininet hosts
Jon Hall3b489db2015-10-05 14:38:37 -0700574 Currently the only supported Params are: SRC, TARGET, and WAIT
Hari Krishna012a1c12015-08-25 14:23:58 -0700575 FLOWLABEL and -I (src interface) will be added later after running some tests.
576 Example: main.Mininet1.ping6pair( src="h1", target="1000::2" )
577 """
Jon Hall3b489db2015-10-05 14:38:37 -0700578 args = utilities.parse_args( [ "SRC", "TARGET", 'WAIT' ], **pingParams )
579 wait = args['WAIT']
580 wait = int( wait if wait else 1 )
Subhash Kumar Singhbcc1c792015-11-07 04:52:11 +0530581 command = args[ "SRC" ] + " ping6 " + \
Jon Hall3b489db2015-10-05 14:38:37 -0700582 args[ "TARGET" ] + " -c 1 -i 1 -W " + str( wait ) + " "
Hari Krishna012a1c12015-08-25 14:23:58 -0700583 try:
584 main.log.info( "Sending: " + command )
585 self.handle.sendline( command )
Jon Hall3b489db2015-10-05 14:38:37 -0700586 i = self.handle.expect( [ command, pexpect.TIMEOUT ],
587 timeout=wait + 1 )
Hari Krishna012a1c12015-08-25 14:23:58 -0700588 if i == 1:
589 main.log.error(
590 self.name +
591 ": timeout when waiting for response from mininet" )
592 main.log.error( "response: " + str( self.handle.before ) )
593 i = self.handle.expect( [ "mininet>", pexpect.TIMEOUT ] )
594 if i == 1:
595 main.log.error(
596 self.name +
597 ": timeout when waiting for response from mininet" )
598 main.log.error( "response: " + str( self.handle.before ) )
599 response = self.handle.before
600 main.log.info( self.name + ": Ping Response: " + response )
601 if re.search( ',\s0\%\spacket\sloss', response ):
602 main.log.info( self.name + ": no packets lost, host is reachable" )
GlennRC2cf7d952015-09-11 16:32:13 -0700603 return main.TRUE
Hari Krishna012a1c12015-08-25 14:23:58 -0700604 else:
605 main.log.error(
606 self.name +
607 ": PACKET LOST, HOST IS NOT REACHABLE" )
608 return main.FALSE
609
610 except pexpect.EOF:
611 main.log.error( self.name + ": EOF exception found" )
612 main.log.error( self.name + ": " + self.handle.before )
613 main.cleanup()
614 main.exit()
615 except Exception:
616 main.log.exception( self.name + ": Uncaught exception!" )
617 main.cleanup()
618 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -0800619
Jon Hall7eb38402015-01-08 17:19:54 -0800620 def checkIP( self, host ):
621 """
622 Verifies the host's ip configured or not."""
623 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -0700624 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800625 response = self.execute(
626 cmd=host +
627 " ifconfig",
628 prompt="mininet>",
629 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800630 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800631 main.log.error( self.name + ": EOF exception found" )
632 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700633 main.cleanup()
634 main.exit()
adminbae64d82013-08-01 10:50:15 -0700635
Jon Hall7eb38402015-01-08 17:19:54 -0800636 pattern = "inet\s(addr|Mask):([0-1]{1}[0-9]{1,2}|" +\
kelvin-onlabedcff052015-01-16 12:53:55 -0800637 "2[0-4][0-9]|25[0-5]|[0-9]{1,2}).([0-1]{1}" +\
638 "[0-9]{1,2}|2[0-4][0-9]|25[0-5]|[0-9]{1,2})." +\
639 "([0-1]{1}[0-9]{1,2}|2[0-4][0-9]|25[0-5]|" +\
640 "[0-9]{1,2}).([0-1]{1}[0-9]{1,2}|2[0-4]" +\
641 "[0-9]|25[0-5]|[0-9]{1,2})"
Jon Hall7eb38402015-01-08 17:19:54 -0800642 # pattern = "inet addr:10.0.0.6"
643 if re.search( pattern, response ):
644 main.log.info( self.name + ": Host Ip configured properly" )
adminbae64d82013-08-01 10:50:15 -0700645 return main.TRUE
646 else:
Jon Hall7eb38402015-01-08 17:19:54 -0800647 main.log.error( self.name + ": Host IP not found" )
adminbae64d82013-08-01 10:50:15 -0700648 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800649 else:
650 main.log.error( self.name + ": Connection failed to the host" )
Jon Hallfbc828e2015-01-06 17:30:19 -0800651
Jon Hall7eb38402015-01-08 17:19:54 -0800652 def verifySSH( self, **connectargs ):
Jon Hallefbd9792015-03-05 16:11:36 -0800653 # FIXME: Who uses this and what is the purpose? seems very specific
Jon Hall6094a362014-04-11 14:46:56 -0700654 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800655 response = self.execute(
656 cmd="h1 /usr/sbin/sshd -D&",
657 prompt="mininet>",
658 timeout=10 )
659 response = self.execute(
660 cmd="h4 /usr/sbin/sshd -D&",
661 prompt="mininet>",
662 timeout=10 )
Jon Hall6094a362014-04-11 14:46:56 -0700663 for key in connectargs:
Jon Hall7eb38402015-01-08 17:19:54 -0800664 vars( self )[ key ] = connectargs[ key ]
665 response = self.execute(
666 cmd="xterm h1 h4 ",
667 prompt="mininet>",
668 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800669 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800670 main.log.error( self.name + ": EOF exception found" )
671 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700672 main.cleanup()
673 main.exit()
adminbae64d82013-08-01 10:50:15 -0700674 import time
Jon Hall7eb38402015-01-08 17:19:54 -0800675 time.sleep( 20 )
adminbae64d82013-08-01 10:50:15 -0700676 if self.flag == 0:
677 self.flag = 1
678 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800679 else:
adminbae64d82013-08-01 10:50:15 -0700680 return main.TRUE
shahshreyae6c7cf42014-11-26 16:39:01 -0800681
kelvin-onlaba1484582015-02-02 15:46:20 -0800682 def moveHost( self, host, oldSw, newSw, ):
683 """
684 Moves a host from one switch to another on the fly
685 Note: The intf between host and oldSw when detached
686 using detach(), will still show up in the 'net'
687 cmd, because switch.detach() doesn't affect switch.intfs[]
Jon Halld80cc142015-07-06 13:36:05 -0700688 ( which is correct behavior since the interfaces
689 haven't moved ).
kelvin-onlaba1484582015-02-02 15:46:20 -0800690 """
691 if self.handle:
692 try:
693 # Bring link between oldSw-host down
Jon Halld80cc142015-07-06 13:36:05 -0700694 cmd = "py net.configLinkStatus('" + oldSw + "'," + "'" + host +\
Jon Hallefbd9792015-03-05 16:11:36 -0800695 "'," + "'down')"
kelvin-onlaba1484582015-02-02 15:46:20 -0800696 print "cmd1= ", cmd
Jon Hallefbd9792015-03-05 16:11:36 -0800697 response = self.execute( cmd=cmd,
698 prompt="mininet>",
699 timeout=10 )
Jon Hallafa8a472015-06-12 14:02:42 -0700700
kelvin-onlaba1484582015-02-02 15:46:20 -0800701 # Determine hostintf and Oldswitchintf
702 cmd = "px hintf,sintf = " + host + ".connectionsTo(" + oldSw +\
Jon Hallefbd9792015-03-05 16:11:36 -0800703 ")[0]"
kelvin-onlaba1484582015-02-02 15:46:20 -0800704 print "cmd2= ", cmd
705 self.handle.sendline( cmd )
706 self.handle.expect( "mininet>" )
707
shahshreya73537862015-02-11 15:15:24 -0800708 # Determine ip and mac address of the host-oldSw interface
kelvin-onlaba1484582015-02-02 15:46:20 -0800709 cmd = "px ipaddr = hintf.IP()"
710 print "cmd3= ", cmd
711 self.handle.sendline( cmd )
712 self.handle.expect( "mininet>" )
shahshreya73537862015-02-11 15:15:24 -0800713
714 cmd = "px macaddr = hintf.MAC()"
715 print "cmd3= ", cmd
716 self.handle.sendline( cmd )
717 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700718
kelvin-onlaba1484582015-02-02 15:46:20 -0800719 # Detach interface between oldSw-host
720 cmd = "px " + oldSw + ".detach( sintf )"
721 print "cmd4= ", cmd
722 self.handle.sendline( cmd )
723 self.handle.expect( "mininet>" )
724
725 # Add link between host-newSw
726 cmd = "py net.addLink(" + host + "," + newSw + ")"
727 print "cmd5= ", cmd
728 self.handle.sendline( cmd )
729 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700730
kelvin-onlaba1484582015-02-02 15:46:20 -0800731 # Determine hostintf and Newswitchintf
732 cmd = "px hintf,sintf = " + host + ".connectionsTo(" + newSw +\
Jon Hallefbd9792015-03-05 16:11:36 -0800733 ")[0]"
kelvin-onlaba1484582015-02-02 15:46:20 -0800734 print "cmd6= ", cmd
735 self.handle.sendline( cmd )
Jon Hallafa8a472015-06-12 14:02:42 -0700736 self.handle.expect( "mininet>" )
kelvin-onlaba1484582015-02-02 15:46:20 -0800737
738 # Attach interface between newSw-host
739 cmd = "px " + newSw + ".attach( sintf )"
740 print "cmd3= ", cmd
741 self.handle.sendline( cmd )
742 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700743
kelvin-onlaba1484582015-02-02 15:46:20 -0800744 # Set ipaddress of the host-newSw interface
745 cmd = "px " + host + ".setIP( ip = ipaddr, intf = hintf)"
746 print "cmd7 = ", cmd
747 self.handle.sendline( cmd )
748 self.handle.expect( "mininet>" )
shahshreya73537862015-02-11 15:15:24 -0800749
750 # Set macaddress of the host-newSw interface
751 cmd = "px " + host + ".setMAC( mac = macaddr, intf = hintf)"
752 print "cmd8 = ", cmd
753 self.handle.sendline( cmd )
754 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700755
kelvin-onlaba1484582015-02-02 15:46:20 -0800756 cmd = "net"
shahshreya73537862015-02-11 15:15:24 -0800757 print "cmd9 = ", cmd
kelvin-onlaba1484582015-02-02 15:46:20 -0800758 self.handle.sendline( cmd )
759 self.handle.expect( "mininet>" )
760 print "output = ", self.handle.before
761
762 # Determine ipaddress of the host-newSw interface
shahshreya73537862015-02-11 15:15:24 -0800763 cmd = host + " ifconfig"
764 print "cmd10= ", cmd
kelvin-onlaba1484582015-02-02 15:46:20 -0800765 self.handle.sendline( cmd )
766 self.handle.expect( "mininet>" )
767 print "ifconfig o/p = ", self.handle.before
Jon Hallafa8a472015-06-12 14:02:42 -0700768
kelvin-onlaba1484582015-02-02 15:46:20 -0800769 return main.TRUE
770 except pexpect.EOF:
771 main.log.error( self.name + ": EOF exception found" )
772 main.log.error( self.name + ": " + self.handle.before )
773 return main.FALSE
774
Jon Hall7eb38402015-01-08 17:19:54 -0800775 def changeIP( self, host, intf, newIP, newNetmask ):
776 """
777 Changes the ip address of a host on the fly
778 Ex: h2 ifconfig h2-eth0 10.0.1.2 netmask 255.255.255.0"""
shahshreyae6c7cf42014-11-26 16:39:01 -0800779 if self.handle:
780 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800781 cmd = host + " ifconfig " + intf + " " + \
782 newIP + " " + 'netmask' + " " + newNetmask
783 self.handle.sendline( cmd )
784 self.handle.expect( "mininet>" )
shahshreyae6c7cf42014-11-26 16:39:01 -0800785 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800786 main.log.info( "response = " + response )
787 main.log.info(
788 "Ip of host " +
789 host +
790 " changed to new IP " +
791 newIP )
shahshreyae6c7cf42014-11-26 16:39:01 -0800792 return main.TRUE
793 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800794 main.log.error( self.name + ": EOF exception found" )
795 main.log.error( self.name + ": " + self.handle.before )
shahshreyae6c7cf42014-11-26 16:39:01 -0800796 return main.FALSE
797
Jon Hall7eb38402015-01-08 17:19:54 -0800798 def changeDefaultGateway( self, host, newGW ):
799 """
800 Changes the default gateway of a host
801 Ex: h1 route add default gw 10.0.1.2"""
shahshreyae6c7cf42014-11-26 16:39:01 -0800802 if self.handle:
803 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800804 cmd = host + " route add default gw " + newGW
805 self.handle.sendline( cmd )
806 self.handle.expect( "mininet>" )
shahshreyae6c7cf42014-11-26 16:39:01 -0800807 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800808 main.log.info( "response = " + response )
809 main.log.info(
810 "Default gateway of host " +
811 host +
812 " changed to " +
813 newGW )
shahshreyae6c7cf42014-11-26 16:39:01 -0800814 return main.TRUE
815 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800816 main.log.error( self.name + ": EOF exception found" )
817 main.log.error( self.name + ": " + self.handle.before )
shahshreyae6c7cf42014-11-26 16:39:01 -0800818 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800819
Jon Hall7eb38402015-01-08 17:19:54 -0800820 def addStaticMACAddress( self, host, GW, macaddr ):
821 """
Jon Hallefbd9792015-03-05 16:11:36 -0800822 Changes the mac address of a gateway host"""
shahshreyad0c80432014-12-04 16:56:05 -0800823 if self.handle:
824 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800825 # h1 arp -s 10.0.1.254 00:00:00:00:11:11
826 cmd = host + " arp -s " + GW + " " + macaddr
827 self.handle.sendline( cmd )
828 self.handle.expect( "mininet>" )
shahshreyad0c80432014-12-04 16:56:05 -0800829 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800830 main.log.info( "response = " + response )
831 main.log.info(
Jon Hallefbd9792015-03-05 16:11:36 -0800832 "Mac address of gateway " +
Jon Hall7eb38402015-01-08 17:19:54 -0800833 GW +
834 " changed to " +
835 macaddr )
shahshreyad0c80432014-12-04 16:56:05 -0800836 return main.TRUE
837 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800838 main.log.error( self.name + ": EOF exception found" )
839 main.log.error( self.name + ": " + self.handle.before )
shahshreyad0c80432014-12-04 16:56:05 -0800840 return main.FALSE
841
Jon Hall7eb38402015-01-08 17:19:54 -0800842 def verifyStaticGWandMAC( self, host ):
843 """
844 Verify if the static gateway and mac address assignment"""
shahshreyad0c80432014-12-04 16:56:05 -0800845 if self.handle:
846 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800847 # h1 arp -an
848 cmd = host + " arp -an "
849 self.handle.sendline( cmd )
850 self.handle.expect( "mininet>" )
shahshreyad0c80432014-12-04 16:56:05 -0800851 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800852 main.log.info( host + " arp -an = " + response )
shahshreyad0c80432014-12-04 16:56:05 -0800853 return main.TRUE
854 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800855 main.log.error( self.name + ": EOF exception found" )
856 main.log.error( self.name + ": " + self.handle.before )
shahshreyad0c80432014-12-04 16:56:05 -0800857 return main.FALSE
858
Jon Hall7eb38402015-01-08 17:19:54 -0800859 def getMacAddress( self, host ):
860 """
861 Verifies the host's ip configured or not."""
862 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -0700863 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800864 response = self.execute(
865 cmd=host +
866 " ifconfig",
867 prompt="mininet>",
868 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800869 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800870 main.log.error( self.name + ": EOF exception found" )
871 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700872 main.cleanup()
873 main.exit()
adminbae64d82013-08-01 10:50:15 -0700874
Ahmed El-Hassanyf720e202014-04-04 16:11:36 -0700875 pattern = r'HWaddr\s([0-9A-F]{2}[:-]){5}([0-9A-F]{2})'
kelvin-onlabd3b64892015-01-20 13:26:24 -0800876 macAddressSearch = re.search( pattern, response, re.I )
877 macAddress = macAddressSearch.group().split( " " )[ 1 ]
Jon Hall7eb38402015-01-08 17:19:54 -0800878 main.log.info(
879 self.name +
880 ": Mac-Address of Host " +
881 host +
882 " is " +
kelvin-onlabd3b64892015-01-20 13:26:24 -0800883 macAddress )
884 return macAddress
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700885 else:
Jon Hall7eb38402015-01-08 17:19:54 -0800886 main.log.error( self.name + ": Connection failed to the host" )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700887
Jon Hall7eb38402015-01-08 17:19:54 -0800888 def getInterfaceMACAddress( self, host, interface ):
889 """
890 Return the IP address of the interface on the given host"""
891 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -0700892 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800893 response = self.execute( cmd=host + " ifconfig " + interface,
894 prompt="mininet>", timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800895 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800896 main.log.error( self.name + ": EOF exception found" )
897 main.log.error( self.name + ": " + self.handle.before )
898 main.cleanup()
899 main.exit()
900
901 pattern = r'HWaddr\s([0-9A-F]{2}[:-]){5}([0-9A-F]{2})'
kelvin-onlabd3b64892015-01-20 13:26:24 -0800902 macAddressSearch = re.search( pattern, response, re.I )
903 if macAddressSearch is None:
Jon Hall7eb38402015-01-08 17:19:54 -0800904 main.log.info( "No mac address found in %s" % response )
905 return main.FALSE
kelvin-onlabd3b64892015-01-20 13:26:24 -0800906 macAddress = macAddressSearch.group().split( " " )[ 1 ]
Jon Hall7eb38402015-01-08 17:19:54 -0800907 main.log.info(
908 "Mac-Address of " +
909 host +
910 ":" +
911 interface +
912 " is " +
kelvin-onlabd3b64892015-01-20 13:26:24 -0800913 macAddress )
914 return macAddress
Jon Hall7eb38402015-01-08 17:19:54 -0800915 else:
916 main.log.error( "Connection failed to the host" )
917
918 def getIPAddress( self, host ):
919 """
920 Verifies the host's ip configured or not."""
921 if self.handle:
922 try:
923 response = self.execute(
924 cmd=host +
925 " ifconfig",
926 prompt="mininet>",
927 timeout=10 )
928 except pexpect.EOF:
929 main.log.error( self.name + ": EOF exception found" )
930 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700931 main.cleanup()
932 main.exit()
adminbae64d82013-08-01 10:50:15 -0700933
934 pattern = "inet\saddr:(\d+\.\d+\.\d+\.\d+)"
kelvin-onlabd3b64892015-01-20 13:26:24 -0800935 ipAddressSearch = re.search( pattern, response )
Jon Hall7eb38402015-01-08 17:19:54 -0800936 main.log.info(
937 self.name +
938 ": IP-Address of Host " +
939 host +
940 " is " +
kelvin-onlabd3b64892015-01-20 13:26:24 -0800941 ipAddressSearch.group( 1 ) )
942 return ipAddressSearch.group( 1 )
Jon Hall7eb38402015-01-08 17:19:54 -0800943 else:
944 main.log.error( self.name + ": Connection failed to the host" )
Jon Hallfbc828e2015-01-06 17:30:19 -0800945
Jon Hall7eb38402015-01-08 17:19:54 -0800946 def getSwitchDPID( self, switch ):
947 """
948 return the datapath ID of the switch"""
949 if self.handle:
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700950 cmd = "py %s.dpid" % switch
Jon Hall6094a362014-04-11 14:46:56 -0700951 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800952 response = self.execute(
953 cmd=cmd,
954 prompt="mininet>",
955 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800956 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800957 main.log.error( self.name + ": EOF exception found" )
958 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700959 main.cleanup()
960 main.exit()
Jon Hall28bf54b2014-12-17 16:25:44 -0800961 pattern = r'^(?P<dpid>\w)+'
Jon Hall7eb38402015-01-08 17:19:54 -0800962 result = re.search( pattern, response, re.MULTILINE )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700963 if result is None:
Jon Hall7eb38402015-01-08 17:19:54 -0800964 main.log.info(
965 "Couldn't find DPID for switch %s, found: %s" %
966 ( switch, response ) )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700967 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800968 return str( result.group( 0 ) ).lower()
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700969 else:
Jon Hall7eb38402015-01-08 17:19:54 -0800970 main.log.error( "Connection failed to the host" )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700971
Jon Hall7eb38402015-01-08 17:19:54 -0800972 def getDPID( self, switch ):
admin2580a0e2014-07-29 11:24:34 -0700973 if self.handle:
Jon Hall7eb38402015-01-08 17:19:54 -0800974 self.handle.sendline( "" )
975 self.expect( "mininet>" )
976 cmd = "py %s.dpid" % switch
admin2580a0e2014-07-29 11:24:34 -0700977 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800978 response = self.execute(
979 cmd=cmd,
980 prompt="mininet>",
981 timeout=10 )
982 self.handle.expect( "mininet>" )
admin2580a0e2014-07-29 11:24:34 -0700983 response = self.handle.before
984 return response
985 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800986 main.log.error( self.name + ": EOF exception found" )
987 main.log.error( self.name + ": " + self.handle.before )
admin2580a0e2014-07-29 11:24:34 -0700988 main.cleanup()
989 main.exit()
990
Jon Hall7eb38402015-01-08 17:19:54 -0800991 def getInterfaces( self, node ):
992 """
993 return information dict about interfaces connected to the node"""
994 if self.handle:
995 cmd = 'py "\\n".join(["name=%s,mac=%s,ip=%s,enabled=%s"' +\
kelvin-onlabedcff052015-01-16 12:53:55 -0800996 ' % (i.name, i.MAC(), i.IP(), i.isUp())'
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700997 cmd += ' for i in %s.intfs.values()])' % node
Jon Hall6094a362014-04-11 14:46:56 -0700998 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800999 response = self.execute(
1000 cmd=cmd,
1001 prompt="mininet>",
1002 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001003 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001004 main.log.error( self.name + ": EOF exception found" )
1005 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001006 main.cleanup()
1007 main.exit()
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -07001008 return response
1009 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001010 main.log.error( "Connection failed to the node" )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -07001011
Jon Hall7eb38402015-01-08 17:19:54 -08001012 def dump( self ):
1013 main.log.info( self.name + ": Dump node info" )
Jon Hall6094a362014-04-11 14:46:56 -07001014 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001015 response = self.execute(
1016 cmd='dump',
1017 prompt='mininet>',
1018 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001019 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001020 main.log.error( self.name + ": EOF exception found" )
1021 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001022 main.cleanup()
1023 main.exit()
Ahmed El-Hassanyd1f71702014-04-04 16:12:45 -07001024 return response
Jon Hallfbc828e2015-01-06 17:30:19 -08001025
Jon Hall7eb38402015-01-08 17:19:54 -08001026 def intfs( self ):
1027 main.log.info( self.name + ": List interfaces" )
Jon Hall6094a362014-04-11 14:46:56 -07001028 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001029 response = self.execute(
1030 cmd='intfs',
1031 prompt='mininet>',
1032 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001033 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001034 main.log.error( self.name + ": EOF exception found" )
1035 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001036 main.cleanup()
1037 main.exit()
Jon Hall668ed802014-04-08 17:17:59 -07001038 return response
Jon Hallfbc828e2015-01-06 17:30:19 -08001039
Jon Hall7eb38402015-01-08 17:19:54 -08001040 def net( self ):
1041 main.log.info( self.name + ": List network connections" )
Jon Hall6094a362014-04-11 14:46:56 -07001042 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001043 response = self.execute( cmd='net', prompt='mininet>', timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001044 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001045 main.log.error( self.name + ": EOF exception found" )
1046 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001047 main.cleanup()
1048 main.exit()
Jon Hall668ed802014-04-08 17:17:59 -07001049 return response
Jon Hall7eb38402015-01-08 17:19:54 -08001050
Jon Hallafa8a472015-06-12 14:02:42 -07001051 def links( self ):
1052 main.log.info( self.name + ": List network links" )
1053 try:
1054 response = self.execute( cmd='links', prompt='mininet>',
Jon Hall3b489db2015-10-05 14:38:37 -07001055 timeout=20 )
Jon Hallafa8a472015-06-12 14:02:42 -07001056 except pexpect.EOF:
1057 main.log.error( self.name + ": EOF exception found" )
1058 main.log.error( self.name + ": " + self.handle.before )
1059 main.cleanup()
1060 main.exit()
1061 return response
1062
GlennRC61321f22015-07-16 13:36:54 -07001063 def iperftcpAll(self, hosts, timeout=6):
kelvin-onlab7cce9382015-07-17 10:21:03 -07001064 '''
1065 Runs the iperftcp function with a given set of hosts and specified timeout.
GlennRC61321f22015-07-16 13:36:54 -07001066
kelvin-onlab7cce9382015-07-17 10:21:03 -07001067 @parm:
1068 timeout: The defualt timeout is 6 sec to allow enough time for a successful test to complete,
1069 and short enough to stop an unsuccessful test from quiting and cleaning up mininet.
1070 '''
1071 for host1 in hosts:
1072 for host2 in hosts:
1073 if host1 != host2:
1074 if self.iperftcp(host1, host2, timeout) == main.FALSE:
1075 main.log.error(self.name + ": iperftcp test failed for " + host1 + " and " + host2)
GlennRC61321f22015-07-16 13:36:54 -07001076
1077 def iperftcp(self, host1="h1", host2="h2", timeout=6):
kelvin-onlab7cce9382015-07-17 10:21:03 -07001078 '''
1079 Creates an iperf TCP test between two hosts. Returns main.TRUE if test results
1080 are valid.
GlennRC61321f22015-07-16 13:36:54 -07001081
kelvin-onlab7cce9382015-07-17 10:21:03 -07001082 @parm:
1083 timeout: The defualt timeout is 6 sec to allow enough time for a successful test to complete,
1084 and short enough to stop an unsuccessful test from quiting and cleaning up mininet.
1085 '''
1086 main.log.info( self.name + ": Simple iperf TCP test between two hosts" )
1087 try:
1088 # Setup the mininet command
1089 cmd1 = 'iperf ' + host1 + " " + host2
1090 self.handle.sendline( cmd1 )
1091 outcome = self.handle.expect( "mininet>", timeout )
1092 response = self.handle.before
GlennRC61321f22015-07-16 13:36:54 -07001093
kelvin-onlab7cce9382015-07-17 10:21:03 -07001094 # checks if there are results in the mininet response
1095 if "Results:" in response:
Jon Hall892818c2015-10-20 17:58:34 -07001096 main.log.report(self.name + ": iperf test completed")
kelvin-onlab7cce9382015-07-17 10:21:03 -07001097 # parse the mn results
1098 response = response.split("\r\n")
1099 response = response[len(response)-2]
1100 response = response.split(": ")
1101 response = response[len(response)-1]
1102 response = response.replace("[", "")
1103 response = response.replace("]", "")
1104 response = response.replace("\'", "")
GlennRC61321f22015-07-16 13:36:54 -07001105
kelvin-onlab7cce9382015-07-17 10:21:03 -07001106 # this is the bandwith two and from the two hosts
1107 bandwidth = response.split(", ")
GlennRC61321f22015-07-16 13:36:54 -07001108
kelvin-onlab7cce9382015-07-17 10:21:03 -07001109 # there should be two elements in the bandwidth list
1110 # ['host1 to host2', 'host2 to host1"]
1111 if len(bandwidth) == 2:
1112 main.log.report(self.name + ": iperf test successful")
1113 return main.TRUE
1114 else:
1115 main.log.error(self.name + ": invalid iperf results")
1116 return main.FALSE
shahshreyae6c7cf42014-11-26 16:39:01 -08001117 else:
kelvin-onlab7cce9382015-07-17 10:21:03 -07001118 main.log.error( self.name + ": iperf test failed" )
Jon Hall7eb38402015-01-08 17:19:54 -08001119 return main.FALSE
GlennRC61321f22015-07-16 13:36:54 -07001120 except pexpect.TIMEOUT:
Jon Hall3b489db2015-10-05 14:38:37 -07001121 main.log.error( self.name + ": TIMEOUT exception found" )
1122 main.log.error( self.name + " response: " +
Jon Hall892818c2015-10-20 17:58:34 -07001123 repr( self.handle.before ) )
Jon Hall3b489db2015-10-05 14:38:37 -07001124 # NOTE: Send ctrl-c to make sure iperf is done
1125 self.handle.sendline( "\x03" )
1126 self.handle.expect( "Interrupt" )
1127 self.handle.expect( "mininet>" )
GlennRC61321f22015-07-16 13:36:54 -07001128 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -08001129 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001130 main.log.error( self.name + ": EOF exception found" )
1131 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001132 main.cleanup()
kelvin-onlab7cce9382015-07-17 10:21:03 -07001133 main.exit()
GlennRC61321f22015-07-16 13:36:54 -07001134
1135 def iperfudpAll(self, hosts, bandwidth="10M"):
1136 '''
1137 Runs the iperfudp function with a given set of hosts and specified
1138 bandwidth
kelvin-onlab7cce9382015-07-17 10:21:03 -07001139
GlennRC61321f22015-07-16 13:36:54 -07001140 @param:
1141 bandwidth: the targeted bandwidth, in megabits ('M')
1142 '''
1143 for host1 in hosts:
1144 for host2 in hosts:
1145 if host1 != host2:
1146 if self.iperfudp(host1, host2, bandwidth) == main.FALSE:
1147 main.log.error(self.name + ": iperfudp test failed for " + host1 + " and " + host2)
1148
1149 def iperfudp( self, bandwidth="10M", host1="h1", host2="h2"):
1150
kelvin-onlab7cce9382015-07-17 10:21:03 -07001151 '''
1152 Creates an iperf UDP test with a specific bandwidth.
1153 Returns true if results are valid.
GlennRC61321f22015-07-16 13:36:54 -07001154
kelvin-onlab7cce9382015-07-17 10:21:03 -07001155 @param:
1156 bandwidth: the targeted bandwidth, in megabits ('M'), to run the test
1157 '''
1158 main.log.info(self.name + ": Simple iperf UDP test between two hosts")
1159 try:
1160 # setup the mininet command
1161 cmd = 'iperfudp ' + bandwidth + " " + host1 + " " + host2
1162 self.handle.sendline(cmd)
1163 self.handle.expect("mininet>")
1164 response = self.handle.before
GlennRC61321f22015-07-16 13:36:54 -07001165
kelvin-onlab7cce9382015-07-17 10:21:03 -07001166 # check if there are in results in the mininet response
1167 if "Results:" in response:
Jon Hall892818c2015-10-20 17:58:34 -07001168 main.log.report(self.name + ": iperfudp test completed")
kelvin-onlab7cce9382015-07-17 10:21:03 -07001169 # parse the results
1170 response = response.split("\r\n")
1171 response = response[len(response)-2]
1172 response = response.split(": ")
1173 response = response[len(response)-1]
1174 response = response.replace("[", "")
1175 response = response.replace("]", "")
1176 response = response.replace("\'", "")
GlennRC61321f22015-07-16 13:36:54 -07001177
kelvin-onlab7cce9382015-07-17 10:21:03 -07001178 mnBandwidth = response.split(", ")
GlennRC61321f22015-07-16 13:36:54 -07001179
kelvin-onlab7cce9382015-07-17 10:21:03 -07001180 # check to see if there are at least three entries
1181 # ['bandwidth', 'host1 to host2', 'host2 to host1']
1182 if len(mnBandwidth) == 3:
1183 # if one entry is blank then something is wrong
1184 for item in mnBandwidth:
1185 if item == "":
1186 main.log.error(self.name + ": Could not parse iperf output")
1187 main.log.error(self.name + ": invalid iperfudp results")
1188 return main.FALSE
1189 # otherwise results are vaild
1190 main.log.report(self.name + ": iperfudp test successful")
1191 return main.TRUE
1192 else:
1193 main.log.error(self.name + ": invalid iperfudp results")
1194 return main.FALSE
GlennRC61321f22015-07-16 13:36:54 -07001195
kelvin-onlab7cce9382015-07-17 10:21:03 -07001196 except pexpect.EOF:
1197 main.log.error( self.name + ": EOF exception found" )
1198 main.log.error( self.name + ": " + self.handle.before )
1199 main.cleanup()
1200 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -08001201
Jon Hall7eb38402015-01-08 17:19:54 -08001202 def nodes( self ):
1203 main.log.info( self.name + ": List all nodes." )
Jon Hall6094a362014-04-11 14:46:56 -07001204 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001205 response = self.execute(
1206 cmd='nodes',
1207 prompt='mininet>',
1208 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001209 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001210 main.log.error( self.name + ": EOF exception found" )
1211 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001212 main.cleanup()
1213 main.exit()
Jon Hall668ed802014-04-08 17:17:59 -07001214 return response
Jon Hallfbc828e2015-01-06 17:30:19 -08001215
Jon Hall7eb38402015-01-08 17:19:54 -08001216 def pingpair( self ):
1217 main.log.info( self.name + ": Ping between first two hosts" )
Jon Hall6094a362014-04-11 14:46:56 -07001218 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001219 response = self.execute(
1220 cmd='pingpair',
1221 prompt='mininet>',
1222 timeout=20 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001223 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001224 main.log.error( self.name + ": EOF exception found" )
1225 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001226 main.cleanup()
1227 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -08001228
Jon Hall7eb38402015-01-08 17:19:54 -08001229 if re.search( ',\s0\%\spacket\sloss', response ):
1230 main.log.info( self.name + ": Ping between two hosts SUCCESSFUL" )
adminbae64d82013-08-01 10:50:15 -07001231 return main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001232 else:
1233 main.log.error( self.name + ": PACKET LOST, HOSTS NOT REACHABLE" )
adminbae64d82013-08-01 10:50:15 -07001234 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -08001235
Jon Hall7eb38402015-01-08 17:19:54 -08001236 def link( self, **linkargs ):
1237 """
GlennRCed771242016-01-13 17:02:47 -08001238 Bring link( s ) between two nodes up or down
1239 """
Jon Hall6094a362014-04-11 14:46:56 -07001240 try:
GlennRCed771242016-01-13 17:02:47 -08001241 args = utilities.parse_args( [ "END1", "END2", "OPTION" ], **linkargs )
1242 end1 = args[ "END1" ] if args[ "END1" ] is not None else ""
1243 end2 = args[ "END2" ] if args[ "END2" ] is not None else ""
1244 option = args[ "OPTION" ] if args[ "OPTION" ] is not None else ""
1245
1246 main.log.info( "Bring link between " + str( end1 ) + " and " + str( end2 ) + " " + str( option ) )
1247 cmd = "link {} {} {}".format( end1, end2, option )
1248 self.handle.sendline( cmd )
Jon Hall7eb38402015-01-08 17:19:54 -08001249 self.handle.expect( "mininet>" )
GlennRCed771242016-01-13 17:02:47 -08001250 response = self.handle.before
1251 main.log.info( response )
1252
1253 return main.TRUE
1254 except pexpect.TIMEOUT:
1255 main.log.exception( self.name + ": Command timed out" )
1256 return None
Jon Hallfbc828e2015-01-06 17:30:19 -08001257 except pexpect.EOF:
GlennRCed771242016-01-13 17:02:47 -08001258 main.log.exception( self.name + ": connection closed." )
Jon Hall6094a362014-04-11 14:46:56 -07001259 main.cleanup()
1260 main.exit()
GlennRCed771242016-01-13 17:02:47 -08001261 except Exception:
1262 main.log.exception( self.name + ": Uncaught exception!" )
1263 main.cleanup()
1264 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -08001265
pingping-lin8244a3b2015-09-16 13:36:56 -07001266 def switch( self, **switchargs ):
1267 """
1268 start/stop a switch
1269 """
1270 args = utilities.parse_args( [ "SW", "OPTION" ], **switchargs )
1271 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1272 option = args[ "OPTION" ] if args[ "OPTION" ] is not None else ""
1273 command = "switch " + str( sw ) + " " + str( option )
1274 main.log.info( command )
1275 try:
1276 self.handle.sendline( command )
1277 self.handle.expect( "mininet>" )
1278 except pexpect.TIMEOUT:
1279 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1280 main.cleanup()
1281 main.exit()
1282 except pexpect.EOF:
1283 main.log.error( self.name + ": EOF exception found" )
1284 main.log.error( self.name + ": " + self.handle.before )
1285 main.cleanup()
1286 main.exit()
1287 return main.TRUE
1288
pingping-lin5bb663b2015-09-24 11:47:50 -07001289 def node( self, nodeName, commandStr ):
1290 """
1291 Carry out a command line on a given node
1292 @parm:
1293 nodeName: the node name in Mininet testbed
1294 commandStr: the command line will be carried out on the node
1295 Example: main.Mininet.node( nodeName="h1", commandStr="ls" )
1296 """
1297 command = str( nodeName ) + " " + str( commandStr )
1298 main.log.info( command )
1299
1300 try:
1301 response = self.execute( cmd = command, prompt = "mininet>" )
1302 if re.search( "Unknown command", response ):
1303 main.log.warn( response )
1304 return main.FALSE
Jon Hall9ed8f372016-02-24 17:34:07 -08001305 if re.search( "Permission denied", response ):
1306 main.log.warn( response )
1307 return main.FALSE
pingping-lin5bb663b2015-09-24 11:47:50 -07001308 except pexpect.TIMEOUT:
1309 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1310 main.cleanup()
1311 main.exit()
1312 except pexpect.EOF:
1313 main.log.error( self.name + ": EOF exception found" )
1314 main.log.error( self.name + ": " + self.handle.before )
1315 main.cleanup()
1316 main.exit()
1317 main.log.info( " response is :" )
1318 main.log.info( response )
1319 return response
1320
Jon Hall7eb38402015-01-08 17:19:54 -08001321 def yank( self, **yankargs ):
1322 """
1323 yank a mininet switch interface to a host"""
1324 main.log.info( 'Yank the switch interface attached to a host' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001325 args = utilities.parse_args( [ "SW", "INTF" ], **yankargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001326 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1327 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
1328 command = "py " + str( sw ) + '.detach("' + str(intf) + '")'
Jon Hall6094a362014-04-11 14:46:56 -07001329 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001330 response = self.execute(
1331 cmd=command,
1332 prompt="mininet>",
1333 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001334 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001335 main.log.error( self.name + ": EOF exception found" )
1336 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001337 main.cleanup()
1338 main.exit()
adminaeedddd2013-08-02 15:14:15 -07001339 return main.TRUE
1340
Jon Hall7eb38402015-01-08 17:19:54 -08001341 def plug( self, **plugargs ):
1342 """
1343 plug the yanked mininet switch interface to a switch"""
1344 main.log.info( 'Plug the switch interface attached to a switch' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001345 args = utilities.parse_args( [ "SW", "INTF" ], **plugargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001346 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1347 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
1348 command = "py " + str( sw ) + '.attach("' + str(intf) + '")'
Jon Hall6094a362014-04-11 14:46:56 -07001349 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001350 response = self.execute(
1351 cmd=command,
1352 prompt="mininet>",
1353 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001354 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001355 main.log.error( self.name + ": EOF exception found" )
1356 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001357 main.cleanup()
1358 main.exit()
adminbae64d82013-08-01 10:50:15 -07001359 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -08001360
Jon Hall7eb38402015-01-08 17:19:54 -08001361 def dpctl( self, **dpctlargs ):
1362 """
1363 Run dpctl command on all switches."""
1364 main.log.info( 'Run dpctl command on all switches' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001365 args = utilities.parse_args( [ "CMD", "ARGS" ], **dpctlargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001366 cmd = args[ "CMD" ] if args[ "CMD" ] is not None else ""
1367 cmdargs = args[ "ARGS" ] if args[ "ARGS" ] is not None else ""
1368 command = "dpctl " + cmd + " " + str( cmdargs )
1369 try:
1370 response = self.execute(
1371 cmd=command,
1372 prompt="mininet>",
1373 timeout=10 )
1374 except pexpect.EOF:
1375 main.log.error( self.name + ": EOF exception found" )
1376 main.log.error( self.name + ": " + self.handle.before )
1377 main.cleanup()
1378 main.exit()
1379 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -08001380
kelvin-onlabd3b64892015-01-20 13:26:24 -08001381 def getVersion( self ):
Jon Halld80cc142015-07-06 13:36:05 -07001382 # FIXME: What uses this? This should be refactored to get
Jon Hallff6b4b22015-02-23 09:25:15 -08001383 # version from MN and not some other file
kelvin-onlabd3b64892015-01-20 13:26:24 -08001384 fileInput = path + '/lib/Mininet/INSTALL'
1385 version = super( Mininet, self ).getVersion()
adminbae64d82013-08-01 10:50:15 -07001386 pattern = 'Mininet\s\w\.\w\.\w\w*'
kelvin-onlabd3b64892015-01-20 13:26:24 -08001387 for line in open( fileInput, 'r' ).readlines():
Jon Hall7eb38402015-01-08 17:19:54 -08001388 result = re.match( pattern, line )
adminbae64d82013-08-01 10:50:15 -07001389 if result:
Jon Hall7eb38402015-01-08 17:19:54 -08001390 version = result.group( 0 )
Jon Hallec3c21e2014-11-10 22:22:37 -05001391 return version
adminbae64d82013-08-01 10:50:15 -07001392
kelvin-onlabd3b64892015-01-20 13:26:24 -08001393 def getSwController( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001394 """
Jon Hallec3c21e2014-11-10 22:22:37 -05001395 Parameters:
1396 sw: The name of an OVS switch. Example "s1"
1397 Return:
Jon Hall7eb38402015-01-08 17:19:54 -08001398 The output of the command from the mininet cli
1399 or main.FALSE on timeout"""
1400 command = "sh ovs-vsctl get-controller " + str( sw )
admin2a9548d2014-06-17 14:08:07 -07001401 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001402 response = self.execute(
1403 cmd=command,
1404 prompt="mininet>",
1405 timeout=10 )
admin2a9548d2014-06-17 14:08:07 -07001406 if response:
Jon Hallec3c21e2014-11-10 22:22:37 -05001407 return response
admin2a9548d2014-06-17 14:08:07 -07001408 else:
1409 return main.FALSE
1410 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001411 main.log.error( self.name + ": EOF exception found" )
1412 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07001413 main.cleanup()
1414 main.exit()
adminbae64d82013-08-01 10:50:15 -07001415
Charles Chan029be652015-08-24 01:46:10 +08001416 def assignSwController( self, sw, ip, port="6653", ptcp="" ):
Jon Hall7eb38402015-01-08 17:19:54 -08001417 """
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001418 Description:
1419 Assign switches to the controllers ( for ovs use only )
1420 Required:
1421 sw - Name of the switch. This can be a list or a string.
1422 ip - Ip addresses of controllers. This can be a list or a string.
1423 Optional:
Charles Chan029be652015-08-24 01:46:10 +08001424 port - ONOS use port 6653, if no list of ports is passed, then
1425 the all the controller will use 6653 as their port number
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001426 ptcp - ptcp number, This can be a string or a list that has
1427 the same length as switch. This is optional and not required
1428 when using ovs switches.
1429 NOTE: If switches and ptcp are given in a list type they should have the
1430 same length and should be in the same order, Eg. sw=[ 's1' ... n ]
1431 ptcp=[ '6637' ... n ], s1 has ptcp number 6637 and so on.
Jon Hallf89c8552014-04-02 13:14:06 -07001432
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001433 Return:
1434 Returns main.TRUE if mininet correctly assigned switches to
1435 controllers, otherwise it will return main.FALSE or an appropriate
1436 exception(s)
1437 """
1438 assignResult = main.TRUE
1439 # Initial ovs command
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001440 commandList = []
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001441 command = "sh ovs-vsctl set-controller "
1442 onosIp = ""
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001443 try:
1444 if isinstance( ip, types.StringType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001445 onosIp = "tcp:" + str( ip ) + ":"
kelvin-onlab5c2df432015-06-11 17:29:56 -07001446 if isinstance( port, types.StringType ) or \
1447 isinstance( port, types.IntType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001448 onosIp += str( port )
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001449 elif isinstance( port, types.ListType ):
1450 main.log.error( self.name + ": Only one controller " +
1451 "assigned and a list of ports has" +
1452 " been passed" )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001453 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001454 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001455 main.log.error( self.name + ": Invalid controller port " +
1456 "number. Please specify correct " +
1457 "controller port" )
1458 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001459
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001460 elif isinstance( ip, types.ListType ):
kelvin-onlab5c2df432015-06-11 17:29:56 -07001461 if isinstance( port, types.StringType ) or \
1462 isinstance( port, types.IntType ):
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001463 for ipAddress in ip:
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001464 onosIp += "tcp:" + str( ipAddress ) + ":" + \
1465 str( port ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001466 elif isinstance( port, types.ListType ):
1467 if ( len( ip ) != len( port ) ):
1468 main.log.error( self.name + ": Port list = " +
1469 str( len( port ) ) +
1470 "should be the same as controller" +
1471 " ip list = " + str( len( ip ) ) )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001472 return main.FALSE
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001473 else:
1474 onosIp = ""
1475 for ipAddress, portNum in zip( ip, port ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001476 onosIp += "tcp:" + str( ipAddress ) + ":" + \
1477 str( portNum ) + " "
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001478 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001479 main.log.error( self.name + ": Invalid controller port " +
1480 "number. Please specify correct " +
1481 "controller port" )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001482 return main.FALSE
kelvin-onlabe5edb9e2015-06-12 09:38:47 -07001483 else:
1484 main.log.error( self.name + ": Invalid ip address" )
1485 return main.FALSE
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001486
1487 if isinstance( sw, types.StringType ):
1488 command += sw + " "
1489 if ptcp:
1490 if isinstance( ptcp, types.StringType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001491 command += "ptcp:" + str( ptcp ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001492 elif isinstance( ptcp, types.ListType ):
1493 main.log.error( self.name + ": Only one switch is " +
1494 "being set and multiple PTCP is " +
1495 "being passed " )
1496 else:
1497 main.log.error( self.name + ": Invalid PTCP" )
1498 ptcp = ""
1499 command += onosIp
1500 commandList.append( command )
1501
1502 elif isinstance( sw, types.ListType ):
1503 if ptcp:
1504 if isinstance( ptcp, types.ListType ):
1505 if len( ptcp ) != len( sw ):
1506 main.log.error( self.name + ": PTCP length = " +
1507 str( len( ptcp ) ) +
1508 " is not the same as switch" +
1509 " length = " +
1510 str( len( sw ) ) )
1511 return main.FALSE
1512 else:
1513 for switch, ptcpNum in zip( sw, ptcp ):
1514 tempCmd = "sh ovs-vsctl set-controller "
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001515 tempCmd += switch + " ptcp:" + \
Jon Halld80cc142015-07-06 13:36:05 -07001516 str( ptcpNum ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001517 tempCmd += onosIp
1518 commandList.append( tempCmd )
1519 else:
1520 main.log.error( self.name + ": Invalid PTCP" )
1521 return main.FALSE
1522 else:
1523 for switch in sw:
1524 tempCmd = "sh ovs-vsctl set-controller "
1525 tempCmd += switch + " " + onosIp
1526 commandList.append( tempCmd )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001527 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001528 main.log.error( self.name + ": Invalid switch type " )
1529 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001530
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001531 for cmd in commandList:
1532 try:
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001533 self.execute( cmd=cmd, prompt="mininet>", timeout=5 )
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001534 except pexpect.TIMEOUT:
1535 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1536 return main.FALSE
1537 except pexpect.EOF:
1538 main.log.error( self.name + ": EOF exception found" )
1539 main.log.error( self.name + ": " + self.handle.before )
1540 main.cleanup()
1541 main.exit()
1542 return main.TRUE
1543 except Exception:
1544 main.log.exception( self.name + ": Uncaught exception!" )
1545 main.cleanup()
1546 main.exit()
adminbae64d82013-08-01 10:50:15 -07001547
kelvin-onlabd3b64892015-01-20 13:26:24 -08001548 def deleteSwController( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001549 """
1550 Removes the controller target from sw"""
1551 command = "sh ovs-vsctl del-controller " + str( sw )
Jon Hall0819fd92014-05-23 12:08:13 -07001552 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001553 response = self.execute(
1554 cmd=command,
1555 prompt="mininet>",
1556 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001557 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001558 main.log.error( self.name + ": EOF exception found" )
1559 main.log.error( self.name + ": " + self.handle.before )
Jon Hall0819fd92014-05-23 12:08:13 -07001560 main.cleanup()
1561 main.exit()
1562 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001563 main.log.info( response )
Jon Hall0819fd92014-05-23 12:08:13 -07001564
kelvin-onlabd3b64892015-01-20 13:26:24 -08001565 def addSwitch( self, sw, **kwargs ):
Jon Hall7eb38402015-01-08 17:19:54 -08001566 """
Jon Hallb1290e82014-11-18 16:17:48 -05001567 adds a switch to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001568 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001569 dynamic_topo branch
Jon Hallb1290e82014-11-18 16:17:48 -05001570 NOTE: cannot currently specify what type of switch
1571 required params:
Jon Hallefbd9792015-03-05 16:11:36 -08001572 sw = name of the new switch as a string
1573 optional keywords:
Jon Hallb1290e82014-11-18 16:17:48 -05001574 dpid = "dpid"
Jon Hallefbd9792015-03-05 16:11:36 -08001575 returns: main.FALSE on an error, else main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001576 """
1577 dpid = kwargs.get( 'dpid', '' )
Jon Hallffb386d2014-11-21 13:43:38 -08001578 command = "addswitch " + str( sw ) + " " + str( dpid )
Jon Hallb1290e82014-11-18 16:17:48 -05001579 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001580 response = self.execute(
1581 cmd=command,
1582 prompt="mininet>",
1583 timeout=10 )
1584 if re.search( "already exists!", response ):
1585 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001586 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001587 elif re.search( "Error", response ):
1588 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001589 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001590 elif re.search( "usage:", response ):
1591 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001592 return main.FALSE
1593 else:
1594 return main.TRUE
1595 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001596 main.log.error( self.name + ": EOF exception found" )
Jon Halld80cc142015-07-06 13:36:05 -07001597 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001598 main.cleanup()
1599 main.exit()
1600
kelvin-onlabd3b64892015-01-20 13:26:24 -08001601 def delSwitch( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001602 """
Jon Hallbe6dfc42015-01-12 17:37:25 -08001603 delete a switch from the mininet topology
1604 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001605 dynamic_topo branch
Jon Hallbe6dfc42015-01-12 17:37:25 -08001606 required params:
Jon Hallefbd9792015-03-05 16:11:36 -08001607 sw = name of the switch as a string
1608 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001609 command = "delswitch " + str( sw )
Jon Hallb1290e82014-11-18 16:17:48 -05001610 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001611 response = self.execute(
1612 cmd=command,
1613 prompt="mininet>",
1614 timeout=10 )
1615 if re.search( "no switch named", response ):
1616 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001617 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001618 elif re.search( "Error", response ):
1619 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001620 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001621 elif re.search( "usage:", response ):
1622 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001623 return main.FALSE
1624 else:
1625 return main.TRUE
1626 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001627 main.log.error( self.name + ": EOF exception found" )
1628 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001629 main.cleanup()
1630 main.exit()
1631
kelvin-onlabd3b64892015-01-20 13:26:24 -08001632 def addLink( self, node1, node2 ):
Jon Hall7eb38402015-01-08 17:19:54 -08001633 """
1634 add a link to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001635 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001636 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001637 NOTE: cannot currently specify what type of link
1638 required params:
1639 node1 = the string node name of the first endpoint of the link
1640 node2 = the string node name of the second endpoint of the link
Jon Hallefbd9792015-03-05 16:11:36 -08001641 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001642 command = "addlink " + str( node1 ) + " " + str( node2 )
Jon Hallb1290e82014-11-18 16:17:48 -05001643 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001644 response = self.execute(
1645 cmd=command,
1646 prompt="mininet>",
1647 timeout=10 )
1648 if re.search( "doesnt exist!", response ):
1649 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001650 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001651 elif re.search( "Error", response ):
1652 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001653 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001654 elif re.search( "usage:", response ):
1655 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001656 return main.FALSE
1657 else:
1658 return main.TRUE
1659 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001660 main.log.error( self.name + ": EOF exception found" )
1661 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001662 main.cleanup()
1663 main.exit()
1664
kelvin-onlabd3b64892015-01-20 13:26:24 -08001665 def delLink( self, node1, node2 ):
Jon Hall7eb38402015-01-08 17:19:54 -08001666 """
1667 delete a link from the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001668 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001669 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001670 required params:
1671 node1 = the string node name of the first endpoint of the link
1672 node2 = the string node name of the second endpoint of the link
Jon Hallefbd9792015-03-05 16:11:36 -08001673 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001674 command = "dellink " + str( node1 ) + " " + str( node2 )
Jon Hallb1290e82014-11-18 16:17:48 -05001675 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001676 response = self.execute(
1677 cmd=command,
1678 prompt="mininet>",
1679 timeout=10 )
1680 if re.search( "no node named", response ):
1681 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001682 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001683 elif re.search( "Error", response ):
1684 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001685 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001686 elif re.search( "usage:", response ):
1687 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001688 return main.FALSE
1689 else:
1690 return main.TRUE
1691 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001692 main.log.error( self.name + ": EOF exception found" )
1693 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001694 main.cleanup()
1695 main.exit()
1696
kelvin-onlabd3b64892015-01-20 13:26:24 -08001697 def addHost( self, hostname, **kwargs ):
Jon Hall7eb38402015-01-08 17:19:54 -08001698 """
Jon Hallb1290e82014-11-18 16:17:48 -05001699 Add a host to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001700 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001701 dynamic_topo branch
Jon Hallb1290e82014-11-18 16:17:48 -05001702 NOTE: cannot currently specify what type of host
1703 required params:
1704 hostname = the string hostname
1705 optional key-value params
1706 switch = "switch name"
Jon Hallefbd9792015-03-05 16:11:36 -08001707 returns: main.FALSE on an error, else main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001708 """
1709 switch = kwargs.get( 'switch', '' )
Jon Hallffb386d2014-11-21 13:43:38 -08001710 command = "addhost " + str( hostname ) + " " + str( switch )
Jon Hallb1290e82014-11-18 16:17:48 -05001711 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001712 response = self.execute(
1713 cmd=command,
1714 prompt="mininet>",
1715 timeout=10 )
1716 if re.search( "already exists!", response ):
1717 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001718 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001719 elif re.search( "doesnt exists!", response ):
1720 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001721 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001722 elif re.search( "Error", response ):
1723 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001724 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001725 elif re.search( "usage:", response ):
1726 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001727 return main.FALSE
1728 else:
1729 return main.TRUE
1730 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001731 main.log.error( self.name + ": EOF exception found" )
1732 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001733 main.cleanup()
1734 main.exit()
1735
kelvin-onlabd3b64892015-01-20 13:26:24 -08001736 def delHost( self, hostname ):
Jon Hall7eb38402015-01-08 17:19:54 -08001737 """
1738 delete a host from the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001739 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001740 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001741 NOTE: this uses a custom mn function
1742 required params:
1743 hostname = the string hostname
Jon Hallefbd9792015-03-05 16:11:36 -08001744 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001745 command = "delhost " + str( hostname )
Jon Hallb1290e82014-11-18 16:17:48 -05001746 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001747 response = self.execute(
1748 cmd=command,
1749 prompt="mininet>",
1750 timeout=10 )
1751 if re.search( "no host named", response ):
1752 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001753 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001754 elif re.search( "Error", response ):
1755 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001756 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001757 elif re.search( "usage:", response ):
1758 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001759 return main.FALSE
1760 else:
1761 return main.TRUE
1762 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001763 main.log.error( self.name + ": EOF exception found" )
1764 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001765 main.cleanup()
1766 main.exit()
Jon Hall0819fd92014-05-23 12:08:13 -07001767
Jon Hall7eb38402015-01-08 17:19:54 -08001768 def disconnect( self ):
kelvin-onlaba1484582015-02-02 15:46:20 -08001769 """
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001770 Called at the end of the test to stop the mininet and
1771 disconnect the handle.
kelvin-onlaba1484582015-02-02 15:46:20 -08001772 """
Jon Halld80cc142015-07-06 13:36:05 -07001773 self.handle.sendline( '' )
Jon Halld61331b2015-02-17 16:35:47 -08001774 i = self.handle.expect( [ 'mininet>', pexpect.EOF, pexpect.TIMEOUT ],
Jon Halld80cc142015-07-06 13:36:05 -07001775 timeout=2 )
Jon Hall390696c2015-05-05 17:13:41 -07001776 response = main.TRUE
kelvin-onlaba1484582015-02-02 15:46:20 -08001777 if i == 0:
Jon Hall390696c2015-05-05 17:13:41 -07001778 response = self.stopNet()
Jon Halld61331b2015-02-17 16:35:47 -08001779 elif i == 1:
1780 return main.TRUE
kelvin-onlaba1484582015-02-02 15:46:20 -08001781 # print "Disconnecting Mininet"
1782 if self.handle:
1783 self.handle.sendline( "exit" )
1784 self.handle.expect( "exit" )
1785 self.handle.expect( "(.*)" )
kelvin-onlaba1484582015-02-02 15:46:20 -08001786 else:
1787 main.log.error( "Connection failed to the host" )
kelvin-onlaba1484582015-02-02 15:46:20 -08001788 return response
1789
Jon Halld80cc142015-07-06 13:36:05 -07001790 def stopNet( self, fileName="", timeout=5 ):
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001791 """
Jon Hall21270ac2015-02-16 17:59:55 -08001792 Stops mininet.
Jon Hallefbd9792015-03-05 16:11:36 -08001793 Returns main.TRUE if the mininet successfully stops and
Jon Hall21270ac2015-02-16 17:59:55 -08001794 main.FALSE if the pexpect handle does not exist.
1795
Jon Halld61331b2015-02-17 16:35:47 -08001796 Will cleanup and exit the test if mininet fails to stop
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001797 """
Jon Halld61331b2015-02-17 16:35:47 -08001798 main.log.info( self.name + ": Stopping mininet..." )
adminbae64d82013-08-01 10:50:15 -07001799 response = ''
1800 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -07001801 try:
Jon Halld80cc142015-07-06 13:36:05 -07001802 self.handle.sendline( "" )
kelvin-onlab56a3f462015-02-06 14:04:43 -08001803 i = self.handle.expect( [ 'mininet>',
1804 '\$',
1805 pexpect.EOF,
1806 pexpect.TIMEOUT ],
1807 timeout )
1808 if i == 0:
1809 main.log.info( "Exiting mininet..." )
Jon Hall7eb38402015-01-08 17:19:54 -08001810 response = self.execute(
1811 cmd="exit",
1812 prompt="(.*)",
1813 timeout=120 )
Jon Halld80cc142015-07-06 13:36:05 -07001814 main.log.info( self.name + ": Stopped" )
Jon Hall7eb38402015-01-08 17:19:54 -08001815 self.handle.sendline( "sudo mn -c" )
shahshreya328c2a72014-11-17 10:19:50 -08001816 response = main.TRUE
Jon Hallafa8a472015-06-12 14:02:42 -07001817
kelvin-onlab56a3f462015-02-06 14:04:43 -08001818 if i == 1:
1819 main.log.info( " Mininet trying to exit while not " +
1820 "in the mininet prompt" )
1821 elif i == 2:
1822 main.log.error( "Something went wrong exiting mininet" )
1823 elif i == 3: # timeout
1824 main.log.error( "Something went wrong exiting mininet " +
1825 "TIMEOUT" )
Jon Hallafa8a472015-06-12 14:02:42 -07001826
Hari Krishnab35c6d02015-03-18 11:13:51 -07001827 if fileName:
Jon Halld80cc142015-07-06 13:36:05 -07001828 self.handle.sendline( "" )
1829 self.handle.expect( '\$' )
1830 self.handle.sendline(
1831 "sudo kill -9 \`ps -ef | grep \"" +
1832 fileName +
1833 "\" | grep -v grep | awk '{print $2}'\`" )
Jon Hallfbc828e2015-01-06 17:30:19 -08001834 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001835 main.log.error( self.name + ": EOF exception found" )
1836 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001837 main.cleanup()
1838 main.exit()
Jon Hall7eb38402015-01-08 17:19:54 -08001839 else:
1840 main.log.error( self.name + ": Connection failed to the host" )
adminbae64d82013-08-01 10:50:15 -07001841 response = main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -08001842 return response
1843
Jon Halla5cb3412015-08-18 14:08:22 -07001844 def arping( self, srcHost="", dstHost="10.128.20.211", ethDevice="" ):
kelvin-onlab65782a82015-05-07 14:12:13 -07001845 """
1846 Description:
1847 Sends arp message from mininet host for hosts discovery
1848 Required:
1849 host - hosts name
1850 Optional:
1851 ip - ip address that does not exist in the network so there would
1852 be no reply.
1853 """
kelvin-onlabf0594d72015-05-19 17:25:12 -07001854 if ethDevice:
1855 ethDevice = '-I ' + ethDevice + ' '
Jon Halla5cb3412015-08-18 14:08:22 -07001856 cmd = srcHost + " arping -c1 " + ethDevice + dstHost
admin07529932013-11-22 14:58:28 -08001857 try:
Jon Halla5cb3412015-08-18 14:08:22 -07001858 main.log.info( "Sending: " + cmd )
kelvin-onlab65782a82015-05-07 14:12:13 -07001859 self.handle.sendline( cmd )
Jon Halla5cb3412015-08-18 14:08:22 -07001860 i = self.handle.expect( [ "mininet>", "arping: " ] )
1861 if i == 0:
1862 return main.TRUE
1863 elif i == 1:
1864 response = self.handle.before + self.handle.after
1865 self.handle.expect( "mininet>" )
1866 response += self.handle.before + self.handle.after
1867 main.log.warn( "Error sending arping, output was: " +
1868 response )
1869 return main.FALSE
1870 except pexpect.TIMEOUT:
1871 main.log.error( self.name + ": TIMEOUT exception found" )
1872 main.log.warn( self.handle.before )
1873 return main.FALSE
kelvin-onlab65782a82015-05-07 14:12:13 -07001874 except pexpect.EOF:
1875 main.log.error( self.name + ": EOF exception found" )
1876 main.log.error( self.name + ": " + self.handle.before )
1877 main.cleanup()
1878 main.exit()
admin07529932013-11-22 14:58:28 -08001879
Jon Hall7eb38402015-01-08 17:19:54 -08001880 def decToHex( self, num ):
1881 return hex( num ).split( 'x' )[ 1 ]
Jon Hallfbc828e2015-01-06 17:30:19 -08001882
Jon Hall7eb38402015-01-08 17:19:54 -08001883 def getSwitchFlowCount( self, switch ):
1884 """
1885 return the Flow Count of the switch"""
admin2a9548d2014-06-17 14:08:07 -07001886 if self.handle:
1887 cmd = "sh ovs-ofctl dump-aggregate %s" % switch
1888 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001889 response = self.execute(
1890 cmd=cmd,
1891 prompt="mininet>",
1892 timeout=10 )
admin2a9548d2014-06-17 14:08:07 -07001893 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001894 main.log.error( self.name + ": EOF exception found" )
1895 main.log.error( self.name + " " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07001896 main.cleanup()
1897 main.exit()
1898 pattern = "flow_count=(\d+)"
Jon Hall7eb38402015-01-08 17:19:54 -08001899 result = re.search( pattern, response, re.MULTILINE )
admin2a9548d2014-06-17 14:08:07 -07001900 if result is None:
Jon Hall7eb38402015-01-08 17:19:54 -08001901 main.log.info(
1902 "Couldn't find flows on switch %s, found: %s" %
1903 ( switch, response ) )
admin2a9548d2014-06-17 14:08:07 -07001904 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001905 return result.group( 1 )
admin2a9548d2014-06-17 14:08:07 -07001906 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001907 main.log.error( "Connection failed to the Mininet host" )
Jon Hallfbc828e2015-01-06 17:30:19 -08001908
Jon Hall9ed8f372016-02-24 17:34:07 -08001909 def checkFlows( self, sw, dumpFormat=None ):
1910 if dumpFormat:
1911 command = "sh ovs-ofctl -F " + \
1912 dumpFormat + " dump-flows " + str( sw )
1913 else:
1914 command = "sh ovs-ofctl dump-flows " + str( sw )
1915 try:
1916 response = self.execute(
1917 cmd=command,
1918 prompt="mininet>",
1919 timeout=10 )
1920 return response
1921 except pexpect.EOF:
1922 main.log.error( self.name + ": EOF exception found" )
1923 main.log.error( self.name + ": " + self.handle.before )
1924 main.cleanup()
1925 main.exit()
1926
GlennRC68467eb2015-11-16 18:01:01 -08001927 def flowTableComp( self, flowTable1, flowTable2 ):
1928 # This function compares the selctors and treatments of each flow
1929 try:
1930 if len(flowTable1) != len(flowTable2):
1931 main.log.warn( "Flow table lengths do not match" )
1932 return main.FALSE
GlennRCfa65fce2015-12-16 13:16:08 -08001933 dFields = ["n_bytes", "cookie", "n_packets", "duration"]
1934 for flow1, flow2 in zip(flowTable1, flowTable2):
Jon Hallacd1b182015-12-17 11:43:20 -08001935 for field in dFields:
1936 try:
1937 flow1.pop( field )
1938 except KeyError as e:
1939 main.log.warn( e )
1940 main.log.debug( flow1 )
1941 try:
1942 flow2.pop( field )
1943 except KeyError as e:
1944 main.log.warn( e )
1945 main.log.debug( flow2 )
GlennRC68467eb2015-11-16 18:01:01 -08001946 for i in range( len(flowTable1) ):
GlennRC17bbcf52015-12-14 17:31:50 -08001947 if flowTable1[i] not in flowTable2:
1948 main.log.warn( "Flow tables do not match:" )
1949 main.log.warn( "Old flow:\n{}\n not in new flow table".format( flowTable1[i] ) )
GlennRC68467eb2015-11-16 18:01:01 -08001950 return main.FALSE
Jon Hall9043c902015-07-30 14:23:44 -07001951 return main.TRUE
GlennRC68467eb2015-11-16 18:01:01 -08001952 except Exception:
1953 main.log.exception( "Uncaught exception!" )
1954 main.cleanup()
1955 main.exit()
Jon Hall9043c902015-07-30 14:23:44 -07001956
GlennRC528ad292015-11-12 10:38:18 -08001957 def parseFlowTable( self, flowTable, version="", debug=True ):
GlennRC956ea742015-11-05 16:14:15 -08001958 '''
1959 Discription: Parses flows into json format.
1960 NOTE: this can parse any string thats separated with commas
1961 Arguments:
1962 Required:
1963 flows: a list of strings that represnt flows
1964 Optional:
1965 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
1966 debug: prints out the final result
1967 returns: A list of flows in json format
1968 '''
GlennRC528ad292015-11-12 10:38:18 -08001969 jsonFlowTable = []
1970 for flow in flowTable:
GlennRC956ea742015-11-05 16:14:15 -08001971 jsonFlow = {}
GlennRC528ad292015-11-12 10:38:18 -08001972 # split up the fields of the flow
1973 parsedFlow = flow.split(", ")
1974 # get rid of any spaces in front of the field
1975 for i in range( len(parsedFlow) ):
1976 item = parsedFlow[i]
1977 if item[0] == " ":
1978 parsedFlow[i] = item[1:]
1979 # grab the selector and treatment from the parsed flow
1980 # the last element is the selector and the treatment
1981 temp = parsedFlow.pop(-1)
1982 # split up the selector and the treatment
1983 temp = temp.split(" ")
1984 index = 0
1985 # parse the flags
1986 # NOTE: This only parses one flag
1987 flag = {}
1988 if version == "1.3":
1989 flag = {"flag":[temp[index]]}
1990 index += 1
1991 # the first element is the selector and split it up
1992 sel = temp[index]
1993 index += 1
1994 sel = sel.split(",")
1995 # the priority is stuck in the selecter so put it back
1996 # in the flow
1997 parsedFlow.append(sel.pop(0))
1998 # parse selector
1999 criteria = []
2000 for item in sel:
2001 # this is the type of the packet e.g. "arp"
2002 if "=" not in item:
2003 criteria.append( {"type":item} )
2004 else:
2005 field = item.split("=")
2006 criteria.append( {field[0]:field[1]} )
GlennRC68467eb2015-11-16 18:01:01 -08002007 selector = {"selector": {"criteria":sorted(criteria)} }
GlennRC528ad292015-11-12 10:38:18 -08002008 treat = temp[index]
2009 # get rid of the action part e.g. "action=output:2"
2010 # we will add it back later
2011 treat = treat.split("=")
2012 treat.pop(0)
2013 # parse treatment
2014 action = []
2015 for item in treat:
2016 field = item.split(":")
2017 action.append( {field[0]:field[1]} )
2018 # create the treatment field and add the actions
GlennRC68467eb2015-11-16 18:01:01 -08002019 treatment = {"treatment": {"action":sorted(action)} }
GlennRC528ad292015-11-12 10:38:18 -08002020 # parse the rest of the flow
2021 for item in parsedFlow:
2022 field = item.split("=")
2023 jsonFlow.update( {field[0]:field[1]} )
2024 # add the treatment and the selector to the json flow
2025 jsonFlow.update( selector )
2026 jsonFlow.update( treatment )
2027 jsonFlow.update( flag )
GlennRC956ea742015-11-05 16:14:15 -08002028
GlennRC528ad292015-11-12 10:38:18 -08002029 if debug: main.log.debug( "\033[94mJson flow:\033[0m\n{}\n".format(jsonFlow) )
GlennRC956ea742015-11-05 16:14:15 -08002030
GlennRC528ad292015-11-12 10:38:18 -08002031 # add the json flow to the json flow table
2032 jsonFlowTable.append( jsonFlow )
GlennRC956ea742015-11-05 16:14:15 -08002033
GlennRC528ad292015-11-12 10:38:18 -08002034 return jsonFlowTable
2035
Jon Hall0a543792015-12-14 11:00:26 -08002036 def getFlowTable( self, sw, version="", debug=False):
GlennRC956ea742015-11-05 16:14:15 -08002037 '''
2038 Discription: Returns the flow table(s) on a switch or switches in a list.
2039 Each element is a flow.
2040 Arguments:
2041 Required:
2042 sw: The switch name ("s1") to retrive the flow table. Can also be
2043 a list of switches.
2044 Optional:
2045 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
2046 debug: prints out the final result
2047 '''
2048 try:
2049 switches = []
2050 if type(sw) is list:
Jon Hallca7ac292015-11-11 09:28:12 -08002051 switches.extend(sw)
GlennRC956ea742015-11-05 16:14:15 -08002052 else: switches.append(sw)
2053
2054 flows = []
2055 for s in switches:
2056 cmd = "sh ovs-ofctl dump-flows " + s
2057
GlennRC528ad292015-11-12 10:38:18 -08002058 if "1.0" == version:
2059 cmd += " -F OpenFlow10-table_id"
2060 elif "1.3" == version:
GlennRC956ea742015-11-05 16:14:15 -08002061 cmd += " -O OpenFlow13"
GlennRC956ea742015-11-05 16:14:15 -08002062
2063 main.log.info( "Sending: " + cmd )
2064 self.handle.sendline( cmd )
2065 self.handle.expect( "mininet>" )
2066 response = self.handle.before
2067 response = response.split( "\r\n" )
2068 # dump the first two elements and the last
2069 # the first element is the command that was sent
2070 # the second is the table header
2071 # the last element is empty
2072 response = response[2:-1]
2073 flows.extend( response )
2074
2075 if debug: print "Flows:\n{}\n\n".format(flows)
2076
GlennRC528ad292015-11-12 10:38:18 -08002077 return self.parseFlowTable( flows, version, debug )
GlennRC956ea742015-11-05 16:14:15 -08002078
2079 except pexpect.TIMEOUT:
2080 main.log.exception( self.name + ": Command timed out" )
2081 return None
2082 except pexpect.EOF:
2083 main.log.exception( self.name + ": connection closed." )
2084 main.cleanup()
2085 main.exit()
2086 except Exception:
2087 main.log.exception( self.name + ": Uncaught exception!" )
2088 main.cleanup()
2089 main.exit()
2090
2091 def checkFlowId( self, sw, flowId, version="1.3", debug=True ):
2092 '''
2093 Discription: Checks whether the ID provided matches a flow ID in Mininet
2094 Arguments:
2095 Required:
2096 sw: The switch name ("s1") to retrive the flow table. Can also be
2097 a list of switches.
2098 flowId: the flow ID in hex format. Can also be a list of IDs
2099 Optional:
2100 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
2101 debug: prints out the final result
2102 returns: main.TRUE if all IDs are present, otherwise returns main.FALSE
2103 NOTE: prints out IDs that are not present
2104 '''
2105 try:
2106 main.log.info( "Getting flows from Mininet" )
2107 flows = self.getFlowTable( sw, version, debug )
2108
2109 if debug: print "flow ids:\n{}\n\n".format(flowId)
2110
2111 # Check flowId is a list or a string
2112 if type( flowId ) is str:
2113 result = False
2114 for f in flows:
2115 if flowId in f.get( 'cookie' ):
2116 result = True
2117 break
2118 # flowId is a list
2119 else:
2120 result = True
2121 # Get flow IDs from Mininet
2122 mnFlowIds = [ f.get( 'cookie' ) for f in flows ]
2123 # Save the IDs that are not in Mininet
2124 absentIds = [ x for x in flowId if x not in mnFlowIds ]
2125
2126 if debug: print "mn flow ids:\n{}\n\n".format(mnFlowIds)
2127
2128 # Print out the IDs that are not in Mininet
2129 if absentIds:
2130 main.log.warn( "Absent ids: {}".format( absentIds ) )
2131 result = False
2132
2133 return main.TRUE if result else main.FALSE
2134
2135 except Exception:
2136 main.log.exception( self.name + ": Uncaught exception!" )
2137 main.cleanup()
2138 main.exit()
2139
2140
Charles Chan029be652015-08-24 01:46:10 +08002141 def startTcpdump( self, filename, intf="eth0", port="port 6653" ):
Jon Hall7eb38402015-01-08 17:19:54 -08002142 """
Jon Hallefbd9792015-03-05 16:11:36 -08002143 Runs tpdump on an interface and saves the file
Jon Hall7eb38402015-01-08 17:19:54 -08002144 intf can be specified, or the default eth0 is used"""
admin2a9548d2014-06-17 14:08:07 -07002145 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002146 self.handle.sendline( "" )
2147 self.handle.expect( "mininet>" )
2148 self.handle.sendline(
2149 "sh sudo tcpdump -n -i " +
2150 intf +
2151 " " +
2152 port +
2153 " -w " +
2154 filename.strip() +
2155 " &" )
2156 self.handle.sendline( "" )
2157 i = self.handle.expect( [ 'No\ssuch\device',
2158 'listening\son',
2159 pexpect.TIMEOUT,
2160 "mininet>" ],
2161 timeout=10 )
2162 main.log.warn( self.handle.before + self.handle.after )
2163 self.handle.sendline( "" )
2164 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002165 if i == 0:
Jon Hall7eb38402015-01-08 17:19:54 -08002166 main.log.error(
2167 self.name +
2168 ": tcpdump - No such device exists. " +
2169 "tcpdump attempted on: " +
2170 intf )
admin2a9548d2014-06-17 14:08:07 -07002171 return main.FALSE
2172 elif i == 1:
Jon Hall7eb38402015-01-08 17:19:54 -08002173 main.log.info( self.name + ": tcpdump started on " + intf )
admin2a9548d2014-06-17 14:08:07 -07002174 return main.TRUE
2175 elif i == 2:
Jon Hall7eb38402015-01-08 17:19:54 -08002176 main.log.error(
2177 self.name +
2178 ": tcpdump command timed out! Check interface name," +
2179 " given interface was: " +
2180 intf )
admin2a9548d2014-06-17 14:08:07 -07002181 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08002182 elif i == 3:
2183 main.log.info( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002184 return main.TRUE
2185 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002186 main.log.error( self.name + ": tcpdump - unexpected response" )
admin2a9548d2014-06-17 14:08:07 -07002187 return main.FALSE
2188 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002189 main.log.error( self.name + ": EOF exception found" )
2190 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002191 main.cleanup()
2192 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -08002193 except Exception:
2194 main.log.exception( self.name + ": Uncaught exception!" )
admin2a9548d2014-06-17 14:08:07 -07002195 main.cleanup()
2196 main.exit()
2197
kelvin-onlabd3b64892015-01-20 13:26:24 -08002198 def stopTcpdump( self ):
Jon Hallefbd9792015-03-05 16:11:36 -08002199 """
2200 pkills tcpdump"""
admin2a9548d2014-06-17 14:08:07 -07002201 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002202 self.handle.sendline( "sh sudo pkill tcpdump" )
2203 self.handle.expect( "mininet>" )
2204 self.handle.sendline( "" )
2205 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002206 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002207 main.log.error( self.name + ": EOF exception found" )
2208 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002209 main.cleanup()
2210 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -08002211 except Exception:
2212 main.log.exception( self.name + ": Uncaught exception!" )
admin2a9548d2014-06-17 14:08:07 -07002213 main.cleanup()
2214 main.exit()
2215
Jon Halld80cc142015-07-06 13:36:05 -07002216 def getPorts( self, nodeName, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002217 """
2218 Read ports from a Mininet switch.
2219
2220 Returns a json structure containing information about the
2221 ports of the given switch.
2222 """
2223 response = self.getInterfaces( nodeName )
2224 # TODO: Sanity check on response. log if no such switch exists
2225 ports = []
2226 for line in response.split( "\n" ):
2227 if not line.startswith( "name=" ):
2228 continue
2229 portVars = {}
2230 for var in line.split( "," ):
2231 key, value = var.split( "=" )
2232 portVars[ key ] = value
2233 isUp = portVars.pop( 'enabled', "True" )
2234 isUp = "True" in isUp
2235 if verbose:
2236 main.log.info( "Reading switch port %s(%s)" %
2237 ( portVars[ 'name' ], portVars[ 'mac' ] ) )
2238 mac = portVars[ 'mac' ]
Jon Halld80cc142015-07-06 13:36:05 -07002239 if mac == 'None':
Jon Hallafa8a472015-06-12 14:02:42 -07002240 mac = None
2241 ips = []
2242 ip = portVars[ 'ip' ]
2243 if ip == 'None':
2244 ip = None
2245 ips.append( ip )
2246 name = portVars[ 'name' ]
2247 if name == 'None':
2248 name = None
2249 portRe = r'[^\-]\d\-eth(?P<port>\d+)'
2250 if name == 'lo':
2251 portNo = 0xfffe # TODO: 1.0 value - Should we just return lo?
2252 else:
2253 portNo = re.search( portRe, name ).group( 'port' )
2254 ports.append( { 'of_port': portNo,
2255 'mac': str( mac ).replace( '\'', '' ),
2256 'name': name,
2257 'ips': ips,
2258 'enabled': isUp } )
2259 return ports
2260
Jon Halld80cc142015-07-06 13:36:05 -07002261 def getSwitches( self, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002262 """
2263 Read switches from Mininet.
2264
2265 Returns a dictionary whose keys are the switch names and the value is
2266 a dictionary containing information about the switch.
2267 """
Jon Halla22481b2015-07-28 17:46:01 -07002268 # NOTE: To support new Mininet switch classes, just append the new
2269 # class to the switchClasses variable
Jon Hallafa8a472015-06-12 14:02:42 -07002270
Jon Halla22481b2015-07-28 17:46:01 -07002271 # Regex patterns to parse 'dump' output
2272 # Example Switches:
Jon Hallafa8a472015-06-12 14:02:42 -07002273 # <OVSSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None pid=5238>
Jon Halld80cc142015-07-06 13:36:05 -07002274 # <OVSSwitch{ 'protocols': 'OpenFlow10' } s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=25974>
Jon Halla22481b2015-07-28 17:46:01 -07002275 # <OVSSwitchNS s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None pid=22550>
2276 # <OVSBridge s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=26830>
2277 # <UserSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=14737>
2278 switchClasses = r"(OVSSwitch)|(OVSBridge)|(OVSSwitchNS)|(IVSSwitch)|(LinuxBridge)|(UserSwitch)"
2279 swRE = r"<(?P<class>" + switchClasses + r")" +\
2280 r"(?P<options>\{.*\})?\s" +\
2281 r"(?P<name>[^:]+)\:\s" +\
2282 r"(?P<ports>([^,]+,)*[^,\s]+)" +\
2283 r"\spid=(?P<pid>(\d)+)"
Jon Hallafa8a472015-06-12 14:02:42 -07002284 # Update mn port info
2285 self.update()
Jon Halld80cc142015-07-06 13:36:05 -07002286 output = {}
Jon Hallafa8a472015-06-12 14:02:42 -07002287 dump = self.dump().split( "\n" )
2288 for line in dump:
Jon Halla22481b2015-07-28 17:46:01 -07002289 result = re.search( swRE, line, re.I )
2290 if result:
Jon Hallafa8a472015-06-12 14:02:42 -07002291 name = result.group( 'name' )
2292 dpid = str( self.getSwitchDPID( name ) ).zfill( 16 )
Jon Halla22481b2015-07-28 17:46:01 -07002293 pid = result.group( 'pid' )
2294 swClass = result.group( 'class' )
2295 options = result.group( 'options' )
Jon Hallafa8a472015-06-12 14:02:42 -07002296 if verbose:
2297 main.log.info( "Reading switch %s(%s)" % ( name, dpid ) )
2298 ports = self.getPorts( name )
Jon Halla22481b2015-07-28 17:46:01 -07002299 output[ name ] = { "dpid": dpid,
2300 "ports": ports,
2301 "swClass": swClass,
2302 "pid": pid,
2303 "options": options }
Jon Hallafa8a472015-06-12 14:02:42 -07002304 return output
2305
Jon Halld80cc142015-07-06 13:36:05 -07002306 def getHosts( self, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002307 """
2308 Read hosts from Mininet.
2309
2310 Returns a dictionary whose keys are the host names and the value is
2311 a dictionary containing information about the host.
2312 """
2313 # Regex patterns to parse dump output
2314 # Example host: <Host h1: h1-eth0:10.0.0.1 pid=5227>
kelvin-onlab299ab062015-07-15 10:58:27 -07002315 # <Host h1: pid=12725>
2316 # <VLANHost h12: h12-eth0.100.100.100:100.1.0.3 pid=30186>
2317 # <dualStackHost h19: h19-eth0:10.1.0.9 pid=30200>
2318 # <IPv6Host h18: h18-eth0:10.0.0.18 pid=30198>
Jon Hallafa8a472015-06-12 14:02:42 -07002319 # NOTE: Does not correctly match hosts with multi-links
2320 # <Host h2: h2-eth0:10.0.0.2,h2-eth1:10.0.1.2 pid=14386>
2321 # FIXME: Fix that
kelvin-onlabd48a68c2015-07-13 16:01:36 -07002322 hostRE = r"Host\s(?P<name>[^:]+)\:((\s(?P<ifname>[^:]+)\:" +\
Jon Halld80cc142015-07-06 13:36:05 -07002323 "(?P<ip>[^\s]+))|(\s)\spid=(?P<pid>[^>]+))"
Jon Hallafa8a472015-06-12 14:02:42 -07002324 # update mn port info
2325 self.update()
2326 # Get mininet dump
2327 dump = self.dump().split( "\n" )
Jon Hall5b0120a2015-06-12 17:35:53 -07002328 hosts = {}
Jon Hallafa8a472015-06-12 14:02:42 -07002329 for line in dump:
kelvin-onlabd48a68c2015-07-13 16:01:36 -07002330 if "Host" in line :
Jon Hallafa8a472015-06-12 14:02:42 -07002331 result = re.search( hostRE, line )
2332 name = result.group( 'name' )
2333 interfaces = []
2334 response = self.getInterfaces( name )
2335 # Populate interface info
2336 for line in response.split( "\n" ):
2337 if line.startswith( "name=" ):
2338 portVars = {}
2339 for var in line.split( "," ):
2340 key, value = var.split( "=" )
2341 portVars[ key ] = value
2342 isUp = portVars.pop( 'enabled', "True" )
2343 isUp = "True" in isUp
2344 if verbose:
2345 main.log.info( "Reading host port %s(%s)" %
2346 ( portVars[ 'name' ],
2347 portVars[ 'mac' ] ) )
2348 mac = portVars[ 'mac' ]
Jon Halld80cc142015-07-06 13:36:05 -07002349 if mac == 'None':
Jon Hallafa8a472015-06-12 14:02:42 -07002350 mac = None
2351 ips = []
2352 ip = portVars[ 'ip' ]
2353 if ip == 'None':
2354 ip = None
2355 ips.append( ip )
2356 intfName = portVars[ 'name' ]
2357 if name == 'None':
2358 name = None
2359 interfaces.append( {
2360 "name": intfName,
2361 "ips": ips,
2362 "mac": str( mac ),
2363 "isUp": isUp } )
Jon Hall5b0120a2015-06-12 17:35:53 -07002364 hosts[ name ] = { "interfaces": interfaces }
Jon Hallafa8a472015-06-12 14:02:42 -07002365 return hosts
2366
2367 def getLinks( self ):
2368 """
2369 Gathers information about current Mininet links. These links may not
2370 be up if one of the ports is down.
2371
2372 Returns a list of dictionaries with link endpoints.
2373
2374 The dictionary structure is:
Jon Halld80cc142015-07-06 13:36:05 -07002375 { 'node1': str( node1 name )
2376 'node2': str( node2 name )
2377 'port1': str( port1 of_port )
2378 'port2': str( port2 of_port ) }
Jon Hallafa8a472015-06-12 14:02:42 -07002379 Note: The port number returned is the eth#, not necessarily the of_port
2380 number. In Mininet, for OVS switch, these should be the same. For
2381 hosts, this is just the eth#.
2382 """
2383 self.update()
2384 response = self.links().split( '\n' )
2385
2386 # Examples:
2387 # s1-eth3<->s2-eth1 (OK OK)
2388 # s13-eth3<->h27-eth0 (OK OK)
2389 linkRE = "(?P<node1>[\w]+)\-eth(?P<port1>[\d]+)\<\-\>" +\
2390 "(?P<node2>[\w]+)\-eth(?P<port2>[\d]+)"
2391 links = []
2392 for line in response:
2393 match = re.search( linkRE, line )
2394 if match:
2395 node1 = match.group( 'node1' )
2396 node2 = match.group( 'node2' )
2397 port1 = match.group( 'port1' )
2398 port2 = match.group( 'port2' )
2399 links.append( { 'node1': node1,
2400 'node2': node2,
2401 'port1': port1,
2402 'port2': port2 } )
2403 return links
2404
2405 def compareSwitches( self, switches, switchesJson, portsJson ):
Jon Hall7eb38402015-01-08 17:19:54 -08002406 """
2407 Compare mn and onos switches
Jon Hallafa8a472015-06-12 14:02:42 -07002408 switchesJson: parsed json object from the onos devices api
Jon Hall3d87d502014-10-17 18:37:42 -04002409
Jon Hallafa8a472015-06-12 14:02:42 -07002410 Dependencies:
2411 1. numpy - "sudo pip install numpy"
2412 """
2413 from numpy import uint64
Jon Hall3d87d502014-10-17 18:37:42 -04002414 # created sorted list of dpid's in MN and ONOS for comparison
Jon Hall7eb38402015-01-08 17:19:54 -08002415 mnDPIDs = []
Jon Hallafa8a472015-06-12 14:02:42 -07002416 for swName, switch in switches.iteritems():
Jon Hall7eb38402015-01-08 17:19:54 -08002417 mnDPIDs.append( switch[ 'dpid' ].lower() )
Jon Hall3d87d502014-10-17 18:37:42 -04002418 mnDPIDs.sort()
kelvin-onlabd3b64892015-01-20 13:26:24 -08002419 if switchesJson == "": # if rest call fails
Jon Hall7eb38402015-01-08 17:19:54 -08002420 main.log.error(
2421 self.name +
Jon Hallfeff3082015-05-19 10:23:26 -07002422 ".compareSwitches(): Empty JSON object given from ONOS" )
Jon Hall3d87d502014-10-17 18:37:42 -04002423 return main.FALSE
kelvin-onlabd3b64892015-01-20 13:26:24 -08002424 onos = switchesJson
Jon Hall7eb38402015-01-08 17:19:54 -08002425 onosDPIDs = []
Jon Hall3d87d502014-10-17 18:37:42 -04002426 for switch in onos:
Jon Hall7eb38402015-01-08 17:19:54 -08002427 if switch[ 'available' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002428 onosDPIDs.append(
2429 switch[ 'id' ].replace(
2430 ":",
2431 '' ).replace(
2432 "of",
2433 '' ).lower() )
Jon Hall3d87d502014-10-17 18:37:42 -04002434 onosDPIDs.sort()
Jon Hall3d87d502014-10-17 18:37:42 -04002435
Jon Hall7eb38402015-01-08 17:19:54 -08002436 if mnDPIDs != onosDPIDs:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002437 switchResults = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002438 main.log.error( "Switches in MN but not in ONOS:" )
Jon Hall7eb38402015-01-08 17:19:54 -08002439 list1 = [ switch for switch in mnDPIDs if switch not in onosDPIDs ]
Jon Hallafa8a472015-06-12 14:02:42 -07002440 main.log.error( str( list1 ) )
2441 main.log.error( "Switches in ONOS but not in MN:" )
Jon Hall7eb38402015-01-08 17:19:54 -08002442 list2 = [ switch for switch in onosDPIDs if switch not in mnDPIDs ]
Jon Hallafa8a472015-06-12 14:02:42 -07002443 main.log.error( str( list2 ) )
Jon Hall7eb38402015-01-08 17:19:54 -08002444 else: # list of dpid's match in onos and mn
kelvin-onlabd3b64892015-01-20 13:26:24 -08002445 switchResults = main.TRUE
Jon Hallafa8a472015-06-12 14:02:42 -07002446 finalResults = switchResults
Jon Hall3d87d502014-10-17 18:37:42 -04002447
Jon Hall7eb38402015-01-08 17:19:54 -08002448 # FIXME: this does not look for extra ports in ONOS, only checks that
2449 # ONOS has what is in MN
kelvin-onlabd3b64892015-01-20 13:26:24 -08002450 portsResults = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002451
Jon Hall7eb38402015-01-08 17:19:54 -08002452 # PORTS
Jon Hallafa8a472015-06-12 14:02:42 -07002453 for name, mnSwitch in switches.iteritems():
kelvin-onlabd3b64892015-01-20 13:26:24 -08002454 mnPorts = []
2455 onosPorts = []
2456 switchResult = main.TRUE
2457 for port in mnSwitch[ 'ports' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002458 if port[ 'enabled' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002459 mnPorts.append( int( port[ 'of_port' ] ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002460 for onosSwitch in portsJson:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002461 if onosSwitch[ 'device' ][ 'available' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002462 if onosSwitch[ 'device' ][ 'id' ].replace(
2463 ':',
2464 '' ).replace(
2465 "of",
2466 '' ) == mnSwitch[ 'dpid' ]:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002467 for port in onosSwitch[ 'ports' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002468 if port[ 'isEnabled' ]:
2469 if port[ 'port' ] == 'local':
kelvin-onlabd3b64892015-01-20 13:26:24 -08002470 # onosPorts.append( 'local' )
2471 onosPorts.append( long( uint64( -2 ) ) )
Jon Hallb1290e82014-11-18 16:17:48 -05002472 else:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002473 onosPorts.append( int( port[ 'port' ] ) )
Jon Hallb1290e82014-11-18 16:17:48 -05002474 break
kelvin-onlabd3b64892015-01-20 13:26:24 -08002475 mnPorts.sort( key=float )
2476 onosPorts.sort( key=float )
Jon Hallafa8a472015-06-12 14:02:42 -07002477
kelvin-onlabd3b64892015-01-20 13:26:24 -08002478 mnPortsLog = mnPorts
2479 onosPortsLog = onosPorts
2480 mnPorts = [ x for x in mnPorts ]
2481 onosPorts = [ x for x in onosPorts ]
Jon Hall38481722014-11-04 16:50:05 -05002482
Jon Hall7eb38402015-01-08 17:19:54 -08002483 # TODO: handle other reserved port numbers besides LOCAL
2484 # NOTE: Reserved ports
2485 # Local port: -2 in Openflow, ONOS shows 'local', we store as
2486 # long( uint64( -2 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002487 for mnPort in mnPortsLog:
2488 if mnPort in onosPorts:
Jon Hall7eb38402015-01-08 17:19:54 -08002489 # don't set results to true here as this is just one of
2490 # many checks and it might override a failure
kelvin-onlabd3b64892015-01-20 13:26:24 -08002491 mnPorts.remove( mnPort )
2492 onosPorts.remove( mnPort )
Jon Hallafa8a472015-06-12 14:02:42 -07002493
Jon Hall7eb38402015-01-08 17:19:54 -08002494 # NOTE: OVS reports this as down since there is no link
Jon Hallb1290e82014-11-18 16:17:48 -05002495 # So ignoring these for now
Jon Hall7eb38402015-01-08 17:19:54 -08002496 # TODO: Come up with a better way of handling these
kelvin-onlabd3b64892015-01-20 13:26:24 -08002497 if 65534 in mnPorts:
2498 mnPorts.remove( 65534 )
2499 if long( uint64( -2 ) ) in onosPorts:
2500 onosPorts.remove( long( uint64( -2 ) ) )
2501 if len( mnPorts ): # the ports of this switch don't match
2502 switchResult = main.FALSE
2503 main.log.warn( "Ports in MN but not ONOS: " + str( mnPorts ) )
2504 if len( onosPorts ): # the ports of this switch don't match
2505 switchResult = main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08002506 main.log.warn(
2507 "Ports in ONOS but not MN: " +
kelvin-onlabd3b64892015-01-20 13:26:24 -08002508 str( onosPorts ) )
2509 if switchResult == main.FALSE:
Jon Hallafa8a472015-06-12 14:02:42 -07002510 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002511 "The list of ports for switch %s(%s) does not match:" %
Jon Hallafa8a472015-06-12 14:02:42 -07002512 ( name, mnSwitch[ 'dpid' ] ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002513 main.log.warn( "mn_ports[] = " + str( mnPortsLog ) )
2514 main.log.warn( "onos_ports[] = " + str( onosPortsLog ) )
2515 portsResults = portsResults and switchResult
Jon Hallafa8a472015-06-12 14:02:42 -07002516 finalResults = finalResults and portsResults
2517 return finalResults
Jon Hall72cf1dc2014-10-20 21:04:50 -04002518
Jon Hallafa8a472015-06-12 14:02:42 -07002519 def compareLinks( self, switches, links, linksJson ):
Jon Hall7eb38402015-01-08 17:19:54 -08002520 """
2521 Compare mn and onos links
kelvin-onlabd3b64892015-01-20 13:26:24 -08002522 linksJson: parsed json object from the onos links api
Jon Hall72cf1dc2014-10-20 21:04:50 -04002523
Jon Hallafa8a472015-06-12 14:02:42 -07002524 """
Jon Hall7eb38402015-01-08 17:19:54 -08002525 # FIXME: this does not look for extra links in ONOS, only checks that
Jon Hallefbd9792015-03-05 16:11:36 -08002526 # ONOS has what is in MN
kelvin-onlabd3b64892015-01-20 13:26:24 -08002527 onos = linksJson
Jon Hall72cf1dc2014-10-20 21:04:50 -04002528
Jon Halld80cc142015-07-06 13:36:05 -07002529 mnLinks = []
Jon Hallafa8a472015-06-12 14:02:42 -07002530 for l in links:
2531 try:
2532 node1 = switches[ l[ 'node1' ] ]
2533 node2 = switches[ l[ 'node2' ] ]
2534 enabled = True
2535 for port in node1[ 'ports' ]:
2536 if port[ 'of_port' ] == l[ 'port1' ]:
2537 enabled = enabled and port[ 'enabled' ]
2538 for port in node2[ 'ports' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002539 if port[ 'of_port' ] == l[ 'port2' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002540 enabled = enabled and port[ 'enabled' ]
2541 if enabled:
2542 mnLinks.append( l )
2543 except KeyError:
2544 pass
kelvin-onlabd3b64892015-01-20 13:26:24 -08002545 if 2 * len( mnLinks ) == len( onos ):
2546 linkResults = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002547 else:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002548 linkResults = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002549 main.log.error(
Jon Hall328ddca2015-01-28 15:57:15 -08002550 "Mininet has " + str( len( mnLinks ) ) +
2551 " bidirectional links and ONOS has " +
2552 str( len( onos ) ) + " unidirectional links" )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002553
Jon Hall7eb38402015-01-08 17:19:54 -08002554 # iterate through MN links and check if an ONOS link exists in
2555 # both directions
kelvin-onlabd3b64892015-01-20 13:26:24 -08002556 for link in mnLinks:
Jon Hall7eb38402015-01-08 17:19:54 -08002557 # TODO: Find a more efficient search method
Jon Hall72cf1dc2014-10-20 21:04:50 -04002558 node1 = None
2559 port1 = None
2560 node2 = None
2561 port2 = None
kelvin-onlabd3b64892015-01-20 13:26:24 -08002562 firstDir = main.FALSE
2563 secondDir = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002564 for swName, switch in switches.iteritems():
2565 if swName == link[ 'node1' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002566 node1 = switch[ 'dpid' ]
2567 for port in switch[ 'ports' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002568 if str( port[ 'of_port' ] ) == str( link[ 'port1' ] ):
Jon Hall7eb38402015-01-08 17:19:54 -08002569 port1 = port[ 'of_port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002570 if node1 is not None and node2 is not None:
2571 break
Jon Hallafa8a472015-06-12 14:02:42 -07002572 if swName == link[ 'node2' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002573 node2 = switch[ 'dpid' ]
2574 for port in switch[ 'ports' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002575 if str( port[ 'of_port' ] ) == str( link[ 'port2' ] ):
Jon Hall7eb38402015-01-08 17:19:54 -08002576 port2 = port[ 'of_port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002577 if node1 is not None and node2 is not None:
2578 break
2579
kelvin-onlabd3b64892015-01-20 13:26:24 -08002580 for onosLink in onos:
2581 onosNode1 = onosLink[ 'src' ][ 'device' ].replace(
Jon Hallafa8a472015-06-12 14:02:42 -07002582 ":", '' ).replace( "of", '' )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002583 onosNode2 = onosLink[ 'dst' ][ 'device' ].replace(
Jon Hallafa8a472015-06-12 14:02:42 -07002584 ":", '' ).replace( "of", '' )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002585 onosPort1 = onosLink[ 'src' ][ 'port' ]
2586 onosPort2 = onosLink[ 'dst' ][ 'port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002587
Jon Hall72cf1dc2014-10-20 21:04:50 -04002588 # check onos link from node1 to node2
kelvin-onlabd3b64892015-01-20 13:26:24 -08002589 if str( onosNode1 ) == str( node1 ) and str(
2590 onosNode2 ) == str( node2 ):
2591 if int( onosPort1 ) == int( port1 ) and int(
2592 onosPort2 ) == int( port2 ):
2593 firstDir = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002594 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002595 main.log.warn(
2596 'The port numbers do not match for ' +
2597 str( link ) +
Jon Hallefbd9792015-03-05 16:11:36 -08002598 ' between ONOS and MN. When checking ONOS for ' +
Jon Hall7eb38402015-01-08 17:19:54 -08002599 'link %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002600 ( node1, port1, node2, port2 ) +
Jon Hall7eb38402015-01-08 17:19:54 -08002601 ' ONOS has the values %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002602 ( onosNode1, onosPort1, onosNode2, onosPort2 ) )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002603
2604 # check onos link from node2 to node1
kelvin-onlabd3b64892015-01-20 13:26:24 -08002605 elif ( str( onosNode1 ) == str( node2 ) and
2606 str( onosNode2 ) == str( node1 ) ):
2607 if ( int( onosPort1 ) == int( port2 )
2608 and int( onosPort2 ) == int( port1 ) ):
2609 secondDir = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002610 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002611 main.log.warn(
2612 'The port numbers do not match for ' +
2613 str( link ) +
Jon Hallefbd9792015-03-05 16:11:36 -08002614 ' between ONOS and MN. When checking ONOS for ' +
Jon Hall7eb38402015-01-08 17:19:54 -08002615 'link %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002616 ( node1, port1, node2, port2 ) +
Jon Hall7eb38402015-01-08 17:19:54 -08002617 ' ONOS has the values %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002618 ( onosNode2, onosPort2, onosNode1, onosPort1 ) )
Jon Hall7eb38402015-01-08 17:19:54 -08002619 else: # this is not the link you're looking for
Jon Hall72cf1dc2014-10-20 21:04:50 -04002620 pass
kelvin-onlabd3b64892015-01-20 13:26:24 -08002621 if not firstDir:
Jon Hallafa8a472015-06-12 14:02:42 -07002622 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002623 'ONOS does not have the link %s/%s -> %s/%s' %
2624 ( node1, port1, node2, port2 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002625 if not secondDir:
Jon Hallafa8a472015-06-12 14:02:42 -07002626 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002627 'ONOS does not have the link %s/%s -> %s/%s' %
2628 ( node2, port2, node1, port1 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002629 linkResults = linkResults and firstDir and secondDir
2630 return linkResults
Jon Hall72cf1dc2014-10-20 21:04:50 -04002631
Jon Hallafa8a472015-06-12 14:02:42 -07002632 def compareHosts( self, hosts, hostsJson ):
Jon Hallff6b4b22015-02-23 09:25:15 -08002633 """
Jon Hallafa8a472015-06-12 14:02:42 -07002634 Compare mn and onos Hosts.
2635 Since Mininet hosts are quiet, ONOS will only know of them when they
2636 speak. For this reason, we will only check that the hosts in ONOS
2637 stores are in Mininet, and not vice versa.
Jon Hallff6b4b22015-02-23 09:25:15 -08002638
Jon Hallafa8a472015-06-12 14:02:42 -07002639 Arguments:
2640 hostsJson: parsed json object from the onos hosts api
2641 Returns:
2642 """
Jon Hallff6b4b22015-02-23 09:25:15 -08002643 import json
2644 hostResults = main.TRUE
Jon Hallff6b4b22015-02-23 09:25:15 -08002645 for onosHost in hostsJson:
2646 onosMAC = onosHost[ 'mac' ].lower()
2647 match = False
Jon Halld80cc142015-07-06 13:36:05 -07002648 for mnHost, info in hosts.iteritems():
2649 for mnIntf in info[ 'interfaces' ]:
2650 if onosMAC == mnIntf[ 'mac' ].lower():
Jon Hallff6b4b22015-02-23 09:25:15 -08002651 match = True
2652 for ip in mnIntf[ 'ips' ]:
Jon Hallfeff3082015-05-19 10:23:26 -07002653 if ip in onosHost[ 'ipAddresses' ]:
Jon Hallff6b4b22015-02-23 09:25:15 -08002654 pass # all is well
2655 else:
2656 # misssing ip
Jon Halld80cc142015-07-06 13:36:05 -07002657 main.log.error( "ONOS host " +
2658 onosHost[ 'id' ] +
2659 " has a different IP(" +
Jon Hallafa8a472015-06-12 14:02:42 -07002660 str( onosHost[ 'ipAddresses' ] ) +
2661 ") than the Mininet host(" +
Jon Halld80cc142015-07-06 13:36:05 -07002662 str( ip ) +
2663 ")." )
Jon Hallff6b4b22015-02-23 09:25:15 -08002664 output = json.dumps(
Jon Halld80cc142015-07-06 13:36:05 -07002665 onosHost,
2666 sort_keys=True,
2667 indent=4,
2668 separators=( ',', ': ' ) )
Jon Hallff6b4b22015-02-23 09:25:15 -08002669 main.log.info( output )
2670 hostResults = main.FALSE
2671 if not match:
2672 hostResults = main.FALSE
2673 main.log.error( "ONOS host " + onosHost[ 'id' ] + " has no " +
2674 "corresponding Mininet host." )
2675 output = json.dumps( onosHost,
2676 sort_keys=True,
2677 indent=4,
2678 separators=( ',', ': ' ) )
2679 main.log.info( output )
Jon Hallff6b4b22015-02-23 09:25:15 -08002680 return hostResults
2681
Jon Hallafa8a472015-06-12 14:02:42 -07002682 def getHostsOld( self ):
Jon Hall7eb38402015-01-08 17:19:54 -08002683 """
2684 Returns a list of all hosts
2685 Don't ask questions just use it"""
2686 self.handle.sendline( "" )
2687 self.handle.expect( "mininet>" )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002688
Jon Hall7eb38402015-01-08 17:19:54 -08002689 self.handle.sendline( "py [ host.name for host in net.hosts ]" )
2690 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002691
kelvin-onlabd3b64892015-01-20 13:26:24 -08002692 handlePy = self.handle.before
2693 handlePy = handlePy.split( "]\r\n", 1 )[ 1 ]
2694 handlePy = handlePy.rstrip()
admin2a9548d2014-06-17 14:08:07 -07002695
Jon Hall7eb38402015-01-08 17:19:54 -08002696 self.handle.sendline( "" )
2697 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002698
kelvin-onlabd3b64892015-01-20 13:26:24 -08002699 hostStr = handlePy.replace( "]", "" )
2700 hostStr = hostStr.replace( "'", "" )
2701 hostStr = hostStr.replace( "[", "" )
kelvin-onlab2ccad6e2015-05-18 10:36:54 -07002702 hostStr = hostStr.replace( " ", "" )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002703 hostList = hostStr.split( "," )
andrewonlab3f0a4af2014-10-17 12:25:14 -04002704
kelvin-onlabd3b64892015-01-20 13:26:24 -08002705 return hostList
adminbae64d82013-08-01 10:50:15 -07002706
kelvin-onlabfa6ada82015-06-11 13:06:24 -07002707 def getSwitch( self ):
2708 """
2709 Returns a list of all switches
2710 Again, don't ask question just use it...
2711 """
2712 # get host list...
2713 hostList = self.getHosts()
2714 # Make host set
2715 hostSet = set( hostList )
2716
2717 # Getting all the nodes in mininet
2718 self.handle.sendline( "" )
2719 self.handle.expect( "mininet>" )
2720
2721 self.handle.sendline( "py [ node.name for node in net.values() ]" )
2722 self.handle.expect( "mininet>" )
2723
2724 handlePy = self.handle.before
2725 handlePy = handlePy.split( "]\r\n", 1 )[ 1 ]
2726 handlePy = handlePy.rstrip()
2727
2728 self.handle.sendline( "" )
2729 self.handle.expect( "mininet>" )
2730
2731 nodesStr = handlePy.replace( "]", "" )
2732 nodesStr = nodesStr.replace( "'", "" )
2733 nodesStr = nodesStr.replace( "[", "" )
2734 nodesStr = nodesStr.replace( " ", "" )
2735 nodesList = nodesStr.split( "," )
2736
2737 nodesSet = set( nodesList )
2738 # discarding default controller(s) node
2739 nodesSet.discard( 'c0' )
2740 nodesSet.discard( 'c1' )
2741 nodesSet.discard( 'c2' )
2742
2743 switchSet = nodesSet - hostSet
2744 switchList = list( switchSet )
2745
2746 return switchList
2747
Jon Hall7eb38402015-01-08 17:19:54 -08002748 def update( self ):
2749 """
2750 updates the port address and status information for
2751 each port in mn"""
2752 # TODO: Add error checking. currently the mininet command has no output
Jon Hallefbd9792015-03-05 16:11:36 -08002753 main.log.info( "Updating MN port information" )
Jon Hallb1290e82014-11-18 16:17:48 -05002754 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002755 self.handle.sendline( "" )
2756 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002757
Jon Hall7eb38402015-01-08 17:19:54 -08002758 self.handle.sendline( "update" )
2759 self.handle.expect( "update" )
2760 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002761
Jon Hall7eb38402015-01-08 17:19:54 -08002762 self.handle.sendline( "" )
2763 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002764
Jon Hallb1290e82014-11-18 16:17:48 -05002765 return main.TRUE
2766 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002767 main.log.error( self.name + ": EOF exception found" )
2768 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05002769 main.cleanup()
2770 main.exit()
2771
Jon Halld80cc142015-07-06 13:36:05 -07002772 def assignVLAN( self, host, intf, vlan ):
kaouthera3f13ca22015-05-05 15:01:41 -07002773 """
2774 Add vlan tag to a host.
2775 Dependencies:
2776 This class depends on the "vlan" package
2777 $ sudo apt-get install vlan
2778 Configuration:
2779 Load the 8021q module into the kernel
2780 $sudo modprobe 8021q
2781
2782 To make this setup permanent:
2783 $ sudo su -c 'echo "8021q" >> /etc/modules'
2784 """
2785 if self.handle:
2786 try:
Jon Halld80cc142015-07-06 13:36:05 -07002787 # get the ip address of the host
2788 main.log.info( "Get the ip address of the host" )
2789 ipaddr = self.getIPAddress( host )
2790 print repr( ipaddr )
kaouthera3f13ca22015-05-05 15:01:41 -07002791
Jon Halld80cc142015-07-06 13:36:05 -07002792 # remove IP from interface intf
2793 # Ex: h1 ifconfig h1-eth0 inet 0
2794 main.log.info( "Remove IP from interface " )
2795 cmd2 = host + " ifconfig " + intf + " " + " inet 0 "
2796 self.handle.sendline( cmd2 )
2797 self.handle.expect( "mininet>" )
2798 response = self.handle.before
2799 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002800
Jon Halld80cc142015-07-06 13:36:05 -07002801 # create VLAN interface
2802 # Ex: h1 vconfig add h1-eth0 100
2803 main.log.info( "Create Vlan" )
2804 cmd3 = host + " vconfig add " + intf + " " + vlan
2805 self.handle.sendline( cmd3 )
2806 self.handle.expect( "mininet>" )
2807 response = self.handle.before
2808 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002809
Jon Halld80cc142015-07-06 13:36:05 -07002810 # assign the host's IP to the VLAN interface
2811 # Ex: h1 ifconfig h1-eth0.100 inet 10.0.0.1
2812 main.log.info( "Assign the host IP to the vlan interface" )
2813 vintf = intf + "." + vlan
2814 cmd4 = host + " ifconfig " + vintf + " " + " inet " + ipaddr
2815 self.handle.sendline( cmd4 )
2816 self.handle.expect( "mininet>" )
2817 response = self.handle.before
2818 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002819
2820 return main.TRUE
2821 except pexpect.EOF:
2822 main.log.error( self.name + ": EOF exception found" )
2823 main.log.error( self.name + ": " + self.handle.before )
2824 return main.FALSE
2825
Jon Hall892818c2015-10-20 17:58:34 -07002826 def createHostComponent( self, name ):
2827 """
2828 Creates a new mininet cli component with the same parameters as self.
2829 This new component is intended to be used to login to the hosts created
2830 by mininet.
2831
2832 Arguments:
2833 name - The string of the name of this component. The new component
2834 will be assigned to main.<name> .
2835 In addition, main.<name>.name = str( name )
2836 """
2837 try:
2838 # look to see if this component already exists
2839 getattr( main, name )
2840 except AttributeError:
2841 # namespace is clear, creating component
2842 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
2843 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
2844 main.componentInit( name )
2845 except Exception:
2846 main.log.exception( self.name + ": Uncaught exception!" )
2847 main.cleanup()
2848 main.exit()
2849 else:
2850 # namespace is not clear!
2851 main.log.error( name + " component already exists!" )
2852 # FIXME: Should we exit here?
2853 main.cleanup()
2854 main.exit()
2855
2856 def removeHostComponent( self, name ):
2857 """
2858 Remove host component
2859 Arguments:
2860 name - The string of the name of the component to delete.
2861 """
2862 try:
2863 # Get host component
2864 component = getattr( main, name )
2865 except AttributeError:
2866 main.log.error( "Component " + name + " does not exist." )
2867 return
2868 try:
2869 # Disconnect from component
2870 component.disconnect()
2871 # Delete component
2872 delattr( main, name )
2873 # Delete component from ComponentDictionary
2874 del( main.componentDictionary[name] )
2875 except Exception:
2876 main.log.exception( self.name + ": Uncaught exception!" )
2877 main.cleanup()
2878 main.exit()
2879
2880 def startHostCli( self, host=None ):
2881 """
2882 Use the mininet m utility to connect to the host's cli
2883 """
2884 # These are fields that can be used by scapy packets. Initialized to None
2885 self.hostIp = None
2886 self.hostMac = None
2887 try:
2888 if not host:
2889 host = self.name
2890 self.handle.sendline( self.home + "/util/m " + host )
2891 self.handle.expect( self.hostPrompt )
2892 return main.TRUE
2893 except pexpect.TIMEOUT:
2894 main.log.exception( self.name + ": Command timed out" )
2895 return main.FALSE
2896 except pexpect.EOF:
2897 main.log.exception( self.name + ": connection closed." )
2898 main.cleanup()
2899 main.exit()
2900 except Exception:
2901 main.log.exception( self.name + ": Uncaught exception!" )
2902 main.cleanup()
2903 main.exit()
2904
GlennRC956ea742015-11-05 16:14:15 -08002905 def startScapy( self, mplsPath="" ):
Jon Hall892818c2015-10-20 17:58:34 -07002906 """
2907 Start the Scapy cli
GlennRC956ea742015-11-05 16:14:15 -08002908 optional:
2909 mplsPath - The path where the MPLS class is located
2910 NOTE: This can be a relative path from the user's home dir
Jon Hall892818c2015-10-20 17:58:34 -07002911 """
GlennRC956ea742015-11-05 16:14:15 -08002912 mplsLines = ['import imp',
2913 'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format(mplsPath),
2914 'from mplsClass import MPLS',
2915 'bind_layers(Ether, MPLS, type = 0x8847)',
2916 'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
2917 'bind_layers(MPLS, IP)']
2918
Jon Hall892818c2015-10-20 17:58:34 -07002919 try:
2920 self.handle.sendline( "scapy" )
2921 self.handle.expect( self.scapyPrompt )
2922 self.handle.sendline( "conf.color_theme = NoTheme()" )
2923 self.handle.expect( self.scapyPrompt )
GlennRC956ea742015-11-05 16:14:15 -08002924 if mplsPath:
2925 main.log.info( "Adding MPLS class" )
2926 main.log.info( "MPLS class path: " + mplsPath )
2927 for line in mplsLines:
2928 main.log.info( "sending line: " + line )
2929 self.handle.sendline( line )
2930 self.handle.expect( self.scapyPrompt )
Jon Hall892818c2015-10-20 17:58:34 -07002931 return main.TRUE
2932 except pexpect.TIMEOUT:
2933 main.log.exception( self.name + ": Command timed out" )
2934 return main.FALSE
2935 except pexpect.EOF:
2936 main.log.exception( self.name + ": connection closed." )
2937 main.cleanup()
2938 main.exit()
2939 except Exception:
2940 main.log.exception( self.name + ": Uncaught exception!" )
2941 main.cleanup()
2942 main.exit()
2943
2944 def stopScapy( self ):
2945 """
2946 Exit the Scapy cli
2947 """
2948 try:
2949 self.handle.sendline( "exit()" )
2950 self.handle.expect( self.hostPrompt )
2951 return main.TRUE
2952 except pexpect.TIMEOUT:
2953 main.log.exception( self.name + ": Command timed out" )
2954 return main.FALSE
2955 except pexpect.EOF:
2956 main.log.exception( self.name + ": connection closed." )
2957 main.cleanup()
2958 main.exit()
2959 except Exception:
2960 main.log.exception( self.name + ": Uncaught exception!" )
2961 main.cleanup()
2962 main.exit()
2963
2964 def buildEther( self, **kwargs ):
2965 """
2966 Build an Ethernet frame
2967
2968 Will create a frame class with the given options. If a field is
2969 left blank it will default to the below value unless it is
2970 overwritten by the next frame.
2971 Default frame:
2972 ###[ Ethernet ]###
2973 dst= ff:ff:ff:ff:ff:ff
2974 src= 00:00:00:00:00:00
2975 type= 0x800
2976
2977 Returns main.TRUE or main.FALSE on error
2978 """
2979 try:
2980 # Set the Ethernet frame
2981 cmd = 'ether = Ether( '
2982 options = []
2983 for key, value in kwargs.iteritems():
2984 if isinstance( value, str ):
2985 value = '"' + value + '"'
2986 options.append( str( key ) + "=" + str( value ) )
2987 cmd += ", ".join( options )
2988 cmd += ' )'
2989 self.handle.sendline( cmd )
2990 self.handle.expect( self.scapyPrompt )
2991 if "Traceback" in self.handle.before:
2992 # KeyError, SyntaxError, ...
2993 main.log.error( "Error in sending command: " + self.handle.before )
2994 return main.FALSE
2995 self.handle.sendline( "packet = ether" )
2996 self.handle.expect( self.scapyPrompt )
2997 if "Traceback" in self.handle.before:
2998 # KeyError, SyntaxError, ...
2999 main.log.error( "Error in sending command: " + self.handle.before )
3000 return main.FALSE
3001 return main.TRUE
3002 except pexpect.TIMEOUT:
3003 main.log.exception( self.name + ": Command timed out" )
3004 return main.FALSE
3005 except pexpect.EOF:
3006 main.log.exception( self.name + ": connection closed." )
3007 main.cleanup()
3008 main.exit()
3009 except Exception:
3010 main.log.exception( self.name + ": Uncaught exception!" )
3011 main.cleanup()
3012 main.exit()
3013
3014 def buildIP( self, **kwargs ):
3015 """
3016 Build an IP frame
3017
3018 Will create a frame class with the given options. If a field is
3019 left blank it will default to the below value unless it is
3020 overwritten by the next frame.
3021 Default frame:
3022 ###[ IP ]###
3023 version= 4
3024 ihl= None
3025 tos= 0x0
3026 len= None
3027 id= 1
3028 flags=
3029 frag= 0
3030 ttl= 64
3031 proto= hopopt
3032 chksum= None
3033 src= 127.0.0.1
3034 dst= 127.0.0.1
3035 \options\
3036
3037 Returns main.TRUE or main.FALSE on error
3038 """
3039 try:
3040 # Set the IP frame
3041 cmd = 'ip = IP( '
3042 options = []
3043 for key, value in kwargs.iteritems():
3044 if isinstance( value, str ):
3045 value = '"' + value + '"'
3046 options.append( str( key ) + "=" + str( value ) )
3047 cmd += ", ".join( options )
3048 cmd += ' )'
3049 self.handle.sendline( cmd )
3050 self.handle.expect( self.scapyPrompt )
3051 if "Traceback" in self.handle.before:
3052 # KeyError, SyntaxError, ...
3053 main.log.error( "Error in sending command: " + self.handle.before )
3054 return main.FALSE
3055 self.handle.sendline( "packet = ether/ip" )
3056 self.handle.expect( self.scapyPrompt )
3057 if "Traceback" in self.handle.before:
3058 # KeyError, SyntaxError, ...
3059 main.log.error( "Error in sending command: " + self.handle.before )
3060 return main.FALSE
3061 return main.TRUE
3062 except pexpect.TIMEOUT:
3063 main.log.exception( self.name + ": Command timed out" )
3064 return main.FALSE
3065 except pexpect.EOF:
3066 main.log.exception( self.name + ": connection closed." )
3067 main.cleanup()
3068 main.exit()
3069 except Exception:
3070 main.log.exception( self.name + ": Uncaught exception!" )
3071 main.cleanup()
3072 main.exit()
3073
3074 def buildIPv6( self, **kwargs ):
3075 """
3076 Build an IPv6 frame
3077
3078 Will create a frame class with the given options. If a field is
3079 left blank it will default to the below value unless it is
3080 overwritten by the next frame.
3081 Default frame:
3082 ###[ IPv6 ]###
3083 version= 6
3084 tc= 0
3085 fl= 0
3086 plen= None
3087 nh= No Next Header
3088 hlim= 64
3089 src= ::1
3090 dst= ::1
3091
3092 Returns main.TRUE or main.FALSE on error
3093 """
3094 try:
3095 # Set the IPv6 frame
3096 cmd = 'ipv6 = IPv6( '
3097 options = []
3098 for key, value in kwargs.iteritems():
3099 if isinstance( value, str ):
3100 value = '"' + value + '"'
3101 options.append( str( key ) + "=" + str( value ) )
3102 cmd += ", ".join( options )
3103 cmd += ' )'
3104 self.handle.sendline( cmd )
3105 self.handle.expect( self.scapyPrompt )
3106 if "Traceback" in self.handle.before:
3107 # KeyError, SyntaxError, ...
3108 main.log.error( "Error in sending command: " + self.handle.before )
3109 return main.FALSE
3110 self.handle.sendline( "packet = ether/ipv6" )
3111 self.handle.expect( self.scapyPrompt )
3112 if "Traceback" in self.handle.before:
3113 # KeyError, SyntaxError, ...
3114 main.log.error( "Error in sending command: " + self.handle.before )
3115 return main.FALSE
3116 return main.TRUE
3117 except pexpect.TIMEOUT:
3118 main.log.exception( self.name + ": Command timed out" )
3119 return main.FALSE
3120 except pexpect.EOF:
3121 main.log.exception( self.name + ": connection closed." )
3122 main.cleanup()
3123 main.exit()
3124 except Exception:
3125 main.log.exception( self.name + ": Uncaught exception!" )
3126 main.cleanup()
3127 main.exit()
3128
3129 def buildTCP( self, ipVersion=4, **kwargs ):
3130 """
3131 Build an TCP frame
3132
3133 Will create a frame class with the given options. If a field is
3134 left blank it will default to the below value unless it is
3135 overwritten by the next frame.
3136
GlennRC956ea742015-11-05 16:14:15 -08003137 NOTE: Some arguments require quotes around them. It's up to you to
3138 know which ones and to add them yourself. Arguments with an asterisk
3139 do not need quotes.
3140
Jon Hall892818c2015-10-20 17:58:34 -07003141 Options:
3142 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
3143 frame to use to encapsulate into
3144 Default frame:
3145 ###[ TCP ]###
GlennRC956ea742015-11-05 16:14:15 -08003146 sport= ftp_data *
3147 dport= http *
Jon Hall892818c2015-10-20 17:58:34 -07003148 seq= 0
3149 ack= 0
3150 dataofs= None
3151 reserved= 0
3152 flags= S
3153 window= 8192
3154 chksum= None
3155 urgptr= 0
3156 options= {}
3157
3158 Returns main.TRUE or main.FALSE on error
3159 """
3160 try:
3161 # Set the TCP frame
3162 cmd = 'tcp = TCP( '
3163 options = []
3164 for key, value in kwargs.iteritems():
Jon Hall892818c2015-10-20 17:58:34 -07003165 options.append( str( key ) + "=" + str( value ) )
3166 cmd += ", ".join( options )
3167 cmd += ' )'
3168 self.handle.sendline( cmd )
3169 self.handle.expect( self.scapyPrompt )
3170 if "Traceback" in self.handle.before:
3171 # KeyError, SyntaxError, ...
3172 main.log.error( "Error in sending command: " + self.handle.before )
3173 return main.FALSE
3174 if str( ipVersion ) is '4':
3175 self.handle.sendline( "packet = ether/ip/tcp" )
3176 elif str( ipVersion ) is '6':
3177 self.handle.sendline( "packet = ether/ipv6/tcp" )
3178 else:
3179 main.log.error( "Unrecognized option for ipVersion, given " +
3180 repr( ipVersion ) )
3181 return main.FALSE
3182 self.handle.expect( self.scapyPrompt )
3183 if "Traceback" in self.handle.before:
3184 # KeyError, SyntaxError, ...
3185 main.log.error( "Error in sending command: " + self.handle.before )
3186 return main.FALSE
3187 return main.TRUE
3188 except pexpect.TIMEOUT:
3189 main.log.exception( self.name + ": Command timed out" )
3190 return main.FALSE
3191 except pexpect.EOF:
3192 main.log.exception( self.name + ": connection closed." )
3193 main.cleanup()
3194 main.exit()
3195 except Exception:
3196 main.log.exception( self.name + ": Uncaught exception!" )
3197 main.cleanup()
3198 main.exit()
3199
3200 def buildUDP( self, ipVersion=4, **kwargs ):
3201 """
3202 Build an UDP frame
3203
3204 Will create a frame class with the given options. If a field is
3205 left blank it will default to the below value unless it is
3206 overwritten by the next frame.
3207
GlennRC956ea742015-11-05 16:14:15 -08003208 NOTE: Some arguments require quotes around them. It's up to you to
3209 know which ones and to add them yourself. Arguments with an asterisk
3210 do not need quotes.
3211
Jon Hall892818c2015-10-20 17:58:34 -07003212 Options:
3213 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
3214 frame to use to encapsulate into
3215 Default frame:
3216 ###[ UDP ]###
GlennRC956ea742015-11-05 16:14:15 -08003217 sport= domain *
3218 dport= domain *
Jon Hall892818c2015-10-20 17:58:34 -07003219 len= None
3220 chksum= None
3221
3222 Returns main.TRUE or main.FALSE on error
3223 """
3224 try:
3225 # Set the UDP frame
3226 cmd = 'udp = UDP( '
3227 options = []
3228 for key, value in kwargs.iteritems():
Jon Hall892818c2015-10-20 17:58:34 -07003229 options.append( str( key ) + "=" + str( value ) )
3230 cmd += ", ".join( options )
3231 cmd += ' )'
3232 self.handle.sendline( cmd )
3233 self.handle.expect( self.scapyPrompt )
3234 if "Traceback" in self.handle.before:
3235 # KeyError, SyntaxError, ...
3236 main.log.error( "Error in sending command: " + self.handle.before )
3237 return main.FALSE
3238 if str( ipVersion ) is '4':
3239 self.handle.sendline( "packet = ether/ip/udp" )
3240 elif str( ipVersion ) is '6':
3241 self.handle.sendline( "packet = ether/ipv6/udp" )
3242 else:
3243 main.log.error( "Unrecognized option for ipVersion, given " +
3244 repr( ipVersion ) )
3245 return main.FALSE
3246 self.handle.expect( self.scapyPrompt )
3247 if "Traceback" in self.handle.before:
3248 # KeyError, SyntaxError, ...
3249 main.log.error( "Error in sending command: " + self.handle.before )
3250 return main.FALSE
3251 return main.TRUE
3252 except pexpect.TIMEOUT:
3253 main.log.exception( self.name + ": Command timed out" )
3254 return main.FALSE
3255 except pexpect.EOF:
3256 main.log.exception( self.name + ": connection closed." )
3257 main.cleanup()
3258 main.exit()
3259 except Exception:
3260 main.log.exception( self.name + ": Uncaught exception!" )
3261 main.cleanup()
3262 main.exit()
3263
3264 def buildICMP( self, **kwargs ):
3265 """
3266 Build an ICMP frame
3267
3268 Will create a frame class with the given options. If a field is
3269 left blank it will default to the below value unless it is
3270 overwritten by the next frame.
3271 Default frame:
3272 ###[ ICMP ]###
3273 type= echo-request
3274 code= 0
3275 chksum= None
3276 id= 0x0
3277 seq= 0x0
3278
3279 Returns main.TRUE or main.FALSE on error
3280 """
3281 try:
3282 # Set the ICMP frame
3283 cmd = 'icmp = ICMP( '
3284 options = []
3285 for key, value in kwargs.iteritems():
3286 if isinstance( value, str ):
3287 value = '"' + value + '"'
3288 options.append( str( key ) + "=" + str( value ) )
3289 cmd += ", ".join( options )
3290 cmd += ' )'
3291 self.handle.sendline( cmd )
3292 self.handle.expect( self.scapyPrompt )
3293 if "Traceback" in self.handle.before:
3294 # KeyError, SyntaxError, ...
3295 main.log.error( "Error in sending command: " + self.handle.before )
3296 return main.FALSE
3297 self.handle.sendline( "packet = ether/ip/icmp" )
3298 self.handle.expect( self.scapyPrompt )
3299 if "Traceback" in self.handle.before:
3300 # KeyError, SyntaxError, ...
3301 main.log.error( "Error in sending command: " + self.handle.before )
3302 return main.FALSE
3303 return main.TRUE
3304 except pexpect.TIMEOUT:
3305 main.log.exception( self.name + ": Command timed out" )
3306 return main.FALSE
3307 except pexpect.EOF:
3308 main.log.exception( self.name + ": connection closed." )
3309 main.cleanup()
3310 main.exit()
3311 except Exception:
3312 main.log.exception( self.name + ": Uncaught exception!" )
3313 main.cleanup()
3314 main.exit()
3315
GlennRC073e8bc2015-10-27 17:11:28 -07003316 def sendPacket( self, iface=None, packet=None, timeout=1 ):
Jon Hall892818c2015-10-20 17:58:34 -07003317 """
3318 Send a packet with either the given scapy packet command, or use the
3319 packet saved in the variable 'packet'.
3320
3321 Examples of a valid string for packet:
3322
3323 Simple IP packet
3324 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
3325
3326 A Ping with two vlan tags
3327 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
3328 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
3329
3330 Returns main.TRUE or main.FALSE on error
3331 """
3332 try:
3333 # TODO: add all params, or use kwargs
3334 sendCmd = 'srp( '
3335 if packet:
3336 sendCmd += packet
3337 else:
3338 sendCmd += "packet"
GlennRC073e8bc2015-10-27 17:11:28 -07003339 if iface:
3340 sendCmd += ", iface='{}'".format( iface )
3341
Jon Hall892818c2015-10-20 17:58:34 -07003342 sendCmd += ', timeout=' + str( timeout ) + ')'
3343 self.handle.sendline( sendCmd )
3344 self.handle.expect( self.scapyPrompt )
3345 if "Traceback" in self.handle.before:
3346 # KeyError, SyntaxError, ...
3347 main.log.error( "Error in sending command: " + self.handle.before )
3348 return main.FALSE
3349 # TODO: Check # of packets sent?
3350 return main.TRUE
3351 except pexpect.TIMEOUT:
3352 main.log.exception( self.name + ": Command timed out" )
3353 return main.FALSE
3354 except pexpect.EOF:
3355 main.log.exception( self.name + ": connection closed." )
3356 main.cleanup()
3357 main.exit()
3358 except Exception:
3359 main.log.exception( self.name + ": Uncaught exception!" )
3360 main.cleanup()
3361 main.exit()
3362
3363 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
3364 """
3365 Listen for packets using the given filters
3366
3367 Options:
3368 ifaceName - the name of the interface to listen on. If none is given,
3369 defaults to <host name>-eth0
3370 pktFilter - A string in Berkeley Packet Filter (BPF) format which
3371 specifies which packets to sniff
3372 sniffCount - The number of matching packets to capture before returning
3373
3374 Returns main.TRUE or main.FALSE on error
3375 """
3376 try:
3377 # TODO: add all params, or use kwargs
3378 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
3379 # Set interface
3380 self.handle.sendline( ' conf.iface = "' + ifaceName + '"' )
3381 self.handle.expect( self.scapyPrompt )
3382 cmd = 'pkt = sniff(count = ' + str( sniffCount ) +\
3383 ', filter = "' + str( pktFilter ) + '")'
3384 self.handle.sendline( cmd )
3385 self.handle.expect( '"\)\r\n' )
3386 # TODO: parse this?
3387 return main.TRUE
3388 except pexpect.TIMEOUT:
3389 main.log.exception( self.name + ": Command timed out" )
3390 return main.FALSE
3391 except pexpect.EOF:
3392 main.log.exception( self.name + ": connection closed." )
3393 main.cleanup()
3394 main.exit()
3395 except Exception:
3396 main.log.exception( self.name + ": Uncaught exception!" )
3397 main.cleanup()
3398 main.exit()
3399
3400 def checkFilter( self ):
3401 """
3402 Check that a filter returned and returns the reponse
3403 """
3404 try:
3405 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ] )
3406 if i == 0:
3407 return main.TRUE
3408 else:
3409 return main.FALSE
3410 except pexpect.EOF:
3411 main.log.exception( self.name + ": connection closed." )
3412 main.cleanup()
3413 main.exit()
3414 except Exception:
3415 main.log.exception( self.name + ": Uncaught exception!" )
3416 main.cleanup()
3417 main.exit()
3418
3419 def killFilter( self ):
3420 """
3421 Kill a scapy filter
3422 """
3423 try:
3424 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
3425 self.handle.expect( self.scapyPrompt )
3426 return self.handle.before
3427 except pexpect.TIMEOUT:
3428 main.log.exception( self.name + ": Command timed out" )
3429 return None
3430 except pexpect.EOF:
3431 main.log.exception( self.name + ": connection closed." )
3432 main.cleanup()
3433 main.exit()
3434 except Exception:
3435 main.log.exception( self.name + ": Uncaught exception!" )
3436 main.cleanup()
3437 main.exit()
3438
3439 def readPackets( self ):
3440 """
3441 Read all the packets captured by the previous filter
3442 """
3443 try:
3444 self.handle.sendline( "for p in pkt: p \n")
3445 self.handle.expect( "for p in pkt: p \r\n... \r\n" )
3446 self.handle.expect( self.scapyPrompt )
3447 except pexpect.TIMEOUT:
3448 main.log.exception( self.name + ": Command timed out" )
3449 return None
3450 except pexpect.EOF:
3451 main.log.exception( self.name + ": connection closed." )
3452 main.cleanup()
3453 main.exit()
3454 except Exception:
3455 main.log.exception( self.name + ": Uncaught exception!" )
3456 main.cleanup()
3457 main.exit()
3458 return self.handle.before
3459
3460 def updateSelf( self ):
3461 """
3462 Updates local MAC and IP fields
3463 """
3464 self.hostMac = self.getMac()
3465 self.hostIp = self.getIp()
3466
3467 def getMac( self, ifaceName=None ):
3468 """
3469 Save host's MAC address
3470 """
3471 try:
3472 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
3473 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
3474 self.handle.sendline( cmd )
3475 self.handle.expect( self.scapyPrompt )
3476 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
3477 match = re.search( pattern, self.handle.before )
3478 if match:
3479 return match.group()
3480 else:
3481 # the command will have an exception if iface doesn't exist
3482 return None
3483 except pexpect.TIMEOUT:
3484 main.log.exception( self.name + ": Command timed out" )
3485 return None
3486 except pexpect.EOF:
3487 main.log.exception( self.name + ": connection closed." )
3488 main.cleanup()
3489 main.exit()
3490 except Exception:
3491 main.log.exception( self.name + ": Uncaught exception!" )
3492 main.cleanup()
3493 main.exit()
3494
3495 def getIp( self, ifaceName=None ):
3496 """
3497 Save host's IP address
3498 """
3499 try:
3500 ifaceName = ifaceName if ifaceName else self.name + "-eth0"
3501 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
3502 self.handle.sendline( cmd )
3503 self.handle.expect( self.scapyPrompt )
3504
3505 pattern = r'(((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9]))'
3506 match = re.search( pattern, self.handle.before )
3507 if match:
3508 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
3509 return match.group()
3510 else:
3511 return None
3512 except pexpect.TIMEOUT:
3513 main.log.exception( self.name + ": Command timed out" )
3514 return None
3515 except pexpect.EOF:
3516 main.log.exception( self.name + ": connection closed." )
3517 main.cleanup()
3518 main.exit()
3519 except Exception:
3520 main.log.exception( self.name + ": Uncaught exception!" )
3521 main.cleanup()
3522 main.exit()
3523
adminbae64d82013-08-01 10:50:15 -07003524if __name__ != "__main__":
kelvin-onlab50907142015-04-01 13:37:45 -07003525 sys.modules[ __name__ ] = MininetCliDriver()