blob: 21eb9592011f9290a4f5e6ce5e8f08e6765bed82 [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
360 self.handle.sendline( "\x03" )
361 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
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700372 self.handle.sendline( "\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 """
1238 Bring link( s ) between two nodes up or down"""
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001239 args = utilities.parse_args( [ "END1", "END2", "OPTION" ], **linkargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001240 end1 = args[ "END1" ] if args[ "END1" ] is not None else ""
1241 end2 = args[ "END2" ] if args[ "END2" ] is not None else ""
1242 option = args[ "OPTION" ] if args[ "OPTION" ] is not None else ""
1243 main.log.info(
1244 "Bring link between '" +
1245 end1 +
1246 "' and '" +
1247 end2 +
1248 "' '" +
1249 option +
1250 "'" )
1251 command = "link " + \
1252 str( end1 ) + " " + str( end2 ) + " " + str( option )
Jon Hall6094a362014-04-11 14:46:56 -07001253 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001254 self.handle.sendline( command )
1255 self.handle.expect( "mininet>" )
Jon Hallfbc828e2015-01-06 17:30:19 -08001256 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001257 main.log.error( self.name + ": EOF exception found" )
1258 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001259 main.cleanup()
1260 main.exit()
adminbae64d82013-08-01 10:50:15 -07001261 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -08001262
pingping-lin8244a3b2015-09-16 13:36:56 -07001263 def switch( self, **switchargs ):
1264 """
1265 start/stop a switch
1266 """
1267 args = utilities.parse_args( [ "SW", "OPTION" ], **switchargs )
1268 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1269 option = args[ "OPTION" ] if args[ "OPTION" ] is not None else ""
1270 command = "switch " + str( sw ) + " " + str( option )
1271 main.log.info( command )
1272 try:
1273 self.handle.sendline( command )
1274 self.handle.expect( "mininet>" )
1275 except pexpect.TIMEOUT:
1276 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1277 main.cleanup()
1278 main.exit()
1279 except pexpect.EOF:
1280 main.log.error( self.name + ": EOF exception found" )
1281 main.log.error( self.name + ": " + self.handle.before )
1282 main.cleanup()
1283 main.exit()
1284 return main.TRUE
1285
pingping-lin5bb663b2015-09-24 11:47:50 -07001286 def node( self, nodeName, commandStr ):
1287 """
1288 Carry out a command line on a given node
1289 @parm:
1290 nodeName: the node name in Mininet testbed
1291 commandStr: the command line will be carried out on the node
1292 Example: main.Mininet.node( nodeName="h1", commandStr="ls" )
1293 """
1294 command = str( nodeName ) + " " + str( commandStr )
1295 main.log.info( command )
1296
1297 try:
1298 response = self.execute( cmd = command, prompt = "mininet>" )
1299 if re.search( "Unknown command", response ):
1300 main.log.warn( response )
1301 return main.FALSE
1302 except pexpect.TIMEOUT:
1303 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1304 main.cleanup()
1305 main.exit()
1306 except pexpect.EOF:
1307 main.log.error( self.name + ": EOF exception found" )
1308 main.log.error( self.name + ": " + self.handle.before )
1309 main.cleanup()
1310 main.exit()
1311 main.log.info( " response is :" )
1312 main.log.info( response )
1313 return response
1314
Jon Hall7eb38402015-01-08 17:19:54 -08001315 def yank( self, **yankargs ):
1316 """
1317 yank a mininet switch interface to a host"""
1318 main.log.info( 'Yank the switch interface attached to a host' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001319 args = utilities.parse_args( [ "SW", "INTF" ], **yankargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001320 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1321 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
1322 command = "py " + str( sw ) + '.detach("' + str(intf) + '")'
Jon Hall6094a362014-04-11 14:46:56 -07001323 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001324 response = self.execute(
1325 cmd=command,
1326 prompt="mininet>",
1327 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001328 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001329 main.log.error( self.name + ": EOF exception found" )
1330 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001331 main.cleanup()
1332 main.exit()
adminaeedddd2013-08-02 15:14:15 -07001333 return main.TRUE
1334
Jon Hall7eb38402015-01-08 17:19:54 -08001335 def plug( self, **plugargs ):
1336 """
1337 plug the yanked mininet switch interface to a switch"""
1338 main.log.info( 'Plug the switch interface attached to a switch' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001339 args = utilities.parse_args( [ "SW", "INTF" ], **plugargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001340 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1341 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
1342 command = "py " + str( sw ) + '.attach("' + str(intf) + '")'
Jon Hall6094a362014-04-11 14:46:56 -07001343 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001344 response = self.execute(
1345 cmd=command,
1346 prompt="mininet>",
1347 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001348 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001349 main.log.error( self.name + ": EOF exception found" )
1350 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001351 main.cleanup()
1352 main.exit()
adminbae64d82013-08-01 10:50:15 -07001353 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -08001354
Jon Hall7eb38402015-01-08 17:19:54 -08001355 def dpctl( self, **dpctlargs ):
1356 """
1357 Run dpctl command on all switches."""
1358 main.log.info( 'Run dpctl command on all switches' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001359 args = utilities.parse_args( [ "CMD", "ARGS" ], **dpctlargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001360 cmd = args[ "CMD" ] if args[ "CMD" ] is not None else ""
1361 cmdargs = args[ "ARGS" ] if args[ "ARGS" ] is not None else ""
1362 command = "dpctl " + cmd + " " + str( cmdargs )
1363 try:
1364 response = self.execute(
1365 cmd=command,
1366 prompt="mininet>",
1367 timeout=10 )
1368 except pexpect.EOF:
1369 main.log.error( self.name + ": EOF exception found" )
1370 main.log.error( self.name + ": " + self.handle.before )
1371 main.cleanup()
1372 main.exit()
1373 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -08001374
kelvin-onlabd3b64892015-01-20 13:26:24 -08001375 def getVersion( self ):
Jon Halld80cc142015-07-06 13:36:05 -07001376 # FIXME: What uses this? This should be refactored to get
Jon Hallff6b4b22015-02-23 09:25:15 -08001377 # version from MN and not some other file
kelvin-onlabd3b64892015-01-20 13:26:24 -08001378 fileInput = path + '/lib/Mininet/INSTALL'
1379 version = super( Mininet, self ).getVersion()
adminbae64d82013-08-01 10:50:15 -07001380 pattern = 'Mininet\s\w\.\w\.\w\w*'
kelvin-onlabd3b64892015-01-20 13:26:24 -08001381 for line in open( fileInput, 'r' ).readlines():
Jon Hall7eb38402015-01-08 17:19:54 -08001382 result = re.match( pattern, line )
adminbae64d82013-08-01 10:50:15 -07001383 if result:
Jon Hall7eb38402015-01-08 17:19:54 -08001384 version = result.group( 0 )
Jon Hallec3c21e2014-11-10 22:22:37 -05001385 return version
adminbae64d82013-08-01 10:50:15 -07001386
kelvin-onlabd3b64892015-01-20 13:26:24 -08001387 def getSwController( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001388 """
Jon Hallec3c21e2014-11-10 22:22:37 -05001389 Parameters:
1390 sw: The name of an OVS switch. Example "s1"
1391 Return:
Jon Hall7eb38402015-01-08 17:19:54 -08001392 The output of the command from the mininet cli
1393 or main.FALSE on timeout"""
1394 command = "sh ovs-vsctl get-controller " + str( sw )
admin2a9548d2014-06-17 14:08:07 -07001395 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001396 response = self.execute(
1397 cmd=command,
1398 prompt="mininet>",
1399 timeout=10 )
admin2a9548d2014-06-17 14:08:07 -07001400 if response:
Jon Hallec3c21e2014-11-10 22:22:37 -05001401 return response
admin2a9548d2014-06-17 14:08:07 -07001402 else:
1403 return main.FALSE
1404 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001405 main.log.error( self.name + ": EOF exception found" )
1406 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07001407 main.cleanup()
1408 main.exit()
adminbae64d82013-08-01 10:50:15 -07001409
Charles Chan029be652015-08-24 01:46:10 +08001410 def assignSwController( self, sw, ip, port="6653", ptcp="" ):
Jon Hall7eb38402015-01-08 17:19:54 -08001411 """
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001412 Description:
1413 Assign switches to the controllers ( for ovs use only )
1414 Required:
1415 sw - Name of the switch. This can be a list or a string.
1416 ip - Ip addresses of controllers. This can be a list or a string.
1417 Optional:
Charles Chan029be652015-08-24 01:46:10 +08001418 port - ONOS use port 6653, if no list of ports is passed, then
1419 the all the controller will use 6653 as their port number
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001420 ptcp - ptcp number, This can be a string or a list that has
1421 the same length as switch. This is optional and not required
1422 when using ovs switches.
1423 NOTE: If switches and ptcp are given in a list type they should have the
1424 same length and should be in the same order, Eg. sw=[ 's1' ... n ]
1425 ptcp=[ '6637' ... n ], s1 has ptcp number 6637 and so on.
Jon Hallf89c8552014-04-02 13:14:06 -07001426
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001427 Return:
1428 Returns main.TRUE if mininet correctly assigned switches to
1429 controllers, otherwise it will return main.FALSE or an appropriate
1430 exception(s)
1431 """
1432 assignResult = main.TRUE
1433 # Initial ovs command
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001434 commandList = []
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001435 command = "sh ovs-vsctl set-controller "
1436 onosIp = ""
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001437 try:
1438 if isinstance( ip, types.StringType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001439 onosIp = "tcp:" + str( ip ) + ":"
kelvin-onlab5c2df432015-06-11 17:29:56 -07001440 if isinstance( port, types.StringType ) or \
1441 isinstance( port, types.IntType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001442 onosIp += str( port )
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001443 elif isinstance( port, types.ListType ):
1444 main.log.error( self.name + ": Only one controller " +
1445 "assigned and a list of ports has" +
1446 " been passed" )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001447 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001448 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001449 main.log.error( self.name + ": Invalid controller port " +
1450 "number. Please specify correct " +
1451 "controller port" )
1452 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001453
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001454 elif isinstance( ip, types.ListType ):
kelvin-onlab5c2df432015-06-11 17:29:56 -07001455 if isinstance( port, types.StringType ) or \
1456 isinstance( port, types.IntType ):
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001457 for ipAddress in ip:
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001458 onosIp += "tcp:" + str( ipAddress ) + ":" + \
1459 str( port ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001460 elif isinstance( port, types.ListType ):
1461 if ( len( ip ) != len( port ) ):
1462 main.log.error( self.name + ": Port list = " +
1463 str( len( port ) ) +
1464 "should be the same as controller" +
1465 " ip list = " + str( len( ip ) ) )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001466 return main.FALSE
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001467 else:
1468 onosIp = ""
1469 for ipAddress, portNum in zip( ip, port ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001470 onosIp += "tcp:" + str( ipAddress ) + ":" + \
1471 str( portNum ) + " "
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001472 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001473 main.log.error( self.name + ": Invalid controller port " +
1474 "number. Please specify correct " +
1475 "controller port" )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001476 return main.FALSE
kelvin-onlabe5edb9e2015-06-12 09:38:47 -07001477 else:
1478 main.log.error( self.name + ": Invalid ip address" )
1479 return main.FALSE
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001480
1481 if isinstance( sw, types.StringType ):
1482 command += sw + " "
1483 if ptcp:
1484 if isinstance( ptcp, types.StringType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001485 command += "ptcp:" + str( ptcp ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001486 elif isinstance( ptcp, types.ListType ):
1487 main.log.error( self.name + ": Only one switch is " +
1488 "being set and multiple PTCP is " +
1489 "being passed " )
1490 else:
1491 main.log.error( self.name + ": Invalid PTCP" )
1492 ptcp = ""
1493 command += onosIp
1494 commandList.append( command )
1495
1496 elif isinstance( sw, types.ListType ):
1497 if ptcp:
1498 if isinstance( ptcp, types.ListType ):
1499 if len( ptcp ) != len( sw ):
1500 main.log.error( self.name + ": PTCP length = " +
1501 str( len( ptcp ) ) +
1502 " is not the same as switch" +
1503 " length = " +
1504 str( len( sw ) ) )
1505 return main.FALSE
1506 else:
1507 for switch, ptcpNum in zip( sw, ptcp ):
1508 tempCmd = "sh ovs-vsctl set-controller "
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001509 tempCmd += switch + " ptcp:" + \
Jon Halld80cc142015-07-06 13:36:05 -07001510 str( ptcpNum ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001511 tempCmd += onosIp
1512 commandList.append( tempCmd )
1513 else:
1514 main.log.error( self.name + ": Invalid PTCP" )
1515 return main.FALSE
1516 else:
1517 for switch in sw:
1518 tempCmd = "sh ovs-vsctl set-controller "
1519 tempCmd += switch + " " + onosIp
1520 commandList.append( tempCmd )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001521 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001522 main.log.error( self.name + ": Invalid switch type " )
1523 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001524
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001525 for cmd in commandList:
1526 try:
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001527 self.execute( cmd=cmd, prompt="mininet>", timeout=5 )
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001528 except pexpect.TIMEOUT:
1529 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1530 return main.FALSE
1531 except pexpect.EOF:
1532 main.log.error( self.name + ": EOF exception found" )
1533 main.log.error( self.name + ": " + self.handle.before )
1534 main.cleanup()
1535 main.exit()
1536 return main.TRUE
1537 except Exception:
1538 main.log.exception( self.name + ": Uncaught exception!" )
1539 main.cleanup()
1540 main.exit()
adminbae64d82013-08-01 10:50:15 -07001541
kelvin-onlabd3b64892015-01-20 13:26:24 -08001542 def deleteSwController( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001543 """
1544 Removes the controller target from sw"""
1545 command = "sh ovs-vsctl del-controller " + str( sw )
Jon Hall0819fd92014-05-23 12:08:13 -07001546 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001547 response = self.execute(
1548 cmd=command,
1549 prompt="mininet>",
1550 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001551 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001552 main.log.error( self.name + ": EOF exception found" )
1553 main.log.error( self.name + ": " + self.handle.before )
Jon Hall0819fd92014-05-23 12:08:13 -07001554 main.cleanup()
1555 main.exit()
1556 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001557 main.log.info( response )
Jon Hall0819fd92014-05-23 12:08:13 -07001558
kelvin-onlabd3b64892015-01-20 13:26:24 -08001559 def addSwitch( self, sw, **kwargs ):
Jon Hall7eb38402015-01-08 17:19:54 -08001560 """
Jon Hallb1290e82014-11-18 16:17:48 -05001561 adds a switch to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001562 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001563 dynamic_topo branch
Jon Hallb1290e82014-11-18 16:17:48 -05001564 NOTE: cannot currently specify what type of switch
1565 required params:
Jon Hallefbd9792015-03-05 16:11:36 -08001566 sw = name of the new switch as a string
1567 optional keywords:
Jon Hallb1290e82014-11-18 16:17:48 -05001568 dpid = "dpid"
Jon Hallefbd9792015-03-05 16:11:36 -08001569 returns: main.FALSE on an error, else main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001570 """
1571 dpid = kwargs.get( 'dpid', '' )
Jon Hallffb386d2014-11-21 13:43:38 -08001572 command = "addswitch " + str( sw ) + " " + str( dpid )
Jon Hallb1290e82014-11-18 16:17:48 -05001573 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001574 response = self.execute(
1575 cmd=command,
1576 prompt="mininet>",
1577 timeout=10 )
1578 if re.search( "already exists!", response ):
1579 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001580 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001581 elif re.search( "Error", response ):
1582 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001583 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001584 elif re.search( "usage:", response ):
1585 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001586 return main.FALSE
1587 else:
1588 return main.TRUE
1589 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001590 main.log.error( self.name + ": EOF exception found" )
Jon Halld80cc142015-07-06 13:36:05 -07001591 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001592 main.cleanup()
1593 main.exit()
1594
kelvin-onlabd3b64892015-01-20 13:26:24 -08001595 def delSwitch( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001596 """
Jon Hallbe6dfc42015-01-12 17:37:25 -08001597 delete a switch from the mininet topology
1598 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001599 dynamic_topo branch
Jon Hallbe6dfc42015-01-12 17:37:25 -08001600 required params:
Jon Hallefbd9792015-03-05 16:11:36 -08001601 sw = name of the switch as a string
1602 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001603 command = "delswitch " + str( sw )
Jon Hallb1290e82014-11-18 16:17:48 -05001604 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001605 response = self.execute(
1606 cmd=command,
1607 prompt="mininet>",
1608 timeout=10 )
1609 if re.search( "no switch named", response ):
1610 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001611 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001612 elif re.search( "Error", response ):
1613 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001614 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001615 elif re.search( "usage:", response ):
1616 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001617 return main.FALSE
1618 else:
1619 return main.TRUE
1620 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001621 main.log.error( self.name + ": EOF exception found" )
1622 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001623 main.cleanup()
1624 main.exit()
1625
kelvin-onlabd3b64892015-01-20 13:26:24 -08001626 def addLink( self, node1, node2 ):
Jon Hall7eb38402015-01-08 17:19:54 -08001627 """
1628 add a link to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001629 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001630 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001631 NOTE: cannot currently specify what type of link
1632 required params:
1633 node1 = the string node name of the first endpoint of the link
1634 node2 = the string node name of the second endpoint of the link
Jon Hallefbd9792015-03-05 16:11:36 -08001635 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001636 command = "addlink " + str( node1 ) + " " + str( node2 )
Jon Hallb1290e82014-11-18 16:17:48 -05001637 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001638 response = self.execute(
1639 cmd=command,
1640 prompt="mininet>",
1641 timeout=10 )
1642 if re.search( "doesnt exist!", response ):
1643 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001644 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001645 elif re.search( "Error", response ):
1646 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001647 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001648 elif re.search( "usage:", response ):
1649 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001650 return main.FALSE
1651 else:
1652 return main.TRUE
1653 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001654 main.log.error( self.name + ": EOF exception found" )
1655 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001656 main.cleanup()
1657 main.exit()
1658
kelvin-onlabd3b64892015-01-20 13:26:24 -08001659 def delLink( self, node1, node2 ):
Jon Hall7eb38402015-01-08 17:19:54 -08001660 """
1661 delete a link from the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001662 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001663 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001664 required params:
1665 node1 = the string node name of the first endpoint of the link
1666 node2 = the string node name of the second endpoint of the link
Jon Hallefbd9792015-03-05 16:11:36 -08001667 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001668 command = "dellink " + str( node1 ) + " " + str( node2 )
Jon Hallb1290e82014-11-18 16:17:48 -05001669 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001670 response = self.execute(
1671 cmd=command,
1672 prompt="mininet>",
1673 timeout=10 )
1674 if re.search( "no node named", response ):
1675 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001676 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001677 elif re.search( "Error", response ):
1678 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001679 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001680 elif re.search( "usage:", response ):
1681 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001682 return main.FALSE
1683 else:
1684 return main.TRUE
1685 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001686 main.log.error( self.name + ": EOF exception found" )
1687 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001688 main.cleanup()
1689 main.exit()
1690
kelvin-onlabd3b64892015-01-20 13:26:24 -08001691 def addHost( self, hostname, **kwargs ):
Jon Hall7eb38402015-01-08 17:19:54 -08001692 """
Jon Hallb1290e82014-11-18 16:17:48 -05001693 Add a host to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001694 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001695 dynamic_topo branch
Jon Hallb1290e82014-11-18 16:17:48 -05001696 NOTE: cannot currently specify what type of host
1697 required params:
1698 hostname = the string hostname
1699 optional key-value params
1700 switch = "switch name"
Jon Hallefbd9792015-03-05 16:11:36 -08001701 returns: main.FALSE on an error, else main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001702 """
1703 switch = kwargs.get( 'switch', '' )
Jon Hallffb386d2014-11-21 13:43:38 -08001704 command = "addhost " + str( hostname ) + " " + str( switch )
Jon Hallb1290e82014-11-18 16:17:48 -05001705 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001706 response = self.execute(
1707 cmd=command,
1708 prompt="mininet>",
1709 timeout=10 )
1710 if re.search( "already exists!", response ):
1711 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001712 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001713 elif re.search( "doesnt exists!", response ):
1714 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001715 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001716 elif re.search( "Error", 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( "usage:", response ):
1720 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001721 return main.FALSE
1722 else:
1723 return main.TRUE
1724 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001725 main.log.error( self.name + ": EOF exception found" )
1726 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001727 main.cleanup()
1728 main.exit()
1729
kelvin-onlabd3b64892015-01-20 13:26:24 -08001730 def delHost( self, hostname ):
Jon Hall7eb38402015-01-08 17:19:54 -08001731 """
1732 delete a host from the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001733 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001734 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001735 NOTE: this uses a custom mn function
1736 required params:
1737 hostname = the string hostname
Jon Hallefbd9792015-03-05 16:11:36 -08001738 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001739 command = "delhost " + str( hostname )
Jon Hallb1290e82014-11-18 16:17:48 -05001740 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001741 response = self.execute(
1742 cmd=command,
1743 prompt="mininet>",
1744 timeout=10 )
1745 if re.search( "no host named", response ):
1746 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001747 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001748 elif re.search( "Error", response ):
1749 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001750 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001751 elif re.search( "usage:", response ):
1752 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001753 return main.FALSE
1754 else:
1755 return main.TRUE
1756 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001757 main.log.error( self.name + ": EOF exception found" )
1758 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001759 main.cleanup()
1760 main.exit()
Jon Hall0819fd92014-05-23 12:08:13 -07001761
Jon Hall7eb38402015-01-08 17:19:54 -08001762 def disconnect( self ):
kelvin-onlaba1484582015-02-02 15:46:20 -08001763 """
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001764 Called at the end of the test to stop the mininet and
1765 disconnect the handle.
kelvin-onlaba1484582015-02-02 15:46:20 -08001766 """
Jon Halld80cc142015-07-06 13:36:05 -07001767 self.handle.sendline( '' )
Jon Halld61331b2015-02-17 16:35:47 -08001768 i = self.handle.expect( [ 'mininet>', pexpect.EOF, pexpect.TIMEOUT ],
Jon Halld80cc142015-07-06 13:36:05 -07001769 timeout=2 )
Jon Hall390696c2015-05-05 17:13:41 -07001770 response = main.TRUE
kelvin-onlaba1484582015-02-02 15:46:20 -08001771 if i == 0:
Jon Hall390696c2015-05-05 17:13:41 -07001772 response = self.stopNet()
Jon Halld61331b2015-02-17 16:35:47 -08001773 elif i == 1:
1774 return main.TRUE
kelvin-onlaba1484582015-02-02 15:46:20 -08001775 # print "Disconnecting Mininet"
1776 if self.handle:
1777 self.handle.sendline( "exit" )
1778 self.handle.expect( "exit" )
1779 self.handle.expect( "(.*)" )
kelvin-onlaba1484582015-02-02 15:46:20 -08001780 else:
1781 main.log.error( "Connection failed to the host" )
kelvin-onlaba1484582015-02-02 15:46:20 -08001782 return response
1783
Jon Halld80cc142015-07-06 13:36:05 -07001784 def stopNet( self, fileName="", timeout=5 ):
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001785 """
Jon Hall21270ac2015-02-16 17:59:55 -08001786 Stops mininet.
Jon Hallefbd9792015-03-05 16:11:36 -08001787 Returns main.TRUE if the mininet successfully stops and
Jon Hall21270ac2015-02-16 17:59:55 -08001788 main.FALSE if the pexpect handle does not exist.
1789
Jon Halld61331b2015-02-17 16:35:47 -08001790 Will cleanup and exit the test if mininet fails to stop
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001791 """
Jon Halld61331b2015-02-17 16:35:47 -08001792 main.log.info( self.name + ": Stopping mininet..." )
adminbae64d82013-08-01 10:50:15 -07001793 response = ''
1794 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -07001795 try:
Jon Halld80cc142015-07-06 13:36:05 -07001796 self.handle.sendline( "" )
kelvin-onlab56a3f462015-02-06 14:04:43 -08001797 i = self.handle.expect( [ 'mininet>',
1798 '\$',
1799 pexpect.EOF,
1800 pexpect.TIMEOUT ],
1801 timeout )
1802 if i == 0:
1803 main.log.info( "Exiting mininet..." )
Jon Hall7eb38402015-01-08 17:19:54 -08001804 response = self.execute(
1805 cmd="exit",
1806 prompt="(.*)",
1807 timeout=120 )
Jon Halld80cc142015-07-06 13:36:05 -07001808 main.log.info( self.name + ": Stopped" )
Jon Hall7eb38402015-01-08 17:19:54 -08001809 self.handle.sendline( "sudo mn -c" )
shahshreya328c2a72014-11-17 10:19:50 -08001810 response = main.TRUE
Jon Hallafa8a472015-06-12 14:02:42 -07001811
kelvin-onlab56a3f462015-02-06 14:04:43 -08001812 if i == 1:
1813 main.log.info( " Mininet trying to exit while not " +
1814 "in the mininet prompt" )
1815 elif i == 2:
1816 main.log.error( "Something went wrong exiting mininet" )
1817 elif i == 3: # timeout
1818 main.log.error( "Something went wrong exiting mininet " +
1819 "TIMEOUT" )
Jon Hallafa8a472015-06-12 14:02:42 -07001820
Hari Krishnab35c6d02015-03-18 11:13:51 -07001821 if fileName:
Jon Halld80cc142015-07-06 13:36:05 -07001822 self.handle.sendline( "" )
1823 self.handle.expect( '\$' )
1824 self.handle.sendline(
1825 "sudo kill -9 \`ps -ef | grep \"" +
1826 fileName +
1827 "\" | grep -v grep | awk '{print $2}'\`" )
Jon Hallfbc828e2015-01-06 17:30:19 -08001828 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001829 main.log.error( self.name + ": EOF exception found" )
1830 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001831 main.cleanup()
1832 main.exit()
Jon Hall7eb38402015-01-08 17:19:54 -08001833 else:
1834 main.log.error( self.name + ": Connection failed to the host" )
adminbae64d82013-08-01 10:50:15 -07001835 response = main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -08001836 return response
1837
Jon Halla5cb3412015-08-18 14:08:22 -07001838 def arping( self, srcHost="", dstHost="10.128.20.211", ethDevice="" ):
kelvin-onlab65782a82015-05-07 14:12:13 -07001839 """
1840 Description:
1841 Sends arp message from mininet host for hosts discovery
1842 Required:
1843 host - hosts name
1844 Optional:
1845 ip - ip address that does not exist in the network so there would
1846 be no reply.
1847 """
kelvin-onlabf0594d72015-05-19 17:25:12 -07001848 if ethDevice:
1849 ethDevice = '-I ' + ethDevice + ' '
Jon Halla5cb3412015-08-18 14:08:22 -07001850 cmd = srcHost + " arping -c1 " + ethDevice + dstHost
admin07529932013-11-22 14:58:28 -08001851 try:
Jon Halla5cb3412015-08-18 14:08:22 -07001852 main.log.info( "Sending: " + cmd )
kelvin-onlab65782a82015-05-07 14:12:13 -07001853 self.handle.sendline( cmd )
Jon Halla5cb3412015-08-18 14:08:22 -07001854 i = self.handle.expect( [ "mininet>", "arping: " ] )
1855 if i == 0:
1856 return main.TRUE
1857 elif i == 1:
1858 response = self.handle.before + self.handle.after
1859 self.handle.expect( "mininet>" )
1860 response += self.handle.before + self.handle.after
1861 main.log.warn( "Error sending arping, output was: " +
1862 response )
1863 return main.FALSE
1864 except pexpect.TIMEOUT:
1865 main.log.error( self.name + ": TIMEOUT exception found" )
1866 main.log.warn( self.handle.before )
1867 return main.FALSE
kelvin-onlab65782a82015-05-07 14:12:13 -07001868 except pexpect.EOF:
1869 main.log.error( self.name + ": EOF exception found" )
1870 main.log.error( self.name + ": " + self.handle.before )
1871 main.cleanup()
1872 main.exit()
admin07529932013-11-22 14:58:28 -08001873
Jon Hall7eb38402015-01-08 17:19:54 -08001874 def decToHex( self, num ):
1875 return hex( num ).split( 'x' )[ 1 ]
Jon Hallfbc828e2015-01-06 17:30:19 -08001876
Jon Hall7eb38402015-01-08 17:19:54 -08001877 def getSwitchFlowCount( self, switch ):
1878 """
1879 return the Flow Count of the switch"""
admin2a9548d2014-06-17 14:08:07 -07001880 if self.handle:
1881 cmd = "sh ovs-ofctl dump-aggregate %s" % switch
1882 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001883 response = self.execute(
1884 cmd=cmd,
1885 prompt="mininet>",
1886 timeout=10 )
admin2a9548d2014-06-17 14:08:07 -07001887 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001888 main.log.error( self.name + ": EOF exception found" )
1889 main.log.error( self.name + " " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07001890 main.cleanup()
1891 main.exit()
1892 pattern = "flow_count=(\d+)"
Jon Hall7eb38402015-01-08 17:19:54 -08001893 result = re.search( pattern, response, re.MULTILINE )
admin2a9548d2014-06-17 14:08:07 -07001894 if result is None:
Jon Hall7eb38402015-01-08 17:19:54 -08001895 main.log.info(
1896 "Couldn't find flows on switch %s, found: %s" %
1897 ( switch, response ) )
admin2a9548d2014-06-17 14:08:07 -07001898 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001899 return result.group( 1 )
admin2a9548d2014-06-17 14:08:07 -07001900 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001901 main.log.error( "Connection failed to the Mininet host" )
Jon Hallfbc828e2015-01-06 17:30:19 -08001902
GlennRC68467eb2015-11-16 18:01:01 -08001903 def flowTableComp( self, flowTable1, flowTable2 ):
1904 # This function compares the selctors and treatments of each flow
1905 try:
1906 if len(flowTable1) != len(flowTable2):
1907 main.log.warn( "Flow table lengths do not match" )
1908 return main.FALSE
GlennRCfa65fce2015-12-16 13:16:08 -08001909 dFields = ["n_bytes", "cookie", "n_packets", "duration"]
1910 for flow1, flow2 in zip(flowTable1, flowTable2):
Jon Hallacd1b182015-12-17 11:43:20 -08001911 for field in dFields:
1912 try:
1913 flow1.pop( field )
1914 except KeyError as e:
1915 main.log.warn( e )
1916 main.log.debug( flow1 )
1917 try:
1918 flow2.pop( field )
1919 except KeyError as e:
1920 main.log.warn( e )
1921 main.log.debug( flow2 )
GlennRC68467eb2015-11-16 18:01:01 -08001922 for i in range( len(flowTable1) ):
GlennRC17bbcf52015-12-14 17:31:50 -08001923 if flowTable1[i] not in flowTable2:
1924 main.log.warn( "Flow tables do not match:" )
1925 main.log.warn( "Old flow:\n{}\n not in new flow table".format( flowTable1[i] ) )
GlennRC68467eb2015-11-16 18:01:01 -08001926 return main.FALSE
Jon Hall9043c902015-07-30 14:23:44 -07001927 return main.TRUE
GlennRC68467eb2015-11-16 18:01:01 -08001928 except Exception:
1929 main.log.exception( "Uncaught exception!" )
1930 main.cleanup()
1931 main.exit()
Jon Hall9043c902015-07-30 14:23:44 -07001932
GlennRC528ad292015-11-12 10:38:18 -08001933 def parseFlowTable( self, flowTable, version="", debug=True ):
GlennRC956ea742015-11-05 16:14:15 -08001934 '''
1935 Discription: Parses flows into json format.
1936 NOTE: this can parse any string thats separated with commas
1937 Arguments:
1938 Required:
1939 flows: a list of strings that represnt flows
1940 Optional:
1941 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
1942 debug: prints out the final result
1943 returns: A list of flows in json format
1944 '''
GlennRC528ad292015-11-12 10:38:18 -08001945 jsonFlowTable = []
1946 for flow in flowTable:
GlennRC956ea742015-11-05 16:14:15 -08001947 jsonFlow = {}
GlennRC528ad292015-11-12 10:38:18 -08001948 # split up the fields of the flow
1949 parsedFlow = flow.split(", ")
1950 # get rid of any spaces in front of the field
1951 for i in range( len(parsedFlow) ):
1952 item = parsedFlow[i]
1953 if item[0] == " ":
1954 parsedFlow[i] = item[1:]
1955 # grab the selector and treatment from the parsed flow
1956 # the last element is the selector and the treatment
1957 temp = parsedFlow.pop(-1)
1958 # split up the selector and the treatment
1959 temp = temp.split(" ")
1960 index = 0
1961 # parse the flags
1962 # NOTE: This only parses one flag
1963 flag = {}
1964 if version == "1.3":
1965 flag = {"flag":[temp[index]]}
1966 index += 1
1967 # the first element is the selector and split it up
1968 sel = temp[index]
1969 index += 1
1970 sel = sel.split(",")
1971 # the priority is stuck in the selecter so put it back
1972 # in the flow
1973 parsedFlow.append(sel.pop(0))
1974 # parse selector
1975 criteria = []
1976 for item in sel:
1977 # this is the type of the packet e.g. "arp"
1978 if "=" not in item:
1979 criteria.append( {"type":item} )
1980 else:
1981 field = item.split("=")
1982 criteria.append( {field[0]:field[1]} )
GlennRC68467eb2015-11-16 18:01:01 -08001983 selector = {"selector": {"criteria":sorted(criteria)} }
GlennRC528ad292015-11-12 10:38:18 -08001984 treat = temp[index]
1985 # get rid of the action part e.g. "action=output:2"
1986 # we will add it back later
1987 treat = treat.split("=")
1988 treat.pop(0)
1989 # parse treatment
1990 action = []
1991 for item in treat:
1992 field = item.split(":")
1993 action.append( {field[0]:field[1]} )
1994 # create the treatment field and add the actions
GlennRC68467eb2015-11-16 18:01:01 -08001995 treatment = {"treatment": {"action":sorted(action)} }
GlennRC528ad292015-11-12 10:38:18 -08001996 # parse the rest of the flow
1997 for item in parsedFlow:
1998 field = item.split("=")
1999 jsonFlow.update( {field[0]:field[1]} )
2000 # add the treatment and the selector to the json flow
2001 jsonFlow.update( selector )
2002 jsonFlow.update( treatment )
2003 jsonFlow.update( flag )
GlennRC956ea742015-11-05 16:14:15 -08002004
GlennRC528ad292015-11-12 10:38:18 -08002005 if debug: main.log.debug( "\033[94mJson flow:\033[0m\n{}\n".format(jsonFlow) )
GlennRC956ea742015-11-05 16:14:15 -08002006
GlennRC528ad292015-11-12 10:38:18 -08002007 # add the json flow to the json flow table
2008 jsonFlowTable.append( jsonFlow )
GlennRC956ea742015-11-05 16:14:15 -08002009
GlennRC528ad292015-11-12 10:38:18 -08002010 return jsonFlowTable
2011
Jon Hall0a543792015-12-14 11:00:26 -08002012 def getFlowTable( self, sw, version="", debug=False):
GlennRC956ea742015-11-05 16:14:15 -08002013 '''
2014 Discription: Returns the flow table(s) on a switch or switches in a list.
2015 Each element is a flow.
2016 Arguments:
2017 Required:
2018 sw: The switch name ("s1") to retrive the flow table. Can also be
2019 a list of switches.
2020 Optional:
2021 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
2022 debug: prints out the final result
2023 '''
2024 try:
2025 switches = []
2026 if type(sw) is list:
Jon Hallca7ac292015-11-11 09:28:12 -08002027 switches.extend(sw)
GlennRC956ea742015-11-05 16:14:15 -08002028 else: switches.append(sw)
2029
2030 flows = []
2031 for s in switches:
2032 cmd = "sh ovs-ofctl dump-flows " + s
2033
GlennRC528ad292015-11-12 10:38:18 -08002034 if "1.0" == version:
2035 cmd += " -F OpenFlow10-table_id"
2036 elif "1.3" == version:
GlennRC956ea742015-11-05 16:14:15 -08002037 cmd += " -O OpenFlow13"
GlennRC956ea742015-11-05 16:14:15 -08002038
2039 main.log.info( "Sending: " + cmd )
2040 self.handle.sendline( cmd )
2041 self.handle.expect( "mininet>" )
2042 response = self.handle.before
2043 response = response.split( "\r\n" )
2044 # dump the first two elements and the last
2045 # the first element is the command that was sent
2046 # the second is the table header
2047 # the last element is empty
2048 response = response[2:-1]
2049 flows.extend( response )
2050
2051 if debug: print "Flows:\n{}\n\n".format(flows)
2052
GlennRC528ad292015-11-12 10:38:18 -08002053 return self.parseFlowTable( flows, version, debug )
GlennRC956ea742015-11-05 16:14:15 -08002054
2055 except pexpect.TIMEOUT:
2056 main.log.exception( self.name + ": Command timed out" )
2057 return None
2058 except pexpect.EOF:
2059 main.log.exception( self.name + ": connection closed." )
2060 main.cleanup()
2061 main.exit()
2062 except Exception:
2063 main.log.exception( self.name + ": Uncaught exception!" )
2064 main.cleanup()
2065 main.exit()
2066
2067 def checkFlowId( self, sw, flowId, version="1.3", debug=True ):
2068 '''
2069 Discription: Checks whether the ID provided matches a flow ID in Mininet
2070 Arguments:
2071 Required:
2072 sw: The switch name ("s1") to retrive the flow table. Can also be
2073 a list of switches.
2074 flowId: the flow ID in hex format. Can also be a list of IDs
2075 Optional:
2076 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
2077 debug: prints out the final result
2078 returns: main.TRUE if all IDs are present, otherwise returns main.FALSE
2079 NOTE: prints out IDs that are not present
2080 '''
2081 try:
2082 main.log.info( "Getting flows from Mininet" )
2083 flows = self.getFlowTable( sw, version, debug )
2084
2085 if debug: print "flow ids:\n{}\n\n".format(flowId)
2086
2087 # Check flowId is a list or a string
2088 if type( flowId ) is str:
2089 result = False
2090 for f in flows:
2091 if flowId in f.get( 'cookie' ):
2092 result = True
2093 break
2094 # flowId is a list
2095 else:
2096 result = True
2097 # Get flow IDs from Mininet
2098 mnFlowIds = [ f.get( 'cookie' ) for f in flows ]
2099 # Save the IDs that are not in Mininet
2100 absentIds = [ x for x in flowId if x not in mnFlowIds ]
2101
2102 if debug: print "mn flow ids:\n{}\n\n".format(mnFlowIds)
2103
2104 # Print out the IDs that are not in Mininet
2105 if absentIds:
2106 main.log.warn( "Absent ids: {}".format( absentIds ) )
2107 result = False
2108
2109 return main.TRUE if result else main.FALSE
2110
2111 except Exception:
2112 main.log.exception( self.name + ": Uncaught exception!" )
2113 main.cleanup()
2114 main.exit()
2115
2116
Charles Chan029be652015-08-24 01:46:10 +08002117 def startTcpdump( self, filename, intf="eth0", port="port 6653" ):
Jon Hall7eb38402015-01-08 17:19:54 -08002118 """
Jon Hallefbd9792015-03-05 16:11:36 -08002119 Runs tpdump on an interface and saves the file
Jon Hall7eb38402015-01-08 17:19:54 -08002120 intf can be specified, or the default eth0 is used"""
admin2a9548d2014-06-17 14:08:07 -07002121 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002122 self.handle.sendline( "" )
2123 self.handle.expect( "mininet>" )
2124 self.handle.sendline(
2125 "sh sudo tcpdump -n -i " +
2126 intf +
2127 " " +
2128 port +
2129 " -w " +
2130 filename.strip() +
2131 " &" )
2132 self.handle.sendline( "" )
2133 i = self.handle.expect( [ 'No\ssuch\device',
2134 'listening\son',
2135 pexpect.TIMEOUT,
2136 "mininet>" ],
2137 timeout=10 )
2138 main.log.warn( self.handle.before + self.handle.after )
2139 self.handle.sendline( "" )
2140 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002141 if i == 0:
Jon Hall7eb38402015-01-08 17:19:54 -08002142 main.log.error(
2143 self.name +
2144 ": tcpdump - No such device exists. " +
2145 "tcpdump attempted on: " +
2146 intf )
admin2a9548d2014-06-17 14:08:07 -07002147 return main.FALSE
2148 elif i == 1:
Jon Hall7eb38402015-01-08 17:19:54 -08002149 main.log.info( self.name + ": tcpdump started on " + intf )
admin2a9548d2014-06-17 14:08:07 -07002150 return main.TRUE
2151 elif i == 2:
Jon Hall7eb38402015-01-08 17:19:54 -08002152 main.log.error(
2153 self.name +
2154 ": tcpdump command timed out! Check interface name," +
2155 " given interface was: " +
2156 intf )
admin2a9548d2014-06-17 14:08:07 -07002157 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08002158 elif i == 3:
2159 main.log.info( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002160 return main.TRUE
2161 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002162 main.log.error( self.name + ": tcpdump - unexpected response" )
admin2a9548d2014-06-17 14:08:07 -07002163 return main.FALSE
2164 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002165 main.log.error( self.name + ": EOF exception found" )
2166 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002167 main.cleanup()
2168 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -08002169 except Exception:
2170 main.log.exception( self.name + ": Uncaught exception!" )
admin2a9548d2014-06-17 14:08:07 -07002171 main.cleanup()
2172 main.exit()
2173
kelvin-onlabd3b64892015-01-20 13:26:24 -08002174 def stopTcpdump( self ):
Jon Hallefbd9792015-03-05 16:11:36 -08002175 """
2176 pkills tcpdump"""
admin2a9548d2014-06-17 14:08:07 -07002177 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002178 self.handle.sendline( "sh sudo pkill tcpdump" )
2179 self.handle.expect( "mininet>" )
2180 self.handle.sendline( "" )
2181 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002182 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002183 main.log.error( self.name + ": EOF exception found" )
2184 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002185 main.cleanup()
2186 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -08002187 except Exception:
2188 main.log.exception( self.name + ": Uncaught exception!" )
admin2a9548d2014-06-17 14:08:07 -07002189 main.cleanup()
2190 main.exit()
2191
Jon Halld80cc142015-07-06 13:36:05 -07002192 def getPorts( self, nodeName, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002193 """
2194 Read ports from a Mininet switch.
2195
2196 Returns a json structure containing information about the
2197 ports of the given switch.
2198 """
2199 response = self.getInterfaces( nodeName )
2200 # TODO: Sanity check on response. log if no such switch exists
2201 ports = []
2202 for line in response.split( "\n" ):
2203 if not line.startswith( "name=" ):
2204 continue
2205 portVars = {}
2206 for var in line.split( "," ):
2207 key, value = var.split( "=" )
2208 portVars[ key ] = value
2209 isUp = portVars.pop( 'enabled', "True" )
2210 isUp = "True" in isUp
2211 if verbose:
2212 main.log.info( "Reading switch port %s(%s)" %
2213 ( portVars[ 'name' ], portVars[ 'mac' ] ) )
2214 mac = portVars[ 'mac' ]
Jon Halld80cc142015-07-06 13:36:05 -07002215 if mac == 'None':
Jon Hallafa8a472015-06-12 14:02:42 -07002216 mac = None
2217 ips = []
2218 ip = portVars[ 'ip' ]
2219 if ip == 'None':
2220 ip = None
2221 ips.append( ip )
2222 name = portVars[ 'name' ]
2223 if name == 'None':
2224 name = None
2225 portRe = r'[^\-]\d\-eth(?P<port>\d+)'
2226 if name == 'lo':
2227 portNo = 0xfffe # TODO: 1.0 value - Should we just return lo?
2228 else:
2229 portNo = re.search( portRe, name ).group( 'port' )
2230 ports.append( { 'of_port': portNo,
2231 'mac': str( mac ).replace( '\'', '' ),
2232 'name': name,
2233 'ips': ips,
2234 'enabled': isUp } )
2235 return ports
2236
Jon Halld80cc142015-07-06 13:36:05 -07002237 def getSwitches( self, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002238 """
2239 Read switches from Mininet.
2240
2241 Returns a dictionary whose keys are the switch names and the value is
2242 a dictionary containing information about the switch.
2243 """
Jon Halla22481b2015-07-28 17:46:01 -07002244 # NOTE: To support new Mininet switch classes, just append the new
2245 # class to the switchClasses variable
Jon Hallafa8a472015-06-12 14:02:42 -07002246
Jon Halla22481b2015-07-28 17:46:01 -07002247 # Regex patterns to parse 'dump' output
2248 # Example Switches:
Jon Hallafa8a472015-06-12 14:02:42 -07002249 # <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 -07002250 # <OVSSwitch{ 'protocols': 'OpenFlow10' } s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=25974>
Jon Halla22481b2015-07-28 17:46:01 -07002251 # <OVSSwitchNS s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None pid=22550>
2252 # <OVSBridge s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=26830>
2253 # <UserSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=14737>
2254 switchClasses = r"(OVSSwitch)|(OVSBridge)|(OVSSwitchNS)|(IVSSwitch)|(LinuxBridge)|(UserSwitch)"
2255 swRE = r"<(?P<class>" + switchClasses + r")" +\
2256 r"(?P<options>\{.*\})?\s" +\
2257 r"(?P<name>[^:]+)\:\s" +\
2258 r"(?P<ports>([^,]+,)*[^,\s]+)" +\
2259 r"\spid=(?P<pid>(\d)+)"
Jon Hallafa8a472015-06-12 14:02:42 -07002260 # Update mn port info
2261 self.update()
Jon Halld80cc142015-07-06 13:36:05 -07002262 output = {}
Jon Hallafa8a472015-06-12 14:02:42 -07002263 dump = self.dump().split( "\n" )
2264 for line in dump:
Jon Halla22481b2015-07-28 17:46:01 -07002265 result = re.search( swRE, line, re.I )
2266 if result:
Jon Hallafa8a472015-06-12 14:02:42 -07002267 name = result.group( 'name' )
2268 dpid = str( self.getSwitchDPID( name ) ).zfill( 16 )
Jon Halla22481b2015-07-28 17:46:01 -07002269 pid = result.group( 'pid' )
2270 swClass = result.group( 'class' )
2271 options = result.group( 'options' )
Jon Hallafa8a472015-06-12 14:02:42 -07002272 if verbose:
2273 main.log.info( "Reading switch %s(%s)" % ( name, dpid ) )
2274 ports = self.getPorts( name )
Jon Halla22481b2015-07-28 17:46:01 -07002275 output[ name ] = { "dpid": dpid,
2276 "ports": ports,
2277 "swClass": swClass,
2278 "pid": pid,
2279 "options": options }
Jon Hallafa8a472015-06-12 14:02:42 -07002280 return output
2281
Jon Halld80cc142015-07-06 13:36:05 -07002282 def getHosts( self, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002283 """
2284 Read hosts from Mininet.
2285
2286 Returns a dictionary whose keys are the host names and the value is
2287 a dictionary containing information about the host.
2288 """
2289 # Regex patterns to parse dump output
2290 # Example host: <Host h1: h1-eth0:10.0.0.1 pid=5227>
kelvin-onlab299ab062015-07-15 10:58:27 -07002291 # <Host h1: pid=12725>
2292 # <VLANHost h12: h12-eth0.100.100.100:100.1.0.3 pid=30186>
2293 # <dualStackHost h19: h19-eth0:10.1.0.9 pid=30200>
2294 # <IPv6Host h18: h18-eth0:10.0.0.18 pid=30198>
Jon Hallafa8a472015-06-12 14:02:42 -07002295 # NOTE: Does not correctly match hosts with multi-links
2296 # <Host h2: h2-eth0:10.0.0.2,h2-eth1:10.0.1.2 pid=14386>
2297 # FIXME: Fix that
kelvin-onlabd48a68c2015-07-13 16:01:36 -07002298 hostRE = r"Host\s(?P<name>[^:]+)\:((\s(?P<ifname>[^:]+)\:" +\
Jon Halld80cc142015-07-06 13:36:05 -07002299 "(?P<ip>[^\s]+))|(\s)\spid=(?P<pid>[^>]+))"
Jon Hallafa8a472015-06-12 14:02:42 -07002300 # update mn port info
2301 self.update()
2302 # Get mininet dump
2303 dump = self.dump().split( "\n" )
Jon Hall5b0120a2015-06-12 17:35:53 -07002304 hosts = {}
Jon Hallafa8a472015-06-12 14:02:42 -07002305 for line in dump:
kelvin-onlabd48a68c2015-07-13 16:01:36 -07002306 if "Host" in line :
Jon Hallafa8a472015-06-12 14:02:42 -07002307 result = re.search( hostRE, line )
2308 name = result.group( 'name' )
2309 interfaces = []
2310 response = self.getInterfaces( name )
2311 # Populate interface info
2312 for line in response.split( "\n" ):
2313 if line.startswith( "name=" ):
2314 portVars = {}
2315 for var in line.split( "," ):
2316 key, value = var.split( "=" )
2317 portVars[ key ] = value
2318 isUp = portVars.pop( 'enabled', "True" )
2319 isUp = "True" in isUp
2320 if verbose:
2321 main.log.info( "Reading host port %s(%s)" %
2322 ( portVars[ 'name' ],
2323 portVars[ 'mac' ] ) )
2324 mac = portVars[ 'mac' ]
Jon Halld80cc142015-07-06 13:36:05 -07002325 if mac == 'None':
Jon Hallafa8a472015-06-12 14:02:42 -07002326 mac = None
2327 ips = []
2328 ip = portVars[ 'ip' ]
2329 if ip == 'None':
2330 ip = None
2331 ips.append( ip )
2332 intfName = portVars[ 'name' ]
2333 if name == 'None':
2334 name = None
2335 interfaces.append( {
2336 "name": intfName,
2337 "ips": ips,
2338 "mac": str( mac ),
2339 "isUp": isUp } )
Jon Hall5b0120a2015-06-12 17:35:53 -07002340 hosts[ name ] = { "interfaces": interfaces }
Jon Hallafa8a472015-06-12 14:02:42 -07002341 return hosts
2342
2343 def getLinks( self ):
2344 """
2345 Gathers information about current Mininet links. These links may not
2346 be up if one of the ports is down.
2347
2348 Returns a list of dictionaries with link endpoints.
2349
2350 The dictionary structure is:
Jon Halld80cc142015-07-06 13:36:05 -07002351 { 'node1': str( node1 name )
2352 'node2': str( node2 name )
2353 'port1': str( port1 of_port )
2354 'port2': str( port2 of_port ) }
Jon Hallafa8a472015-06-12 14:02:42 -07002355 Note: The port number returned is the eth#, not necessarily the of_port
2356 number. In Mininet, for OVS switch, these should be the same. For
2357 hosts, this is just the eth#.
2358 """
2359 self.update()
2360 response = self.links().split( '\n' )
2361
2362 # Examples:
2363 # s1-eth3<->s2-eth1 (OK OK)
2364 # s13-eth3<->h27-eth0 (OK OK)
2365 linkRE = "(?P<node1>[\w]+)\-eth(?P<port1>[\d]+)\<\-\>" +\
2366 "(?P<node2>[\w]+)\-eth(?P<port2>[\d]+)"
2367 links = []
2368 for line in response:
2369 match = re.search( linkRE, line )
2370 if match:
2371 node1 = match.group( 'node1' )
2372 node2 = match.group( 'node2' )
2373 port1 = match.group( 'port1' )
2374 port2 = match.group( 'port2' )
2375 links.append( { 'node1': node1,
2376 'node2': node2,
2377 'port1': port1,
2378 'port2': port2 } )
2379 return links
2380
2381 def compareSwitches( self, switches, switchesJson, portsJson ):
Jon Hall7eb38402015-01-08 17:19:54 -08002382 """
2383 Compare mn and onos switches
Jon Hallafa8a472015-06-12 14:02:42 -07002384 switchesJson: parsed json object from the onos devices api
Jon Hall3d87d502014-10-17 18:37:42 -04002385
Jon Hallafa8a472015-06-12 14:02:42 -07002386 Dependencies:
2387 1. numpy - "sudo pip install numpy"
2388 """
2389 from numpy import uint64
Jon Hall3d87d502014-10-17 18:37:42 -04002390 # created sorted list of dpid's in MN and ONOS for comparison
Jon Hall7eb38402015-01-08 17:19:54 -08002391 mnDPIDs = []
Jon Hallafa8a472015-06-12 14:02:42 -07002392 for swName, switch in switches.iteritems():
Jon Hall7eb38402015-01-08 17:19:54 -08002393 mnDPIDs.append( switch[ 'dpid' ].lower() )
Jon Hall3d87d502014-10-17 18:37:42 -04002394 mnDPIDs.sort()
kelvin-onlabd3b64892015-01-20 13:26:24 -08002395 if switchesJson == "": # if rest call fails
Jon Hall7eb38402015-01-08 17:19:54 -08002396 main.log.error(
2397 self.name +
Jon Hallfeff3082015-05-19 10:23:26 -07002398 ".compareSwitches(): Empty JSON object given from ONOS" )
Jon Hall3d87d502014-10-17 18:37:42 -04002399 return main.FALSE
kelvin-onlabd3b64892015-01-20 13:26:24 -08002400 onos = switchesJson
Jon Hall7eb38402015-01-08 17:19:54 -08002401 onosDPIDs = []
Jon Hall3d87d502014-10-17 18:37:42 -04002402 for switch in onos:
Jon Hall7eb38402015-01-08 17:19:54 -08002403 if switch[ 'available' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002404 onosDPIDs.append(
2405 switch[ 'id' ].replace(
2406 ":",
2407 '' ).replace(
2408 "of",
2409 '' ).lower() )
Jon Hall3d87d502014-10-17 18:37:42 -04002410 onosDPIDs.sort()
Jon Hall3d87d502014-10-17 18:37:42 -04002411
Jon Hall7eb38402015-01-08 17:19:54 -08002412 if mnDPIDs != onosDPIDs:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002413 switchResults = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002414 main.log.error( "Switches in MN but not in ONOS:" )
Jon Hall7eb38402015-01-08 17:19:54 -08002415 list1 = [ switch for switch in mnDPIDs if switch not in onosDPIDs ]
Jon Hallafa8a472015-06-12 14:02:42 -07002416 main.log.error( str( list1 ) )
2417 main.log.error( "Switches in ONOS but not in MN:" )
Jon Hall7eb38402015-01-08 17:19:54 -08002418 list2 = [ switch for switch in onosDPIDs if switch not in mnDPIDs ]
Jon Hallafa8a472015-06-12 14:02:42 -07002419 main.log.error( str( list2 ) )
Jon Hall7eb38402015-01-08 17:19:54 -08002420 else: # list of dpid's match in onos and mn
kelvin-onlabd3b64892015-01-20 13:26:24 -08002421 switchResults = main.TRUE
Jon Hallafa8a472015-06-12 14:02:42 -07002422 finalResults = switchResults
Jon Hall3d87d502014-10-17 18:37:42 -04002423
Jon Hall7eb38402015-01-08 17:19:54 -08002424 # FIXME: this does not look for extra ports in ONOS, only checks that
2425 # ONOS has what is in MN
kelvin-onlabd3b64892015-01-20 13:26:24 -08002426 portsResults = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002427
Jon Hall7eb38402015-01-08 17:19:54 -08002428 # PORTS
Jon Hallafa8a472015-06-12 14:02:42 -07002429 for name, mnSwitch in switches.iteritems():
kelvin-onlabd3b64892015-01-20 13:26:24 -08002430 mnPorts = []
2431 onosPorts = []
2432 switchResult = main.TRUE
2433 for port in mnSwitch[ 'ports' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002434 if port[ 'enabled' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002435 mnPorts.append( int( port[ 'of_port' ] ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002436 for onosSwitch in portsJson:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002437 if onosSwitch[ 'device' ][ 'available' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002438 if onosSwitch[ 'device' ][ 'id' ].replace(
2439 ':',
2440 '' ).replace(
2441 "of",
2442 '' ) == mnSwitch[ 'dpid' ]:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002443 for port in onosSwitch[ 'ports' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002444 if port[ 'isEnabled' ]:
2445 if port[ 'port' ] == 'local':
kelvin-onlabd3b64892015-01-20 13:26:24 -08002446 # onosPorts.append( 'local' )
2447 onosPorts.append( long( uint64( -2 ) ) )
Jon Hallb1290e82014-11-18 16:17:48 -05002448 else:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002449 onosPorts.append( int( port[ 'port' ] ) )
Jon Hallb1290e82014-11-18 16:17:48 -05002450 break
kelvin-onlabd3b64892015-01-20 13:26:24 -08002451 mnPorts.sort( key=float )
2452 onosPorts.sort( key=float )
Jon Hallafa8a472015-06-12 14:02:42 -07002453
kelvin-onlabd3b64892015-01-20 13:26:24 -08002454 mnPortsLog = mnPorts
2455 onosPortsLog = onosPorts
2456 mnPorts = [ x for x in mnPorts ]
2457 onosPorts = [ x for x in onosPorts ]
Jon Hall38481722014-11-04 16:50:05 -05002458
Jon Hall7eb38402015-01-08 17:19:54 -08002459 # TODO: handle other reserved port numbers besides LOCAL
2460 # NOTE: Reserved ports
2461 # Local port: -2 in Openflow, ONOS shows 'local', we store as
2462 # long( uint64( -2 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002463 for mnPort in mnPortsLog:
2464 if mnPort in onosPorts:
Jon Hall7eb38402015-01-08 17:19:54 -08002465 # don't set results to true here as this is just one of
2466 # many checks and it might override a failure
kelvin-onlabd3b64892015-01-20 13:26:24 -08002467 mnPorts.remove( mnPort )
2468 onosPorts.remove( mnPort )
Jon Hallafa8a472015-06-12 14:02:42 -07002469
Jon Hall7eb38402015-01-08 17:19:54 -08002470 # NOTE: OVS reports this as down since there is no link
Jon Hallb1290e82014-11-18 16:17:48 -05002471 # So ignoring these for now
Jon Hall7eb38402015-01-08 17:19:54 -08002472 # TODO: Come up with a better way of handling these
kelvin-onlabd3b64892015-01-20 13:26:24 -08002473 if 65534 in mnPorts:
2474 mnPorts.remove( 65534 )
2475 if long( uint64( -2 ) ) in onosPorts:
2476 onosPorts.remove( long( uint64( -2 ) ) )
2477 if len( mnPorts ): # the ports of this switch don't match
2478 switchResult = main.FALSE
2479 main.log.warn( "Ports in MN but not ONOS: " + str( mnPorts ) )
2480 if len( onosPorts ): # the ports of this switch don't match
2481 switchResult = main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08002482 main.log.warn(
2483 "Ports in ONOS but not MN: " +
kelvin-onlabd3b64892015-01-20 13:26:24 -08002484 str( onosPorts ) )
2485 if switchResult == main.FALSE:
Jon Hallafa8a472015-06-12 14:02:42 -07002486 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002487 "The list of ports for switch %s(%s) does not match:" %
Jon Hallafa8a472015-06-12 14:02:42 -07002488 ( name, mnSwitch[ 'dpid' ] ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002489 main.log.warn( "mn_ports[] = " + str( mnPortsLog ) )
2490 main.log.warn( "onos_ports[] = " + str( onosPortsLog ) )
2491 portsResults = portsResults and switchResult
Jon Hallafa8a472015-06-12 14:02:42 -07002492 finalResults = finalResults and portsResults
2493 return finalResults
Jon Hall72cf1dc2014-10-20 21:04:50 -04002494
Jon Hallafa8a472015-06-12 14:02:42 -07002495 def compareLinks( self, switches, links, linksJson ):
Jon Hall7eb38402015-01-08 17:19:54 -08002496 """
2497 Compare mn and onos links
kelvin-onlabd3b64892015-01-20 13:26:24 -08002498 linksJson: parsed json object from the onos links api
Jon Hall72cf1dc2014-10-20 21:04:50 -04002499
Jon Hallafa8a472015-06-12 14:02:42 -07002500 """
Jon Hall7eb38402015-01-08 17:19:54 -08002501 # FIXME: this does not look for extra links in ONOS, only checks that
Jon Hallefbd9792015-03-05 16:11:36 -08002502 # ONOS has what is in MN
kelvin-onlabd3b64892015-01-20 13:26:24 -08002503 onos = linksJson
Jon Hall72cf1dc2014-10-20 21:04:50 -04002504
Jon Halld80cc142015-07-06 13:36:05 -07002505 mnLinks = []
Jon Hallafa8a472015-06-12 14:02:42 -07002506 for l in links:
2507 try:
2508 node1 = switches[ l[ 'node1' ] ]
2509 node2 = switches[ l[ 'node2' ] ]
2510 enabled = True
2511 for port in node1[ 'ports' ]:
2512 if port[ 'of_port' ] == l[ 'port1' ]:
2513 enabled = enabled and port[ 'enabled' ]
2514 for port in node2[ 'ports' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002515 if port[ 'of_port' ] == l[ 'port2' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002516 enabled = enabled and port[ 'enabled' ]
2517 if enabled:
2518 mnLinks.append( l )
2519 except KeyError:
2520 pass
kelvin-onlabd3b64892015-01-20 13:26:24 -08002521 if 2 * len( mnLinks ) == len( onos ):
2522 linkResults = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002523 else:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002524 linkResults = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002525 main.log.error(
Jon Hall328ddca2015-01-28 15:57:15 -08002526 "Mininet has " + str( len( mnLinks ) ) +
2527 " bidirectional links and ONOS has " +
2528 str( len( onos ) ) + " unidirectional links" )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002529
Jon Hall7eb38402015-01-08 17:19:54 -08002530 # iterate through MN links and check if an ONOS link exists in
2531 # both directions
kelvin-onlabd3b64892015-01-20 13:26:24 -08002532 for link in mnLinks:
Jon Hall7eb38402015-01-08 17:19:54 -08002533 # TODO: Find a more efficient search method
Jon Hall72cf1dc2014-10-20 21:04:50 -04002534 node1 = None
2535 port1 = None
2536 node2 = None
2537 port2 = None
kelvin-onlabd3b64892015-01-20 13:26:24 -08002538 firstDir = main.FALSE
2539 secondDir = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002540 for swName, switch in switches.iteritems():
2541 if swName == link[ 'node1' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002542 node1 = switch[ 'dpid' ]
2543 for port in switch[ 'ports' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002544 if str( port[ 'of_port' ] ) == str( link[ 'port1' ] ):
Jon Hall7eb38402015-01-08 17:19:54 -08002545 port1 = port[ 'of_port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002546 if node1 is not None and node2 is not None:
2547 break
Jon Hallafa8a472015-06-12 14:02:42 -07002548 if swName == link[ 'node2' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002549 node2 = switch[ 'dpid' ]
2550 for port in switch[ 'ports' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002551 if str( port[ 'of_port' ] ) == str( link[ 'port2' ] ):
Jon Hall7eb38402015-01-08 17:19:54 -08002552 port2 = port[ 'of_port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002553 if node1 is not None and node2 is not None:
2554 break
2555
kelvin-onlabd3b64892015-01-20 13:26:24 -08002556 for onosLink in onos:
2557 onosNode1 = onosLink[ 'src' ][ 'device' ].replace(
Jon Hallafa8a472015-06-12 14:02:42 -07002558 ":", '' ).replace( "of", '' )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002559 onosNode2 = onosLink[ 'dst' ][ 'device' ].replace(
Jon Hallafa8a472015-06-12 14:02:42 -07002560 ":", '' ).replace( "of", '' )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002561 onosPort1 = onosLink[ 'src' ][ 'port' ]
2562 onosPort2 = onosLink[ 'dst' ][ 'port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002563
Jon Hall72cf1dc2014-10-20 21:04:50 -04002564 # check onos link from node1 to node2
kelvin-onlabd3b64892015-01-20 13:26:24 -08002565 if str( onosNode1 ) == str( node1 ) and str(
2566 onosNode2 ) == str( node2 ):
2567 if int( onosPort1 ) == int( port1 ) and int(
2568 onosPort2 ) == int( port2 ):
2569 firstDir = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002570 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002571 main.log.warn(
2572 'The port numbers do not match for ' +
2573 str( link ) +
Jon Hallefbd9792015-03-05 16:11:36 -08002574 ' between ONOS and MN. When checking ONOS for ' +
Jon Hall7eb38402015-01-08 17:19:54 -08002575 'link %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002576 ( node1, port1, node2, port2 ) +
Jon Hall7eb38402015-01-08 17:19:54 -08002577 ' ONOS has the values %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002578 ( onosNode1, onosPort1, onosNode2, onosPort2 ) )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002579
2580 # check onos link from node2 to node1
kelvin-onlabd3b64892015-01-20 13:26:24 -08002581 elif ( str( onosNode1 ) == str( node2 ) and
2582 str( onosNode2 ) == str( node1 ) ):
2583 if ( int( onosPort1 ) == int( port2 )
2584 and int( onosPort2 ) == int( port1 ) ):
2585 secondDir = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002586 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002587 main.log.warn(
2588 'The port numbers do not match for ' +
2589 str( link ) +
Jon Hallefbd9792015-03-05 16:11:36 -08002590 ' between ONOS and MN. When checking ONOS for ' +
Jon Hall7eb38402015-01-08 17:19:54 -08002591 'link %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002592 ( node1, port1, node2, port2 ) +
Jon Hall7eb38402015-01-08 17:19:54 -08002593 ' ONOS has the values %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002594 ( onosNode2, onosPort2, onosNode1, onosPort1 ) )
Jon Hall7eb38402015-01-08 17:19:54 -08002595 else: # this is not the link you're looking for
Jon Hall72cf1dc2014-10-20 21:04:50 -04002596 pass
kelvin-onlabd3b64892015-01-20 13:26:24 -08002597 if not firstDir:
Jon Hallafa8a472015-06-12 14:02:42 -07002598 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002599 'ONOS does not have the link %s/%s -> %s/%s' %
2600 ( node1, port1, node2, port2 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002601 if not secondDir:
Jon Hallafa8a472015-06-12 14:02:42 -07002602 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002603 'ONOS does not have the link %s/%s -> %s/%s' %
2604 ( node2, port2, node1, port1 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002605 linkResults = linkResults and firstDir and secondDir
2606 return linkResults
Jon Hall72cf1dc2014-10-20 21:04:50 -04002607
Jon Hallafa8a472015-06-12 14:02:42 -07002608 def compareHosts( self, hosts, hostsJson ):
Jon Hallff6b4b22015-02-23 09:25:15 -08002609 """
Jon Hallafa8a472015-06-12 14:02:42 -07002610 Compare mn and onos Hosts.
2611 Since Mininet hosts are quiet, ONOS will only know of them when they
2612 speak. For this reason, we will only check that the hosts in ONOS
2613 stores are in Mininet, and not vice versa.
Jon Hallff6b4b22015-02-23 09:25:15 -08002614
Jon Hallafa8a472015-06-12 14:02:42 -07002615 Arguments:
2616 hostsJson: parsed json object from the onos hosts api
2617 Returns:
2618 """
Jon Hallff6b4b22015-02-23 09:25:15 -08002619 import json
2620 hostResults = main.TRUE
Jon Hallff6b4b22015-02-23 09:25:15 -08002621 for onosHost in hostsJson:
2622 onosMAC = onosHost[ 'mac' ].lower()
2623 match = False
Jon Halld80cc142015-07-06 13:36:05 -07002624 for mnHost, info in hosts.iteritems():
2625 for mnIntf in info[ 'interfaces' ]:
2626 if onosMAC == mnIntf[ 'mac' ].lower():
Jon Hallff6b4b22015-02-23 09:25:15 -08002627 match = True
2628 for ip in mnIntf[ 'ips' ]:
Jon Hallfeff3082015-05-19 10:23:26 -07002629 if ip in onosHost[ 'ipAddresses' ]:
Jon Hallff6b4b22015-02-23 09:25:15 -08002630 pass # all is well
2631 else:
2632 # misssing ip
Jon Halld80cc142015-07-06 13:36:05 -07002633 main.log.error( "ONOS host " +
2634 onosHost[ 'id' ] +
2635 " has a different IP(" +
Jon Hallafa8a472015-06-12 14:02:42 -07002636 str( onosHost[ 'ipAddresses' ] ) +
2637 ") than the Mininet host(" +
Jon Halld80cc142015-07-06 13:36:05 -07002638 str( ip ) +
2639 ")." )
Jon Hallff6b4b22015-02-23 09:25:15 -08002640 output = json.dumps(
Jon Halld80cc142015-07-06 13:36:05 -07002641 onosHost,
2642 sort_keys=True,
2643 indent=4,
2644 separators=( ',', ': ' ) )
Jon Hallff6b4b22015-02-23 09:25:15 -08002645 main.log.info( output )
2646 hostResults = main.FALSE
2647 if not match:
2648 hostResults = main.FALSE
2649 main.log.error( "ONOS host " + onosHost[ 'id' ] + " has no " +
2650 "corresponding Mininet host." )
2651 output = json.dumps( onosHost,
2652 sort_keys=True,
2653 indent=4,
2654 separators=( ',', ': ' ) )
2655 main.log.info( output )
Jon Hallff6b4b22015-02-23 09:25:15 -08002656 return hostResults
2657
Jon Hallafa8a472015-06-12 14:02:42 -07002658 def getHostsOld( self ):
Jon Hall7eb38402015-01-08 17:19:54 -08002659 """
2660 Returns a list of all hosts
2661 Don't ask questions just use it"""
2662 self.handle.sendline( "" )
2663 self.handle.expect( "mininet>" )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002664
Jon Hall7eb38402015-01-08 17:19:54 -08002665 self.handle.sendline( "py [ host.name for host in net.hosts ]" )
2666 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002667
kelvin-onlabd3b64892015-01-20 13:26:24 -08002668 handlePy = self.handle.before
2669 handlePy = handlePy.split( "]\r\n", 1 )[ 1 ]
2670 handlePy = handlePy.rstrip()
admin2a9548d2014-06-17 14:08:07 -07002671
Jon Hall7eb38402015-01-08 17:19:54 -08002672 self.handle.sendline( "" )
2673 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002674
kelvin-onlabd3b64892015-01-20 13:26:24 -08002675 hostStr = handlePy.replace( "]", "" )
2676 hostStr = hostStr.replace( "'", "" )
2677 hostStr = hostStr.replace( "[", "" )
kelvin-onlab2ccad6e2015-05-18 10:36:54 -07002678 hostStr = hostStr.replace( " ", "" )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002679 hostList = hostStr.split( "," )
andrewonlab3f0a4af2014-10-17 12:25:14 -04002680
kelvin-onlabd3b64892015-01-20 13:26:24 -08002681 return hostList
adminbae64d82013-08-01 10:50:15 -07002682
kelvin-onlabfa6ada82015-06-11 13:06:24 -07002683 def getSwitch( self ):
2684 """
2685 Returns a list of all switches
2686 Again, don't ask question just use it...
2687 """
2688 # get host list...
2689 hostList = self.getHosts()
2690 # Make host set
2691 hostSet = set( hostList )
2692
2693 # Getting all the nodes in mininet
2694 self.handle.sendline( "" )
2695 self.handle.expect( "mininet>" )
2696
2697 self.handle.sendline( "py [ node.name for node in net.values() ]" )
2698 self.handle.expect( "mininet>" )
2699
2700 handlePy = self.handle.before
2701 handlePy = handlePy.split( "]\r\n", 1 )[ 1 ]
2702 handlePy = handlePy.rstrip()
2703
2704 self.handle.sendline( "" )
2705 self.handle.expect( "mininet>" )
2706
2707 nodesStr = handlePy.replace( "]", "" )
2708 nodesStr = nodesStr.replace( "'", "" )
2709 nodesStr = nodesStr.replace( "[", "" )
2710 nodesStr = nodesStr.replace( " ", "" )
2711 nodesList = nodesStr.split( "," )
2712
2713 nodesSet = set( nodesList )
2714 # discarding default controller(s) node
2715 nodesSet.discard( 'c0' )
2716 nodesSet.discard( 'c1' )
2717 nodesSet.discard( 'c2' )
2718
2719 switchSet = nodesSet - hostSet
2720 switchList = list( switchSet )
2721
2722 return switchList
2723
Jon Hall7eb38402015-01-08 17:19:54 -08002724 def update( self ):
2725 """
2726 updates the port address and status information for
2727 each port in mn"""
2728 # TODO: Add error checking. currently the mininet command has no output
Jon Hallefbd9792015-03-05 16:11:36 -08002729 main.log.info( "Updating MN port information" )
Jon Hallb1290e82014-11-18 16:17:48 -05002730 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002731 self.handle.sendline( "" )
2732 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002733
Jon Hall7eb38402015-01-08 17:19:54 -08002734 self.handle.sendline( "update" )
2735 self.handle.expect( "update" )
2736 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002737
Jon Hall7eb38402015-01-08 17:19:54 -08002738 self.handle.sendline( "" )
2739 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002740
Jon Hallb1290e82014-11-18 16:17:48 -05002741 return main.TRUE
2742 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002743 main.log.error( self.name + ": EOF exception found" )
2744 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05002745 main.cleanup()
2746 main.exit()
2747
Jon Halld80cc142015-07-06 13:36:05 -07002748 def assignVLAN( self, host, intf, vlan ):
kaouthera3f13ca22015-05-05 15:01:41 -07002749 """
2750 Add vlan tag to a host.
2751 Dependencies:
2752 This class depends on the "vlan" package
2753 $ sudo apt-get install vlan
2754 Configuration:
2755 Load the 8021q module into the kernel
2756 $sudo modprobe 8021q
2757
2758 To make this setup permanent:
2759 $ sudo su -c 'echo "8021q" >> /etc/modules'
2760 """
2761 if self.handle:
2762 try:
Jon Halld80cc142015-07-06 13:36:05 -07002763 # get the ip address of the host
2764 main.log.info( "Get the ip address of the host" )
2765 ipaddr = self.getIPAddress( host )
2766 print repr( ipaddr )
kaouthera3f13ca22015-05-05 15:01:41 -07002767
Jon Halld80cc142015-07-06 13:36:05 -07002768 # remove IP from interface intf
2769 # Ex: h1 ifconfig h1-eth0 inet 0
2770 main.log.info( "Remove IP from interface " )
2771 cmd2 = host + " ifconfig " + intf + " " + " inet 0 "
2772 self.handle.sendline( cmd2 )
2773 self.handle.expect( "mininet>" )
2774 response = self.handle.before
2775 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002776
Jon Halld80cc142015-07-06 13:36:05 -07002777 # create VLAN interface
2778 # Ex: h1 vconfig add h1-eth0 100
2779 main.log.info( "Create Vlan" )
2780 cmd3 = host + " vconfig add " + intf + " " + vlan
2781 self.handle.sendline( cmd3 )
2782 self.handle.expect( "mininet>" )
2783 response = self.handle.before
2784 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002785
Jon Halld80cc142015-07-06 13:36:05 -07002786 # assign the host's IP to the VLAN interface
2787 # Ex: h1 ifconfig h1-eth0.100 inet 10.0.0.1
2788 main.log.info( "Assign the host IP to the vlan interface" )
2789 vintf = intf + "." + vlan
2790 cmd4 = host + " ifconfig " + vintf + " " + " inet " + ipaddr
2791 self.handle.sendline( cmd4 )
2792 self.handle.expect( "mininet>" )
2793 response = self.handle.before
2794 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002795
2796 return main.TRUE
2797 except pexpect.EOF:
2798 main.log.error( self.name + ": EOF exception found" )
2799 main.log.error( self.name + ": " + self.handle.before )
2800 return main.FALSE
2801
Jon Hall892818c2015-10-20 17:58:34 -07002802 def createHostComponent( self, name ):
2803 """
2804 Creates a new mininet cli component with the same parameters as self.
2805 This new component is intended to be used to login to the hosts created
2806 by mininet.
2807
2808 Arguments:
2809 name - The string of the name of this component. The new component
2810 will be assigned to main.<name> .
2811 In addition, main.<name>.name = str( name )
2812 """
2813 try:
2814 # look to see if this component already exists
2815 getattr( main, name )
2816 except AttributeError:
2817 # namespace is clear, creating component
2818 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
2819 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
2820 main.componentInit( name )
2821 except Exception:
2822 main.log.exception( self.name + ": Uncaught exception!" )
2823 main.cleanup()
2824 main.exit()
2825 else:
2826 # namespace is not clear!
2827 main.log.error( name + " component already exists!" )
2828 # FIXME: Should we exit here?
2829 main.cleanup()
2830 main.exit()
2831
2832 def removeHostComponent( self, name ):
2833 """
2834 Remove host component
2835 Arguments:
2836 name - The string of the name of the component to delete.
2837 """
2838 try:
2839 # Get host component
2840 component = getattr( main, name )
2841 except AttributeError:
2842 main.log.error( "Component " + name + " does not exist." )
2843 return
2844 try:
2845 # Disconnect from component
2846 component.disconnect()
2847 # Delete component
2848 delattr( main, name )
2849 # Delete component from ComponentDictionary
2850 del( main.componentDictionary[name] )
2851 except Exception:
2852 main.log.exception( self.name + ": Uncaught exception!" )
2853 main.cleanup()
2854 main.exit()
2855
2856 def startHostCli( self, host=None ):
2857 """
2858 Use the mininet m utility to connect to the host's cli
2859 """
2860 # These are fields that can be used by scapy packets. Initialized to None
2861 self.hostIp = None
2862 self.hostMac = None
2863 try:
2864 if not host:
2865 host = self.name
2866 self.handle.sendline( self.home + "/util/m " + host )
2867 self.handle.expect( self.hostPrompt )
2868 return main.TRUE
2869 except pexpect.TIMEOUT:
2870 main.log.exception( self.name + ": Command timed out" )
2871 return main.FALSE
2872 except pexpect.EOF:
2873 main.log.exception( self.name + ": connection closed." )
2874 main.cleanup()
2875 main.exit()
2876 except Exception:
2877 main.log.exception( self.name + ": Uncaught exception!" )
2878 main.cleanup()
2879 main.exit()
2880
GlennRC956ea742015-11-05 16:14:15 -08002881 def startScapy( self, mplsPath="" ):
Jon Hall892818c2015-10-20 17:58:34 -07002882 """
2883 Start the Scapy cli
GlennRC956ea742015-11-05 16:14:15 -08002884 optional:
2885 mplsPath - The path where the MPLS class is located
2886 NOTE: This can be a relative path from the user's home dir
Jon Hall892818c2015-10-20 17:58:34 -07002887 """
GlennRC956ea742015-11-05 16:14:15 -08002888 mplsLines = ['import imp',
2889 'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format(mplsPath),
2890 'from mplsClass import MPLS',
2891 'bind_layers(Ether, MPLS, type = 0x8847)',
2892 'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
2893 'bind_layers(MPLS, IP)']
2894
Jon Hall892818c2015-10-20 17:58:34 -07002895 try:
2896 self.handle.sendline( "scapy" )
2897 self.handle.expect( self.scapyPrompt )
2898 self.handle.sendline( "conf.color_theme = NoTheme()" )
2899 self.handle.expect( self.scapyPrompt )
GlennRC956ea742015-11-05 16:14:15 -08002900 if mplsPath:
2901 main.log.info( "Adding MPLS class" )
2902 main.log.info( "MPLS class path: " + mplsPath )
2903 for line in mplsLines:
2904 main.log.info( "sending line: " + line )
2905 self.handle.sendline( line )
2906 self.handle.expect( self.scapyPrompt )
Jon Hall892818c2015-10-20 17:58:34 -07002907 return main.TRUE
2908 except pexpect.TIMEOUT:
2909 main.log.exception( self.name + ": Command timed out" )
2910 return main.FALSE
2911 except pexpect.EOF:
2912 main.log.exception( self.name + ": connection closed." )
2913 main.cleanup()
2914 main.exit()
2915 except Exception:
2916 main.log.exception( self.name + ": Uncaught exception!" )
2917 main.cleanup()
2918 main.exit()
2919
2920 def stopScapy( self ):
2921 """
2922 Exit the Scapy cli
2923 """
2924 try:
2925 self.handle.sendline( "exit()" )
2926 self.handle.expect( self.hostPrompt )
2927 return main.TRUE
2928 except pexpect.TIMEOUT:
2929 main.log.exception( self.name + ": Command timed out" )
2930 return main.FALSE
2931 except pexpect.EOF:
2932 main.log.exception( self.name + ": connection closed." )
2933 main.cleanup()
2934 main.exit()
2935 except Exception:
2936 main.log.exception( self.name + ": Uncaught exception!" )
2937 main.cleanup()
2938 main.exit()
2939
2940 def buildEther( self, **kwargs ):
2941 """
2942 Build an Ethernet frame
2943
2944 Will create a frame class with the given options. If a field is
2945 left blank it will default to the below value unless it is
2946 overwritten by the next frame.
2947 Default frame:
2948 ###[ Ethernet ]###
2949 dst= ff:ff:ff:ff:ff:ff
2950 src= 00:00:00:00:00:00
2951 type= 0x800
2952
2953 Returns main.TRUE or main.FALSE on error
2954 """
2955 try:
2956 # Set the Ethernet frame
2957 cmd = 'ether = Ether( '
2958 options = []
2959 for key, value in kwargs.iteritems():
2960 if isinstance( value, str ):
2961 value = '"' + value + '"'
2962 options.append( str( key ) + "=" + str( value ) )
2963 cmd += ", ".join( options )
2964 cmd += ' )'
2965 self.handle.sendline( cmd )
2966 self.handle.expect( self.scapyPrompt )
2967 if "Traceback" in self.handle.before:
2968 # KeyError, SyntaxError, ...
2969 main.log.error( "Error in sending command: " + self.handle.before )
2970 return main.FALSE
2971 self.handle.sendline( "packet = ether" )
2972 self.handle.expect( self.scapyPrompt )
2973 if "Traceback" in self.handle.before:
2974 # KeyError, SyntaxError, ...
2975 main.log.error( "Error in sending command: " + self.handle.before )
2976 return main.FALSE
2977 return main.TRUE
2978 except pexpect.TIMEOUT:
2979 main.log.exception( self.name + ": Command timed out" )
2980 return main.FALSE
2981 except pexpect.EOF:
2982 main.log.exception( self.name + ": connection closed." )
2983 main.cleanup()
2984 main.exit()
2985 except Exception:
2986 main.log.exception( self.name + ": Uncaught exception!" )
2987 main.cleanup()
2988 main.exit()
2989
2990 def buildIP( self, **kwargs ):
2991 """
2992 Build an IP frame
2993
2994 Will create a frame class with the given options. If a field is
2995 left blank it will default to the below value unless it is
2996 overwritten by the next frame.
2997 Default frame:
2998 ###[ IP ]###
2999 version= 4
3000 ihl= None
3001 tos= 0x0
3002 len= None
3003 id= 1
3004 flags=
3005 frag= 0
3006 ttl= 64
3007 proto= hopopt
3008 chksum= None
3009 src= 127.0.0.1
3010 dst= 127.0.0.1
3011 \options\
3012
3013 Returns main.TRUE or main.FALSE on error
3014 """
3015 try:
3016 # Set the IP frame
3017 cmd = 'ip = IP( '
3018 options = []
3019 for key, value in kwargs.iteritems():
3020 if isinstance( value, str ):
3021 value = '"' + value + '"'
3022 options.append( str( key ) + "=" + str( value ) )
3023 cmd += ", ".join( options )
3024 cmd += ' )'
3025 self.handle.sendline( cmd )
3026 self.handle.expect( self.scapyPrompt )
3027 if "Traceback" in self.handle.before:
3028 # KeyError, SyntaxError, ...
3029 main.log.error( "Error in sending command: " + self.handle.before )
3030 return main.FALSE
3031 self.handle.sendline( "packet = ether/ip" )
3032 self.handle.expect( self.scapyPrompt )
3033 if "Traceback" in self.handle.before:
3034 # KeyError, SyntaxError, ...
3035 main.log.error( "Error in sending command: " + self.handle.before )
3036 return main.FALSE
3037 return main.TRUE
3038 except pexpect.TIMEOUT:
3039 main.log.exception( self.name + ": Command timed out" )
3040 return main.FALSE
3041 except pexpect.EOF:
3042 main.log.exception( self.name + ": connection closed." )
3043 main.cleanup()
3044 main.exit()
3045 except Exception:
3046 main.log.exception( self.name + ": Uncaught exception!" )
3047 main.cleanup()
3048 main.exit()
3049
3050 def buildIPv6( self, **kwargs ):
3051 """
3052 Build an IPv6 frame
3053
3054 Will create a frame class with the given options. If a field is
3055 left blank it will default to the below value unless it is
3056 overwritten by the next frame.
3057 Default frame:
3058 ###[ IPv6 ]###
3059 version= 6
3060 tc= 0
3061 fl= 0
3062 plen= None
3063 nh= No Next Header
3064 hlim= 64
3065 src= ::1
3066 dst= ::1
3067
3068 Returns main.TRUE or main.FALSE on error
3069 """
3070 try:
3071 # Set the IPv6 frame
3072 cmd = 'ipv6 = IPv6( '
3073 options = []
3074 for key, value in kwargs.iteritems():
3075 if isinstance( value, str ):
3076 value = '"' + value + '"'
3077 options.append( str( key ) + "=" + str( value ) )
3078 cmd += ", ".join( options )
3079 cmd += ' )'
3080 self.handle.sendline( cmd )
3081 self.handle.expect( self.scapyPrompt )
3082 if "Traceback" in self.handle.before:
3083 # KeyError, SyntaxError, ...
3084 main.log.error( "Error in sending command: " + self.handle.before )
3085 return main.FALSE
3086 self.handle.sendline( "packet = ether/ipv6" )
3087 self.handle.expect( self.scapyPrompt )
3088 if "Traceback" in self.handle.before:
3089 # KeyError, SyntaxError, ...
3090 main.log.error( "Error in sending command: " + self.handle.before )
3091 return main.FALSE
3092 return main.TRUE
3093 except pexpect.TIMEOUT:
3094 main.log.exception( self.name + ": Command timed out" )
3095 return main.FALSE
3096 except pexpect.EOF:
3097 main.log.exception( self.name + ": connection closed." )
3098 main.cleanup()
3099 main.exit()
3100 except Exception:
3101 main.log.exception( self.name + ": Uncaught exception!" )
3102 main.cleanup()
3103 main.exit()
3104
3105 def buildTCP( self, ipVersion=4, **kwargs ):
3106 """
3107 Build an TCP frame
3108
3109 Will create a frame class with the given options. If a field is
3110 left blank it will default to the below value unless it is
3111 overwritten by the next frame.
3112
GlennRC956ea742015-11-05 16:14:15 -08003113 NOTE: Some arguments require quotes around them. It's up to you to
3114 know which ones and to add them yourself. Arguments with an asterisk
3115 do not need quotes.
3116
Jon Hall892818c2015-10-20 17:58:34 -07003117 Options:
3118 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
3119 frame to use to encapsulate into
3120 Default frame:
3121 ###[ TCP ]###
GlennRC956ea742015-11-05 16:14:15 -08003122 sport= ftp_data *
3123 dport= http *
Jon Hall892818c2015-10-20 17:58:34 -07003124 seq= 0
3125 ack= 0
3126 dataofs= None
3127 reserved= 0
3128 flags= S
3129 window= 8192
3130 chksum= None
3131 urgptr= 0
3132 options= {}
3133
3134 Returns main.TRUE or main.FALSE on error
3135 """
3136 try:
3137 # Set the TCP frame
3138 cmd = 'tcp = TCP( '
3139 options = []
3140 for key, value in kwargs.iteritems():
Jon Hall892818c2015-10-20 17:58:34 -07003141 options.append( str( key ) + "=" + str( value ) )
3142 cmd += ", ".join( options )
3143 cmd += ' )'
3144 self.handle.sendline( cmd )
3145 self.handle.expect( self.scapyPrompt )
3146 if "Traceback" in self.handle.before:
3147 # KeyError, SyntaxError, ...
3148 main.log.error( "Error in sending command: " + self.handle.before )
3149 return main.FALSE
3150 if str( ipVersion ) is '4':
3151 self.handle.sendline( "packet = ether/ip/tcp" )
3152 elif str( ipVersion ) is '6':
3153 self.handle.sendline( "packet = ether/ipv6/tcp" )
3154 else:
3155 main.log.error( "Unrecognized option for ipVersion, given " +
3156 repr( ipVersion ) )
3157 return main.FALSE
3158 self.handle.expect( self.scapyPrompt )
3159 if "Traceback" in self.handle.before:
3160 # KeyError, SyntaxError, ...
3161 main.log.error( "Error in sending command: " + self.handle.before )
3162 return main.FALSE
3163 return main.TRUE
3164 except pexpect.TIMEOUT:
3165 main.log.exception( self.name + ": Command timed out" )
3166 return main.FALSE
3167 except pexpect.EOF:
3168 main.log.exception( self.name + ": connection closed." )
3169 main.cleanup()
3170 main.exit()
3171 except Exception:
3172 main.log.exception( self.name + ": Uncaught exception!" )
3173 main.cleanup()
3174 main.exit()
3175
3176 def buildUDP( self, ipVersion=4, **kwargs ):
3177 """
3178 Build an UDP frame
3179
3180 Will create a frame class with the given options. If a field is
3181 left blank it will default to the below value unless it is
3182 overwritten by the next frame.
3183
GlennRC956ea742015-11-05 16:14:15 -08003184 NOTE: Some arguments require quotes around them. It's up to you to
3185 know which ones and to add them yourself. Arguments with an asterisk
3186 do not need quotes.
3187
Jon Hall892818c2015-10-20 17:58:34 -07003188 Options:
3189 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
3190 frame to use to encapsulate into
3191 Default frame:
3192 ###[ UDP ]###
GlennRC956ea742015-11-05 16:14:15 -08003193 sport= domain *
3194 dport= domain *
Jon Hall892818c2015-10-20 17:58:34 -07003195 len= None
3196 chksum= None
3197
3198 Returns main.TRUE or main.FALSE on error
3199 """
3200 try:
3201 # Set the UDP frame
3202 cmd = 'udp = UDP( '
3203 options = []
3204 for key, value in kwargs.iteritems():
Jon Hall892818c2015-10-20 17:58:34 -07003205 options.append( str( key ) + "=" + str( value ) )
3206 cmd += ", ".join( options )
3207 cmd += ' )'
3208 self.handle.sendline( cmd )
3209 self.handle.expect( self.scapyPrompt )
3210 if "Traceback" in self.handle.before:
3211 # KeyError, SyntaxError, ...
3212 main.log.error( "Error in sending command: " + self.handle.before )
3213 return main.FALSE
3214 if str( ipVersion ) is '4':
3215 self.handle.sendline( "packet = ether/ip/udp" )
3216 elif str( ipVersion ) is '6':
3217 self.handle.sendline( "packet = ether/ipv6/udp" )
3218 else:
3219 main.log.error( "Unrecognized option for ipVersion, given " +
3220 repr( ipVersion ) )
3221 return main.FALSE
3222 self.handle.expect( self.scapyPrompt )
3223 if "Traceback" in self.handle.before:
3224 # KeyError, SyntaxError, ...
3225 main.log.error( "Error in sending command: " + self.handle.before )
3226 return main.FALSE
3227 return main.TRUE
3228 except pexpect.TIMEOUT:
3229 main.log.exception( self.name + ": Command timed out" )
3230 return main.FALSE
3231 except pexpect.EOF:
3232 main.log.exception( self.name + ": connection closed." )
3233 main.cleanup()
3234 main.exit()
3235 except Exception:
3236 main.log.exception( self.name + ": Uncaught exception!" )
3237 main.cleanup()
3238 main.exit()
3239
3240 def buildICMP( self, **kwargs ):
3241 """
3242 Build an ICMP frame
3243
3244 Will create a frame class with the given options. If a field is
3245 left blank it will default to the below value unless it is
3246 overwritten by the next frame.
3247 Default frame:
3248 ###[ ICMP ]###
3249 type= echo-request
3250 code= 0
3251 chksum= None
3252 id= 0x0
3253 seq= 0x0
3254
3255 Returns main.TRUE or main.FALSE on error
3256 """
3257 try:
3258 # Set the ICMP frame
3259 cmd = 'icmp = ICMP( '
3260 options = []
3261 for key, value in kwargs.iteritems():
3262 if isinstance( value, str ):
3263 value = '"' + value + '"'
3264 options.append( str( key ) + "=" + str( value ) )
3265 cmd += ", ".join( options )
3266 cmd += ' )'
3267 self.handle.sendline( cmd )
3268 self.handle.expect( self.scapyPrompt )
3269 if "Traceback" in self.handle.before:
3270 # KeyError, SyntaxError, ...
3271 main.log.error( "Error in sending command: " + self.handle.before )
3272 return main.FALSE
3273 self.handle.sendline( "packet = ether/ip/icmp" )
3274 self.handle.expect( self.scapyPrompt )
3275 if "Traceback" in self.handle.before:
3276 # KeyError, SyntaxError, ...
3277 main.log.error( "Error in sending command: " + self.handle.before )
3278 return main.FALSE
3279 return main.TRUE
3280 except pexpect.TIMEOUT:
3281 main.log.exception( self.name + ": Command timed out" )
3282 return main.FALSE
3283 except pexpect.EOF:
3284 main.log.exception( self.name + ": connection closed." )
3285 main.cleanup()
3286 main.exit()
3287 except Exception:
3288 main.log.exception( self.name + ": Uncaught exception!" )
3289 main.cleanup()
3290 main.exit()
3291
GlennRC073e8bc2015-10-27 17:11:28 -07003292 def sendPacket( self, iface=None, packet=None, timeout=1 ):
Jon Hall892818c2015-10-20 17:58:34 -07003293 """
3294 Send a packet with either the given scapy packet command, or use the
3295 packet saved in the variable 'packet'.
3296
3297 Examples of a valid string for packet:
3298
3299 Simple IP packet
3300 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
3301
3302 A Ping with two vlan tags
3303 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
3304 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
3305
3306 Returns main.TRUE or main.FALSE on error
3307 """
3308 try:
3309 # TODO: add all params, or use kwargs
3310 sendCmd = 'srp( '
3311 if packet:
3312 sendCmd += packet
3313 else:
3314 sendCmd += "packet"
GlennRC073e8bc2015-10-27 17:11:28 -07003315 if iface:
3316 sendCmd += ", iface='{}'".format( iface )
3317
Jon Hall892818c2015-10-20 17:58:34 -07003318 sendCmd += ', timeout=' + str( timeout ) + ')'
3319 self.handle.sendline( sendCmd )
3320 self.handle.expect( self.scapyPrompt )
3321 if "Traceback" in self.handle.before:
3322 # KeyError, SyntaxError, ...
3323 main.log.error( "Error in sending command: " + self.handle.before )
3324 return main.FALSE
3325 # TODO: Check # of packets sent?
3326 return main.TRUE
3327 except pexpect.TIMEOUT:
3328 main.log.exception( self.name + ": Command timed out" )
3329 return main.FALSE
3330 except pexpect.EOF:
3331 main.log.exception( self.name + ": connection closed." )
3332 main.cleanup()
3333 main.exit()
3334 except Exception:
3335 main.log.exception( self.name + ": Uncaught exception!" )
3336 main.cleanup()
3337 main.exit()
3338
3339 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
3340 """
3341 Listen for packets using the given filters
3342
3343 Options:
3344 ifaceName - the name of the interface to listen on. If none is given,
3345 defaults to <host name>-eth0
3346 pktFilter - A string in Berkeley Packet Filter (BPF) format which
3347 specifies which packets to sniff
3348 sniffCount - The number of matching packets to capture before returning
3349
3350 Returns main.TRUE or main.FALSE on error
3351 """
3352 try:
3353 # TODO: add all params, or use kwargs
3354 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
3355 # Set interface
3356 self.handle.sendline( ' conf.iface = "' + ifaceName + '"' )
3357 self.handle.expect( self.scapyPrompt )
3358 cmd = 'pkt = sniff(count = ' + str( sniffCount ) +\
3359 ', filter = "' + str( pktFilter ) + '")'
3360 self.handle.sendline( cmd )
3361 self.handle.expect( '"\)\r\n' )
3362 # TODO: parse this?
3363 return main.TRUE
3364 except pexpect.TIMEOUT:
3365 main.log.exception( self.name + ": Command timed out" )
3366 return main.FALSE
3367 except pexpect.EOF:
3368 main.log.exception( self.name + ": connection closed." )
3369 main.cleanup()
3370 main.exit()
3371 except Exception:
3372 main.log.exception( self.name + ": Uncaught exception!" )
3373 main.cleanup()
3374 main.exit()
3375
3376 def checkFilter( self ):
3377 """
3378 Check that a filter returned and returns the reponse
3379 """
3380 try:
3381 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ] )
3382 if i == 0:
3383 return main.TRUE
3384 else:
3385 return main.FALSE
3386 except pexpect.EOF:
3387 main.log.exception( self.name + ": connection closed." )
3388 main.cleanup()
3389 main.exit()
3390 except Exception:
3391 main.log.exception( self.name + ": Uncaught exception!" )
3392 main.cleanup()
3393 main.exit()
3394
3395 def killFilter( self ):
3396 """
3397 Kill a scapy filter
3398 """
3399 try:
3400 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
3401 self.handle.expect( self.scapyPrompt )
3402 return self.handle.before
3403 except pexpect.TIMEOUT:
3404 main.log.exception( self.name + ": Command timed out" )
3405 return None
3406 except pexpect.EOF:
3407 main.log.exception( self.name + ": connection closed." )
3408 main.cleanup()
3409 main.exit()
3410 except Exception:
3411 main.log.exception( self.name + ": Uncaught exception!" )
3412 main.cleanup()
3413 main.exit()
3414
3415 def readPackets( self ):
3416 """
3417 Read all the packets captured by the previous filter
3418 """
3419 try:
3420 self.handle.sendline( "for p in pkt: p \n")
3421 self.handle.expect( "for p in pkt: p \r\n... \r\n" )
3422 self.handle.expect( self.scapyPrompt )
3423 except pexpect.TIMEOUT:
3424 main.log.exception( self.name + ": Command timed out" )
3425 return None
3426 except pexpect.EOF:
3427 main.log.exception( self.name + ": connection closed." )
3428 main.cleanup()
3429 main.exit()
3430 except Exception:
3431 main.log.exception( self.name + ": Uncaught exception!" )
3432 main.cleanup()
3433 main.exit()
3434 return self.handle.before
3435
3436 def updateSelf( self ):
3437 """
3438 Updates local MAC and IP fields
3439 """
3440 self.hostMac = self.getMac()
3441 self.hostIp = self.getIp()
3442
3443 def getMac( self, ifaceName=None ):
3444 """
3445 Save host's MAC address
3446 """
3447 try:
3448 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
3449 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
3450 self.handle.sendline( cmd )
3451 self.handle.expect( self.scapyPrompt )
3452 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
3453 match = re.search( pattern, self.handle.before )
3454 if match:
3455 return match.group()
3456 else:
3457 # the command will have an exception if iface doesn't exist
3458 return None
3459 except pexpect.TIMEOUT:
3460 main.log.exception( self.name + ": Command timed out" )
3461 return None
3462 except pexpect.EOF:
3463 main.log.exception( self.name + ": connection closed." )
3464 main.cleanup()
3465 main.exit()
3466 except Exception:
3467 main.log.exception( self.name + ": Uncaught exception!" )
3468 main.cleanup()
3469 main.exit()
3470
3471 def getIp( self, ifaceName=None ):
3472 """
3473 Save host's IP address
3474 """
3475 try:
3476 ifaceName = ifaceName if ifaceName else self.name + "-eth0"
3477 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
3478 self.handle.sendline( cmd )
3479 self.handle.expect( self.scapyPrompt )
3480
3481 pattern = r'(((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9]))'
3482 match = re.search( pattern, self.handle.before )
3483 if match:
3484 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
3485 return match.group()
3486 else:
3487 return None
3488 except pexpect.TIMEOUT:
3489 main.log.exception( self.name + ": Command timed out" )
3490 return None
3491 except pexpect.EOF:
3492 main.log.exception( self.name + ": connection closed." )
3493 main.cleanup()
3494 main.exit()
3495 except Exception:
3496 main.log.exception( self.name + ": Uncaught exception!" )
3497 main.cleanup()
3498 main.exit()
3499
adminbae64d82013-08-01 10:50:15 -07003500if __name__ != "__main__":
kelvin-onlab50907142015-04-01 13:37:45 -07003501 sys.modules[ __name__ ] = MininetCliDriver()