blob: 6b4efddd9766b56318c435fa65809cbe19a70fb1 [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
Jon Hall7eb38402015-01-08 17:19:54 -08002"""
adminbae64d82013-08-01 10:50:15 -07003Created on 26-Oct-2012
4
Jon Hallbe6dfc42015-01-12 17:37:25 -08005author: Anil Kumar ( anilkumar.s@paxterrasolutions.com )
adminbae64d82013-08-01 10:50:15 -07006
7
Jon Hall7eb38402015-01-08 17:19:54 -08008TestON is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 of the License, or
11( at your option ) any later version.
adminbae64d82013-08-01 10:50:15 -070012
Jon Hall7eb38402015-01-08 17:19:54 -080013TestON is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
adminbae64d82013-08-01 10:50:15 -070017
Jon Hall7eb38402015-01-08 17:19:54 -080018You should have received a copy of the GNU General Public License
19along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070020
Jon Hallbe6dfc42015-01-12 17:37:25 -080021MininetCliDriver is the basic driver which will handle the Mininet functions
22
23Some functions rely on a modified version of Mininet. These functions
24should all be noted in the comments. To get this MN version run these commands
25from within your Mininet folder:
Jon Hall272a4db2015-01-12 17:43:48 -080026 git remote add jhall11 https://github.com/jhall11/mininet.git
Jon Hallbe6dfc42015-01-12 17:37:25 -080027 git fetch jhall11
Jon Hall272a4db2015-01-12 17:43:48 -080028 git checkout -b dynamic_topo remotes/jhall11/dynamic_topo
Jon Hallbe6dfc42015-01-12 17:37:25 -080029 git pull
30
Jon Hall272a4db2015-01-12 17:43:48 -080031
32 Note that you may need to run 'sudo make develop' if your mnexec.c file
Jon Hallbe6dfc42015-01-12 17:37:25 -080033changed when switching branches."""
adminbae64d82013-08-01 10:50:15 -070034import pexpect
adminbae64d82013-08-01 10:50:15 -070035import re
36import sys
kelvin-onlabfa6ada82015-06-11 13:06:24 -070037import types
kelvin-onlaba4074292015-07-09 15:19:49 -070038import os
Jon Hall1ccf82c2014-10-15 14:55:16 -040039from math import pow
adminbae64d82013-08-01 10:50:15 -070040from drivers.common.cli.emulatordriver import Emulator
adminbae64d82013-08-01 10:50:15 -070041
Jon Hall7eb38402015-01-08 17:19:54 -080042
kelvin-onlab50907142015-04-01 13:37:45 -070043class MininetCliDriver( Emulator ):
Jon Hall7eb38402015-01-08 17:19:54 -080044
45 """
46 MininetCliDriver is the basic driver which will handle
47 the Mininet functions"""
48 def __init__( self ):
49 super( Emulator, self ).__init__()
adminbae64d82013-08-01 10:50:15 -070050 self.handle = self
Jon Hallefbd9792015-03-05 16:11:36 -080051 self.name = None
kelvin-onlabd9e23de2015-08-06 10:34:44 -070052 self.home = None
Jon Hall7eb38402015-01-08 17:19:54 -080053 self.wrapped = sys.modules[ __name__ ]
adminbae64d82013-08-01 10:50:15 -070054 self.flag = 0
Jon Hall892818c2015-10-20 17:58:34 -070055 # TODO: Refactor driver to use these everywhere
56 self.mnPrompt = "mininet>"
57 self.hostPrompt = "~#"
58 self.bashPrompt = "\$"
59 self.scapyPrompt = ">>>"
adminbae64d82013-08-01 10:50:15 -070060
Jon Hall7eb38402015-01-08 17:19:54 -080061 def connect( self, **connectargs ):
62 """
63 Here the main is the TestON instance after creating
64 all the log handles."""
kelvin-onlaba1484582015-02-02 15:46:20 -080065 try:
66 for key in connectargs:
67 vars( self )[ key ] = connectargs[ key ]
kelvin-onlabd9e23de2015-08-06 10:34:44 -070068 self.home = "~/mininet"
kelvin-onlaba1484582015-02-02 15:46:20 -080069 self.name = self.options[ 'name' ]
kelvin-onlabd9e23de2015-08-06 10:34:44 -070070 for key in self.options:
71 if key == "home":
72 self.home = self.options[ 'home' ]
73 break
74 if self.home is None or self.home == "":
75 self.home = "~/mininet"
kelvin-onlaba4074292015-07-09 15:19:49 -070076
77 try:
Jon Hall892818c2015-10-20 17:58:34 -070078 if os.getenv( str( self.ip_address ) ) is not None:
kelvin-onlaba4074292015-07-09 15:19:49 -070079 self.ip_address = os.getenv( str( self.ip_address ) )
80 else:
81 main.log.info( self.name +
82 ": Trying to connect to " +
83 self.ip_address )
84
85 except KeyError:
86 main.log.info( "Invalid host name," +
87 " connecting to local host instead" )
88 self.ip_address = 'localhost'
89 except Exception as inst:
90 main.log.error( "Uncaught exception: " + str( inst ) )
91
kelvin-onlaba1484582015-02-02 15:46:20 -080092 self.handle = super(
kelvin-onlab50907142015-04-01 13:37:45 -070093 MininetCliDriver,
kelvin-onlaba1484582015-02-02 15:46:20 -080094 self ).connect(
95 user_name=self.user_name,
96 ip_address=self.ip_address,
97 port=None,
98 pwd=self.pwd )
Jon Hallfbc828e2015-01-06 17:30:19 -080099
kelvin-onlaba1484582015-02-02 15:46:20 -0800100 if self.handle:
Jon Hallefbd9792015-03-05 16:11:36 -0800101 main.log.info( "Connection successful to the host " +
102 self.user_name +
103 "@" +
104 self.ip_address )
kelvin-onlaba1484582015-02-02 15:46:20 -0800105 return main.TRUE
106 else:
107 main.log.error( "Connection failed to the host " +
Jon Hallefbd9792015-03-05 16:11:36 -0800108 self.user_name +
109 "@" +
110 self.ip_address )
Jon Hallfebb1c72015-03-05 13:30:09 -0800111 main.log.error( "Failed to connect to the Mininet CLI" )
kelvin-onlaba1484582015-02-02 15:46:20 -0800112 return main.FALSE
113 except pexpect.EOF:
114 main.log.error( self.name + ": EOF exception found" )
115 main.log.error( self.name + ": " + self.handle.before )
116 main.cleanup()
117 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -0800118 except Exception:
119 main.log.exception( self.name + ": Uncaught exception!" )
kelvin-onlaba1484582015-02-02 15:46:20 -0800120 main.cleanup()
121 main.exit()
122
kelvin-onlab10e8d392015-06-03 13:53:45 -0700123 def startNet( self, topoFile='', args='', mnCmd='', timeout=120 ):
kelvin-onlab00ac67b2015-02-04 09:52:02 -0800124 """
kelvin-onlabf512e942015-06-08 19:42:59 -0700125 Description:
126 Starts Mininet accepts a topology(.py) file and/or an optional
127 argument, to start the mininet, as a parameter.
128 Can also send regular mininet command to load up desired topology.
129 Eg. Pass in a string 'sudo mn --topo=tree,3,3' to mnCmd
130 Options:
131 topoFile = file path for topology file (.py)
132 args = extra option added when starting the topology from the file
133 mnCmd = Mininet command use to start topology
134 Returns:
135 main.TRUE if the mininet starts successfully, main.FALSE
136 otherwise
kelvin-onlab00ac67b2015-02-04 09:52:02 -0800137 """
Jon Hall7eb38402015-01-08 17:19:54 -0800138 if self.handle:
Jon Hall689d8e42015-04-03 13:59:24 -0700139 # make sure old networks are cleaned up
140 main.log.info( self.name +
141 ": Clearing any residual state or processes" )
Jon Hall7eb38402015-01-08 17:19:54 -0800142 self.handle.sendline( "sudo mn -c" )
143 i = self.handle.expect( [ 'password\sfor\s',
144 'Cleanup\scomplete',
145 pexpect.EOF,
146 pexpect.TIMEOUT ],
kelvin-onlaba1484582015-02-02 15:46:20 -0800147 timeout )
Jon Hall7eb38402015-01-08 17:19:54 -0800148 if i == 0:
Jon Hall689d8e42015-04-03 13:59:24 -0700149 # Sudo asking for password
Jon Hall7eb38402015-01-08 17:19:54 -0800150 main.log.info( self.name + ": Sending sudo password" )
151 self.handle.sendline( self.pwd )
Jon Hallefbd9792015-03-05 16:11:36 -0800152 i = self.handle.expect( [ '%s:' % self.user,
Jon Hall7eb38402015-01-08 17:19:54 -0800153 '\$',
154 pexpect.EOF,
155 pexpect.TIMEOUT ],
kelvin-onlaba1484582015-02-02 15:46:20 -0800156 timeout )
Jon Hall7eb38402015-01-08 17:19:54 -0800157 if i == 1:
158 main.log.info( self.name + ": Clean" )
159 elif i == 2:
160 main.log.error( self.name + ": Connection terminated" )
161 elif i == 3: # timeout
Jon Hall689d8e42015-04-03 13:59:24 -0700162 main.log.error( self.name + ": Something while cleaning " +
163 "Mininet took too long... " )
164 # Craft the string to start mininet
165 cmdString = "sudo "
kelvin-onlab10e8d392015-06-03 13:53:45 -0700166 if not mnCmd:
167 if topoFile is None or topoFile == '': # If no file is given
168 main.log.info( self.name + ": building fresh Mininet" )
169 cmdString += "mn "
170 if args is None or args == '':
171 # If no args given, use args from .topo file
172 args = self.options[ 'arg1' ] +\
Jon Halld80cc142015-07-06 13:36:05 -0700173 " " + self.options[ 'arg2' ] +\
174 " --mac --controller " +\
175 self.options[ 'controller' ] + " " +\
176 self.options[ 'arg3' ]
kelvin-onlab10e8d392015-06-03 13:53:45 -0700177 else: # else only use given args
178 pass
179 # TODO: allow use of topo args and method args?
180 else: # Use given topology file
Jon Halld80cc142015-07-06 13:36:05 -0700181 main.log.info(
182 "Starting Mininet from topo file " +
183 topoFile )
kelvin-onlab10e8d392015-06-03 13:53:45 -0700184 cmdString += topoFile + " "
185 if args is None:
186 args = ''
187 # TODO: allow use of args from .topo file?
188 cmdString += args
189 else:
190 main.log.info( "Starting Mininet topology using '" + mnCmd +
191 "' command" )
192 cmdString += mnCmd
Jon Hall689d8e42015-04-03 13:59:24 -0700193 # Send the command and check if network started
194 self.handle.sendline( "" )
195 self.handle.expect( '\$' )
196 main.log.info( "Sending '" + cmdString + "' to " + self.name )
197 self.handle.sendline( cmdString )
198 while True:
Jon Hall7eb38402015-01-08 17:19:54 -0800199 i = self.handle.expect( [ 'mininet>',
Jon Hall689d8e42015-04-03 13:59:24 -0700200 'Exception',
201 '\*\*\*',
Jon Hallefbd9792015-03-05 16:11:36 -0800202 pexpect.EOF,
203 pexpect.TIMEOUT ],
Jon Hall689d8e42015-04-03 13:59:24 -0700204 timeout )
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800205 if i == 0:
Jon Hall689d8e42015-04-03 13:59:24 -0700206 main.log.info( self.name + ": Mininet built" )
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800207 return main.TRUE
kelvin-onlabec228b82015-02-09 15:45:55 -0800208 elif i == 1:
Jon Hall689d8e42015-04-03 13:59:24 -0700209 response = str( self.handle.before +
210 self.handle.after )
211 self.handle.expect( '\$' )
212 response += str( self.handle.before +
Jon Halld80cc142015-07-06 13:36:05 -0700213 self.handle.after )
Jon Hall689d8e42015-04-03 13:59:24 -0700214 main.log.error(
215 self.name +
216 ": Launching Mininet failed: " + response )
217 return main.FALSE
218 elif i == 2:
219 self.handle.expect( [ "\n",
220 pexpect.EOF,
221 pexpect.TIMEOUT ],
222 timeout )
223 main.log.info( self.handle.before )
224 elif i == 3:
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800225 main.log.error( self.name + ": Connection timeout" )
226 return main.FALSE
Jon Hall689d8e42015-04-03 13:59:24 -0700227 elif i == 4: # timeout
kelvin-onlabef0cc1c2015-02-09 15:20:26 -0800228 main.log.error(
229 self.name +
230 ": Something took too long... " )
231 return main.FALSE
Jon Hall689d8e42015-04-03 13:59:24 -0700232 # Why did we hit this part?
233 main.log.error( "startNet did not return correctly" )
234 return main.FASLE
Jon Hall7eb38402015-01-08 17:19:54 -0800235 else: # if no handle
Jon Hall689d8e42015-04-03 13:59:24 -0700236 main.log.error( self.name + ": Connection failed to the host " +
237 self.user_name + "@" + self.ip_address )
Jon Hall7eb38402015-01-08 17:19:54 -0800238 main.log.error( self.name + ": Failed to connect to the Mininet" )
adminbae64d82013-08-01 10:50:15 -0700239 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800240
kelvin-onlabfccaafa2015-01-20 13:50:44 -0800241 def numSwitchesNlinks( self, topoType, depth, fanout ):
Jon Hall1ccf82c2014-10-15 14:55:16 -0400242 if topoType == 'tree':
Jon Hall7eb38402015-01-08 17:19:54 -0800243 # In tree topology, if fanout arg is not given, by default it is 2
244 if fanout is None:
Jon Hall1ccf82c2014-10-15 14:55:16 -0400245 fanout = 2
246 k = 0
Jon Hall38481722014-11-04 16:50:05 -0500247 count = 0
Jon Hall7eb38402015-01-08 17:19:54 -0800248 while( k <= depth - 1 ):
249 count = count + pow( fanout, k )
250 k = k + 1
kelvin-onlabd3b64892015-01-20 13:26:24 -0800251 numSwitches = count
Jon Hall7eb38402015-01-08 17:19:54 -0800252 while( k <= depth - 2 ):
253 # depth-2 gives you only core links and not considering
254 # edge links as seen by ONOS. If all the links including
255 # edge links are required, do depth-1
256 count = count + pow( fanout, k )
257 k = k + 1
kelvin-onlabd3b64892015-01-20 13:26:24 -0800258 numLinks = count * fanout
Jon Hall7eb38402015-01-08 17:19:54 -0800259 # print "num_switches for %s(%d,%d) = %d and links=%d" %(
kelvin-onlabd3b64892015-01-20 13:26:24 -0800260 # topoType,depth,fanout,numSwitches,numLinks )
Jon Hallfbc828e2015-01-06 17:30:19 -0800261
Jon Hall7eb38402015-01-08 17:19:54 -0800262 elif topoType == 'linear':
kelvin-onlabd3b64892015-01-20 13:26:24 -0800263 # In linear topology, if fanout or numHostsPerSw is not given,
Jon Hall7eb38402015-01-08 17:19:54 -0800264 # by default it is 1
265 if fanout is None:
Jon Hall1ccf82c2014-10-15 14:55:16 -0400266 fanout = 1
kelvin-onlabd3b64892015-01-20 13:26:24 -0800267 numSwitches = depth
268 numHostsPerSw = fanout
269 totalNumHosts = numSwitches * numHostsPerSw
270 numLinks = totalNumHosts + ( numSwitches - 1 )
Jon Hall7eb38402015-01-08 17:19:54 -0800271 print "num_switches for %s(%d,%d) = %d and links=%d" %\
kelvin-onlabd3b64892015-01-20 13:26:24 -0800272 ( topoType, depth, fanout, numSwitches, numLinks )
Jon Hallefbd9792015-03-05 16:11:36 -0800273 topoDict = { "num_switches": int( numSwitches ),
274 "num_corelinks": int( numLinks ) }
Jon Hall1ccf82c2014-10-15 14:55:16 -0400275 return topoDict
276
kelvin-onlabd3b64892015-01-20 13:26:24 -0800277 def calculateSwAndLinks( self ):
Jon Hall689d8e42015-04-03 13:59:24 -0700278 """
279 Calculate the number of switches and links in a topo."""
280 # TODO: combine this function and numSwitchesNlinks
281 argList = self.options[ 'arg1' ].split( "," )
282 topoArgList = argList[ 0 ].split( " " )
283 argList = map( int, argList[ 1: ] )
284 topoArgList = topoArgList[ 1: ] + argList
285
286 topoDict = self.numSwitchesNlinks( *topoArgList )
Jon Hall1ccf82c2014-10-15 14:55:16 -0400287 return topoDict
288
GlennRCf07c44a2015-09-18 13:33:46 -0700289 def pingall( self, protocol="IPv4", timeout=300, shortCircuit=False, acceptableFailed=0 ):
Jon Hall7eb38402015-01-08 17:19:54 -0800290 """
291 Verifies the reachability of the hosts using pingall command.
292 Optional parameter timeout allows you to specify how long to
293 wait for pingall to complete
kelvin-onlabfbcd82f2015-04-02 12:06:00 -0700294 Optional:
Jon Halld80cc142015-07-06 13:36:05 -0700295 timeout( seconds ) - How long to wait before breaking the pingall
kelvin-onlabfbcd82f2015-04-02 12:06:00 -0700296 shortCircuit - Break the pingall based on the number of failed hosts
kelvin-onlabc44f0192015-04-02 22:08:41 -0700297 ping
298 acceptableFailed - Set the number of acceptable failed pings for the
299 function to still return main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -0800300 Returns:
301 main.TRUE if pingall completes with no pings dropped
Jon Hall390696c2015-05-05 17:13:41 -0700302 otherwise main.FALSE
303 """
304 import time
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700305 try:
Jon Hallfb760a02015-04-13 15:35:03 -0700306 timeout = int( timeout )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700307 if self.handle:
308 main.log.info(
309 self.name +
310 ": Checking reachabilty to the hosts using pingall" )
311 response = ""
312 failedPings = 0
313 returnValue = main.TRUE
GlennRCf07c44a2015-09-18 13:33:46 -0700314 cmd = "pingall"
315 if protocol == "IPv6":
316 cmd = "py net.pingAll6()"
317 self.handle.sendline( cmd )
Jon Hall390696c2015-05-05 17:13:41 -0700318 startTime = time.time()
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700319 while True:
Jon Halld80cc142015-07-06 13:36:05 -0700320 i = self.handle.expect( [ "mininet>", "X",
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700321 pexpect.EOF,
322 pexpect.TIMEOUT ],
Jon Halld80cc142015-07-06 13:36:05 -0700323 timeout )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700324 if i == 0:
Jon Halld80cc142015-07-06 13:36:05 -0700325 main.log.info( self.name + ": pingall finished" )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700326 response += self.handle.before
327 break
328 elif i == 1:
329 response += self.handle.before + self.handle.after
330 failedPings = failedPings + 1
kelvin-onlabd26a3742015-04-06 15:31:16 -0700331 if failedPings > acceptableFailed:
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700332 returnValue = main.FALSE
333 if shortCircuit:
334 main.log.error( self.name +
335 ": Aborting pingall - "
336 + str( failedPings ) +
337 " pings failed" )
338 break
Jon Hall390696c2015-05-05 17:13:41 -0700339 if ( time.time() - startTime ) > timeout:
340 returnValue = main.FALSE
341 main.log.error( self.name +
342 ": Aborting pingall - " +
343 "Function took too long " )
344 break
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700345 elif i == 2:
346 main.log.error( self.name +
347 ": EOF exception found" )
348 main.log.error( self.name + ": " +
349 self.handle.before )
350 main.cleanup()
351 main.exit()
352 elif i == 3:
353 response += self.handle.before
354 main.log.error( self.name +
355 ": TIMEOUT exception found" )
356 main.log.error( self.name +
357 ": " +
358 str( response ) )
359 # NOTE: Send ctrl-c to make sure pingall is done
You Wangaf684312016-01-27 14:44:38 -0800360 self.handle.send( "\x03" )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700361 self.handle.expect( "Interrupt" )
362 self.handle.expect( "mininet>" )
363 break
364 pattern = "Results\:"
365 main.log.info( "Pingall output: " + str( response ) )
366 if re.search( pattern, response ):
367 main.log.info( self.name + ": Pingall finished with "
368 + str( failedPings ) + " failed pings" )
369 return returnValue
370 else:
kelvin-onlabc44f0192015-04-02 22:08:41 -0700371 # NOTE: Send ctrl-c to make sure pingall is done
You Wangaf684312016-01-27 14:44:38 -0800372 self.handle.send( "\x03" )
kelvin-onlabc44f0192015-04-02 22:08:41 -0700373 self.handle.expect( "Interrupt" )
kelvin-onlabc44f0192015-04-02 22:08:41 -0700374 self.handle.expect( "mininet>" )
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700375 return main.FALSE
adminbae64d82013-08-01 10:50:15 -0700376 else:
kelvin-onlabd9a8ed32015-04-03 13:55:28 -0700377 main.log.error( self.name + ": Connection failed to the host" )
378 main.cleanup()
379 main.exit()
380 except pexpect.TIMEOUT:
381 if response:
382 main.log.info( "Pingall output: " + str( response ) )
383 main.log.error( self.name + ": pexpect.TIMEOUT found" )
384 return main.FALSE
385 except pexpect.EOF:
386 main.log.error( self.name + ": EOF exception found" )
387 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -0500388 main.cleanup()
389 main.exit()
adminaeedddd2013-08-02 15:14:15 -0700390
Jon Hall7eb38402015-01-08 17:19:54 -0800391 def fpingHost( self, **pingParams ):
392 """
393 Uses the fping package for faster pinging...
394 *requires fping to be installed on machine running mininet"""
kelvin-onlab7d0c9672015-01-20 15:56:22 -0800395 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
Jon Hall7eb38402015-01-08 17:19:54 -0800396 command = args[ "SRC" ] + \
397 " fping -i 100 -t 20 -C 1 -q " + args[ "TARGET" ]
398 self.handle.sendline( command )
399 self.handle.expect(
400 [ args[ "TARGET" ], pexpect.EOF, pexpect.TIMEOUT ] )
401 self.handle.expect( [ "mininet", pexpect.EOF, pexpect.TIMEOUT ] )
402 response = self.handle.before
403 if re.search( ":\s-", response ):
404 main.log.info( self.name + ": Ping fail" )
adminaeedddd2013-08-02 15:14:15 -0700405 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800406 elif re.search( ":\s\d{1,2}\.\d\d", response ):
407 main.log.info( self.name + ": Ping good!" )
adminaeedddd2013-08-02 15:14:15 -0700408 return main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -0800409 main.log.info( self.name + ": Install fping on mininet machine... " )
410 main.log.info( self.name + ": \n---\n" + response )
adminaeedddd2013-08-02 15:14:15 -0700411 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800412
Jon Hall3b489db2015-10-05 14:38:37 -0700413 def pingallHosts( self, hostList, wait=1 ):
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400414 """
Hari Krishna9592fc82015-07-31 15:11:15 -0700415 Ping all specified IPv4 hosts
kelvin-onlab2ff57022015-05-29 10:48:51 -0700416
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400417 Acceptable hostList:
Jon Halld80cc142015-07-06 13:36:05 -0700418 - [ 'h1','h2','h3','h4' ]
kelvin-onlab2ff57022015-05-29 10:48:51 -0700419
420 Returns main.TRUE if all hosts specified can reach
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400421 each other
kelvin-onlab2ff57022015-05-29 10:48:51 -0700422
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400423 Returns main.FALSE if one or more of hosts specified
424 cannot reach each other"""
Jon Hall3b489db2015-10-05 14:38:37 -0700425 wait = int( wait )
426 cmd = " ping -c 1 -i 1 -W " + str( wait ) + " "
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400427
428 try:
429 main.log.info( "Testing reachability between specified hosts" )
kelvin-onlab2ff57022015-05-29 10:48:51 -0700430
andrew@onlab.usdefe38c2015-05-14 19:18:18 -0400431 isReachable = main.TRUE
GlennRC6d506272015-09-25 11:36:07 -0700432 pingResponse = "IPv4 ping across specified hosts\n"
433 failedPings = 0
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400434 for host in hostList:
Jon Halld80cc142015-07-06 13:36:05 -0700435 listIndex = hostList.index( host )
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400436 # List of hosts to ping other than itself
Jon Halld80cc142015-07-06 13:36:05 -0700437 pingList = hostList[ :listIndex ] + \
438 hostList[ ( listIndex + 1 ): ]
GlennRCd10d3cc2015-09-24 12:47:16 -0700439
440 pingResponse += str(str(host) + " -> ")
441
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400442 for temp in pingList:
443 # Current host pings all other hosts specified
Jon Halld80cc142015-07-06 13:36:05 -0700444 pingCmd = str( host ) + cmd + str( temp )
Jon Hall934576d2015-10-09 10:12:22 -0700445 self.handle.sendline( pingCmd )
446 self.handle.expect( "mininet>", timeout=wait + 1 )
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400447 response = self.handle.before
448 if re.search( ',\s0\%\spacket\sloss', response ):
GlennRCd10d3cc2015-09-24 12:47:16 -0700449 pingResponse += str(" h" + str( temp[1:] ))
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400450 else:
GlennRCd10d3cc2015-09-24 12:47:16 -0700451 pingResponse += " X"
andrew@onlab.usdefe38c2015-05-14 19:18:18 -0400452 # One of the host to host pair is unreachable
453 isReachable = main.FALSE
GlennRC6d506272015-09-25 11:36:07 -0700454 failedPings += 1
GlennRCd10d3cc2015-09-24 12:47:16 -0700455 pingResponse += "\n"
GlennRC6d506272015-09-25 11:36:07 -0700456 main.log.info( pingResponse + "Failed pings: " + str(failedPings) )
kelvin-onlab2ff57022015-05-29 10:48:51 -0700457 return isReachable
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700458 except pexpect.TIMEOUT:
459 main.log.exception( self.name + ": TIMEOUT exception" )
Hari Krishna4223dbd2015-08-13 16:29:53 -0700460 return main.FALSE
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400461 except pexpect.EOF:
462 main.log.error( self.name + ": EOF exception found" )
463 main.log.error( self.name + ": " + self.handle.before )
464 main.cleanup()
465 main.exit()
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700466 except Exception:
467 main.log.exception( self.name + ": Uncaught exception!" )
468 main.cleanup()
469 main.exit()
andrew@onlab.us9fdee812015-05-14 17:23:26 -0400470
Jon Hall3b489db2015-10-05 14:38:37 -0700471 def pingIpv6Hosts( self, hostList, prefix='1000::', wait=1 ):
Hari Krishna9592fc82015-07-31 15:11:15 -0700472 """
Jon Hall3b489db2015-10-05 14:38:37 -0700473 IPv6 ping all hosts in hostList. If no prefix passed this will use
474 default prefix of 1000::
Hari Krishna9592fc82015-07-31 15:11:15 -0700475
Jon Hall3b489db2015-10-05 14:38:37 -0700476 Returns main.TRUE if all hosts specified can reach each other
Hari Krishna9592fc82015-07-31 15:11:15 -0700477
Jon Hall3b489db2015-10-05 14:38:37 -0700478 Returns main.FALSE if one or more of hosts specified cannot reach each other
Hari Krishna9592fc82015-07-31 15:11:15 -0700479 """
480 try:
481 main.log.info( "Testing reachability between specified IPv6 hosts" )
482 isReachable = main.TRUE
Jon Hall3b489db2015-10-05 14:38:37 -0700483 wait = int( wait )
484 cmd = " ping6 -c 1 -i 1 -W " + str( wait ) + " "
GlennRC6d506272015-09-25 11:36:07 -0700485 pingResponse = "IPv6 Pingall output:\n"
486 failedPings = 0
Hari Krishna9592fc82015-07-31 15:11:15 -0700487 for host in hostList:
488 listIndex = hostList.index( host )
489 # List of hosts to ping other than itself
490 pingList = hostList[ :listIndex ] + \
491 hostList[ ( listIndex + 1 ): ]
492
GlennRC2cf7d952015-09-11 16:32:13 -0700493 pingResponse += str(str(host) + " -> ")
494
Hari Krishna9592fc82015-07-31 15:11:15 -0700495 for temp in pingList:
496 # Current host pings all other hosts specified
497 pingCmd = str( host ) + cmd + prefix + str( temp[1:] )
Jon Hall934576d2015-10-09 10:12:22 -0700498 self.handle.sendline( pingCmd )
499 self.handle.expect( "mininet>", timeout=wait + 1 )
Hari Krishna9592fc82015-07-31 15:11:15 -0700500 response = self.handle.before
501 if re.search( ',\s0\%\spacket\sloss', response ):
GlennRC2cf7d952015-09-11 16:32:13 -0700502 pingResponse += str(" h" + str( temp[1:] ))
Hari Krishna9592fc82015-07-31 15:11:15 -0700503 else:
GlennRC2cf7d952015-09-11 16:32:13 -0700504 pingResponse += " X"
Hari Krishna9592fc82015-07-31 15:11:15 -0700505 # One of the host to host pair is unreachable
506 isReachable = main.FALSE
GlennRC6d506272015-09-25 11:36:07 -0700507 failedPings += 1
GlennRCd10d3cc2015-09-24 12:47:16 -0700508 pingResponse += "\n"
GlennRC6d506272015-09-25 11:36:07 -0700509 main.log.info( pingResponse + "Failed pings: " + str(failedPings) )
Hari Krishna9592fc82015-07-31 15:11:15 -0700510 return isReachable
511
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700512 except pexpect.TIMEOUT:
513 main.log.exception( self.name + ": TIMEOUT exception" )
514 return main.FALSE
Hari Krishna9592fc82015-07-31 15:11:15 -0700515 except pexpect.EOF:
516 main.log.error( self.name + ": EOF exception found" )
517 main.log.error( self.name + ": " + self.handle.before )
518 main.cleanup()
519 main.exit()
Hari Krishna3bf8ea82015-08-11 09:02:02 -0700520 except Exception:
521 main.log.exception( self.name + ": Uncaught exception!" )
522 main.cleanup()
523 main.exit()
Hari Krishna9592fc82015-07-31 15:11:15 -0700524
Jon Hall7eb38402015-01-08 17:19:54 -0800525 def pingHost( self, **pingParams ):
526 """
Jon Hall3b489db2015-10-05 14:38:37 -0700527 Ping from one mininet host to another
528 Currently the only supported Params: SRC, TARGET, and WAIT
529 """
530 args = utilities.parse_args( [ "SRC", "TARGET", 'WAIT' ], **pingParams )
531 wait = args['WAIT']
532 wait = int( wait if wait else 1 )
Jon Hall7eb38402015-01-08 17:19:54 -0800533 command = args[ "SRC" ] + " ping " + \
Jon Hall3b489db2015-10-05 14:38:37 -0700534 args[ "TARGET" ] + " -c 1 -i 1 -W " + str( wait ) + " "
Jon Hall6094a362014-04-11 14:46:56 -0700535 try:
Jon Hall61282e32015-03-19 11:34:11 -0700536 main.log.info( "Sending: " + command )
Jon Hall7eb38402015-01-08 17:19:54 -0800537 self.handle.sendline( command )
Jon Hall3b489db2015-10-05 14:38:37 -0700538 i = self.handle.expect( [ command, pexpect.TIMEOUT ],
539 timeout=wait + 1 )
Jon Hall6e18c7b2014-04-23 16:26:33 -0700540 if i == 1:
Jon Hall7eb38402015-01-08 17:19:54 -0800541 main.log.error(
542 self.name +
543 ": timeout when waiting for response from mininet" )
544 main.log.error( "response: " + str( self.handle.before ) )
545 i = self.handle.expect( [ "mininet>", pexpect.TIMEOUT ] )
Jon Hall6e18c7b2014-04-23 16:26:33 -0700546 if i == 1:
Jon Hall7eb38402015-01-08 17:19:54 -0800547 main.log.error(
548 self.name +
549 ": timeout when waiting for response from mininet" )
550 main.log.error( "response: " + str( self.handle.before ) )
Jon Hall6e18c7b2014-04-23 16:26:33 -0700551 response = self.handle.before
Hari Krishna012a1c12015-08-25 14:23:58 -0700552 if re.search( ',\s0\%\spacket\sloss', response ):
553 main.log.info( self.name + ": no packets lost, host is reachable" )
554 return main.TRUE
555 else:
556 main.log.error(
557 self.name +
558 ": PACKET LOST, HOST IS NOT REACHABLE" )
559 return main.FALSE
560
Jon Hallfbc828e2015-01-06 17:30:19 -0800561 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800562 main.log.error( self.name + ": EOF exception found" )
563 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700564 main.cleanup()
565 main.exit()
Hari Krishna012a1c12015-08-25 14:23:58 -0700566 except Exception:
567 main.log.exception( self.name + ": Uncaught exception!" )
568 main.cleanup()
569 main.exit()
570
571 def ping6pair( self, **pingParams ):
572 """
GlennRC2cf7d952015-09-11 16:32:13 -0700573 IPv6 Ping between a pair of mininet hosts
Jon Hall3b489db2015-10-05 14:38:37 -0700574 Currently the only supported Params are: SRC, TARGET, and WAIT
Hari Krishna012a1c12015-08-25 14:23:58 -0700575 FLOWLABEL and -I (src interface) will be added later after running some tests.
576 Example: main.Mininet1.ping6pair( src="h1", target="1000::2" )
577 """
Jon Hall3b489db2015-10-05 14:38:37 -0700578 args = utilities.parse_args( [ "SRC", "TARGET", 'WAIT' ], **pingParams )
579 wait = args['WAIT']
580 wait = int( wait if wait else 1 )
Subhash Kumar Singhbcc1c792015-11-07 04:52:11 +0530581 command = args[ "SRC" ] + " ping6 " + \
Jon Hall3b489db2015-10-05 14:38:37 -0700582 args[ "TARGET" ] + " -c 1 -i 1 -W " + str( wait ) + " "
Hari Krishna012a1c12015-08-25 14:23:58 -0700583 try:
584 main.log.info( "Sending: " + command )
585 self.handle.sendline( command )
Jon Hall3b489db2015-10-05 14:38:37 -0700586 i = self.handle.expect( [ command, pexpect.TIMEOUT ],
587 timeout=wait + 1 )
Hari Krishna012a1c12015-08-25 14:23:58 -0700588 if i == 1:
589 main.log.error(
590 self.name +
591 ": timeout when waiting for response from mininet" )
592 main.log.error( "response: " + str( self.handle.before ) )
593 i = self.handle.expect( [ "mininet>", pexpect.TIMEOUT ] )
594 if i == 1:
595 main.log.error(
596 self.name +
597 ": timeout when waiting for response from mininet" )
598 main.log.error( "response: " + str( self.handle.before ) )
599 response = self.handle.before
600 main.log.info( self.name + ": Ping Response: " + response )
601 if re.search( ',\s0\%\spacket\sloss', response ):
602 main.log.info( self.name + ": no packets lost, host is reachable" )
GlennRC2cf7d952015-09-11 16:32:13 -0700603 return main.TRUE
Hari Krishna012a1c12015-08-25 14:23:58 -0700604 else:
605 main.log.error(
606 self.name +
607 ": PACKET LOST, HOST IS NOT REACHABLE" )
608 return main.FALSE
609
610 except pexpect.EOF:
611 main.log.error( self.name + ": EOF exception found" )
612 main.log.error( self.name + ": " + self.handle.before )
613 main.cleanup()
614 main.exit()
615 except Exception:
616 main.log.exception( self.name + ": Uncaught exception!" )
617 main.cleanup()
618 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -0800619
Jon Hall7eb38402015-01-08 17:19:54 -0800620 def checkIP( self, host ):
621 """
622 Verifies the host's ip configured or not."""
623 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -0700624 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800625 response = self.execute(
626 cmd=host +
627 " ifconfig",
628 prompt="mininet>",
629 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800630 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800631 main.log.error( self.name + ": EOF exception found" )
632 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700633 main.cleanup()
634 main.exit()
adminbae64d82013-08-01 10:50:15 -0700635
Jon Hall7eb38402015-01-08 17:19:54 -0800636 pattern = "inet\s(addr|Mask):([0-1]{1}[0-9]{1,2}|" +\
kelvin-onlabedcff052015-01-16 12:53:55 -0800637 "2[0-4][0-9]|25[0-5]|[0-9]{1,2}).([0-1]{1}" +\
638 "[0-9]{1,2}|2[0-4][0-9]|25[0-5]|[0-9]{1,2})." +\
639 "([0-1]{1}[0-9]{1,2}|2[0-4][0-9]|25[0-5]|" +\
640 "[0-9]{1,2}).([0-1]{1}[0-9]{1,2}|2[0-4]" +\
641 "[0-9]|25[0-5]|[0-9]{1,2})"
Jon Hall7eb38402015-01-08 17:19:54 -0800642 # pattern = "inet addr:10.0.0.6"
643 if re.search( pattern, response ):
644 main.log.info( self.name + ": Host Ip configured properly" )
adminbae64d82013-08-01 10:50:15 -0700645 return main.TRUE
646 else:
Jon Hall7eb38402015-01-08 17:19:54 -0800647 main.log.error( self.name + ": Host IP not found" )
adminbae64d82013-08-01 10:50:15 -0700648 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800649 else:
650 main.log.error( self.name + ": Connection failed to the host" )
Jon Hallfbc828e2015-01-06 17:30:19 -0800651
Jon Hall7eb38402015-01-08 17:19:54 -0800652 def verifySSH( self, **connectargs ):
Jon Hallefbd9792015-03-05 16:11:36 -0800653 # FIXME: Who uses this and what is the purpose? seems very specific
Jon Hall6094a362014-04-11 14:46:56 -0700654 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800655 response = self.execute(
656 cmd="h1 /usr/sbin/sshd -D&",
657 prompt="mininet>",
658 timeout=10 )
659 response = self.execute(
660 cmd="h4 /usr/sbin/sshd -D&",
661 prompt="mininet>",
662 timeout=10 )
Jon Hall6094a362014-04-11 14:46:56 -0700663 for key in connectargs:
Jon Hall7eb38402015-01-08 17:19:54 -0800664 vars( self )[ key ] = connectargs[ key ]
665 response = self.execute(
666 cmd="xterm h1 h4 ",
667 prompt="mininet>",
668 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800669 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800670 main.log.error( self.name + ": EOF exception found" )
671 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700672 main.cleanup()
673 main.exit()
adminbae64d82013-08-01 10:50:15 -0700674 import time
Jon Hall7eb38402015-01-08 17:19:54 -0800675 time.sleep( 20 )
adminbae64d82013-08-01 10:50:15 -0700676 if self.flag == 0:
677 self.flag = 1
678 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800679 else:
adminbae64d82013-08-01 10:50:15 -0700680 return main.TRUE
shahshreyae6c7cf42014-11-26 16:39:01 -0800681
kelvin-onlaba1484582015-02-02 15:46:20 -0800682 def moveHost( self, host, oldSw, newSw, ):
683 """
684 Moves a host from one switch to another on the fly
685 Note: The intf between host and oldSw when detached
686 using detach(), will still show up in the 'net'
687 cmd, because switch.detach() doesn't affect switch.intfs[]
Jon Halld80cc142015-07-06 13:36:05 -0700688 ( which is correct behavior since the interfaces
689 haven't moved ).
kelvin-onlaba1484582015-02-02 15:46:20 -0800690 """
691 if self.handle:
692 try:
693 # Bring link between oldSw-host down
Jon Halld80cc142015-07-06 13:36:05 -0700694 cmd = "py net.configLinkStatus('" + oldSw + "'," + "'" + host +\
Jon Hallefbd9792015-03-05 16:11:36 -0800695 "'," + "'down')"
kelvin-onlaba1484582015-02-02 15:46:20 -0800696 print "cmd1= ", cmd
Jon Hallefbd9792015-03-05 16:11:36 -0800697 response = self.execute( cmd=cmd,
698 prompt="mininet>",
699 timeout=10 )
Jon Hallafa8a472015-06-12 14:02:42 -0700700
kelvin-onlaba1484582015-02-02 15:46:20 -0800701 # Determine hostintf and Oldswitchintf
702 cmd = "px hintf,sintf = " + host + ".connectionsTo(" + oldSw +\
Jon Hallefbd9792015-03-05 16:11:36 -0800703 ")[0]"
kelvin-onlaba1484582015-02-02 15:46:20 -0800704 print "cmd2= ", cmd
705 self.handle.sendline( cmd )
706 self.handle.expect( "mininet>" )
707
shahshreya73537862015-02-11 15:15:24 -0800708 # Determine ip and mac address of the host-oldSw interface
kelvin-onlaba1484582015-02-02 15:46:20 -0800709 cmd = "px ipaddr = hintf.IP()"
710 print "cmd3= ", cmd
711 self.handle.sendline( cmd )
712 self.handle.expect( "mininet>" )
shahshreya73537862015-02-11 15:15:24 -0800713
714 cmd = "px macaddr = hintf.MAC()"
715 print "cmd3= ", cmd
716 self.handle.sendline( cmd )
717 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700718
kelvin-onlaba1484582015-02-02 15:46:20 -0800719 # Detach interface between oldSw-host
720 cmd = "px " + oldSw + ".detach( sintf )"
721 print "cmd4= ", cmd
722 self.handle.sendline( cmd )
723 self.handle.expect( "mininet>" )
724
725 # Add link between host-newSw
726 cmd = "py net.addLink(" + host + "," + newSw + ")"
727 print "cmd5= ", cmd
728 self.handle.sendline( cmd )
729 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700730
kelvin-onlaba1484582015-02-02 15:46:20 -0800731 # Determine hostintf and Newswitchintf
732 cmd = "px hintf,sintf = " + host + ".connectionsTo(" + newSw +\
Jon Hallefbd9792015-03-05 16:11:36 -0800733 ")[0]"
kelvin-onlaba1484582015-02-02 15:46:20 -0800734 print "cmd6= ", cmd
735 self.handle.sendline( cmd )
Jon Hallafa8a472015-06-12 14:02:42 -0700736 self.handle.expect( "mininet>" )
kelvin-onlaba1484582015-02-02 15:46:20 -0800737
738 # Attach interface between newSw-host
739 cmd = "px " + newSw + ".attach( sintf )"
740 print "cmd3= ", cmd
741 self.handle.sendline( cmd )
742 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700743
kelvin-onlaba1484582015-02-02 15:46:20 -0800744 # Set ipaddress of the host-newSw interface
745 cmd = "px " + host + ".setIP( ip = ipaddr, intf = hintf)"
746 print "cmd7 = ", cmd
747 self.handle.sendline( cmd )
748 self.handle.expect( "mininet>" )
shahshreya73537862015-02-11 15:15:24 -0800749
750 # Set macaddress of the host-newSw interface
751 cmd = "px " + host + ".setMAC( mac = macaddr, intf = hintf)"
752 print "cmd8 = ", cmd
753 self.handle.sendline( cmd )
754 self.handle.expect( "mininet>" )
Jon Hallafa8a472015-06-12 14:02:42 -0700755
kelvin-onlaba1484582015-02-02 15:46:20 -0800756 cmd = "net"
shahshreya73537862015-02-11 15:15:24 -0800757 print "cmd9 = ", cmd
kelvin-onlaba1484582015-02-02 15:46:20 -0800758 self.handle.sendline( cmd )
759 self.handle.expect( "mininet>" )
760 print "output = ", self.handle.before
761
762 # Determine ipaddress of the host-newSw interface
shahshreya73537862015-02-11 15:15:24 -0800763 cmd = host + " ifconfig"
764 print "cmd10= ", cmd
kelvin-onlaba1484582015-02-02 15:46:20 -0800765 self.handle.sendline( cmd )
766 self.handle.expect( "mininet>" )
767 print "ifconfig o/p = ", self.handle.before
Jon Hallafa8a472015-06-12 14:02:42 -0700768
kelvin-onlaba1484582015-02-02 15:46:20 -0800769 return main.TRUE
770 except pexpect.EOF:
771 main.log.error( self.name + ": EOF exception found" )
772 main.log.error( self.name + ": " + self.handle.before )
773 return main.FALSE
774
Jon Hall7eb38402015-01-08 17:19:54 -0800775 def changeIP( self, host, intf, newIP, newNetmask ):
776 """
777 Changes the ip address of a host on the fly
778 Ex: h2 ifconfig h2-eth0 10.0.1.2 netmask 255.255.255.0"""
shahshreyae6c7cf42014-11-26 16:39:01 -0800779 if self.handle:
780 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800781 cmd = host + " ifconfig " + intf + " " + \
782 newIP + " " + 'netmask' + " " + newNetmask
783 self.handle.sendline( cmd )
784 self.handle.expect( "mininet>" )
shahshreyae6c7cf42014-11-26 16:39:01 -0800785 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800786 main.log.info( "response = " + response )
787 main.log.info(
788 "Ip of host " +
789 host +
790 " changed to new IP " +
791 newIP )
shahshreyae6c7cf42014-11-26 16:39:01 -0800792 return main.TRUE
793 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800794 main.log.error( self.name + ": EOF exception found" )
795 main.log.error( self.name + ": " + self.handle.before )
shahshreyae6c7cf42014-11-26 16:39:01 -0800796 return main.FALSE
797
Jon Hall7eb38402015-01-08 17:19:54 -0800798 def changeDefaultGateway( self, host, newGW ):
799 """
800 Changes the default gateway of a host
801 Ex: h1 route add default gw 10.0.1.2"""
shahshreyae6c7cf42014-11-26 16:39:01 -0800802 if self.handle:
803 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800804 cmd = host + " route add default gw " + newGW
805 self.handle.sendline( cmd )
806 self.handle.expect( "mininet>" )
shahshreyae6c7cf42014-11-26 16:39:01 -0800807 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800808 main.log.info( "response = " + response )
809 main.log.info(
810 "Default gateway of host " +
811 host +
812 " changed to " +
813 newGW )
shahshreyae6c7cf42014-11-26 16:39:01 -0800814 return main.TRUE
815 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800816 main.log.error( self.name + ": EOF exception found" )
817 main.log.error( self.name + ": " + self.handle.before )
shahshreyae6c7cf42014-11-26 16:39:01 -0800818 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800819
Jon Hall7eb38402015-01-08 17:19:54 -0800820 def addStaticMACAddress( self, host, GW, macaddr ):
821 """
Jon Hallefbd9792015-03-05 16:11:36 -0800822 Changes the mac address of a gateway host"""
shahshreyad0c80432014-12-04 16:56:05 -0800823 if self.handle:
824 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800825 # h1 arp -s 10.0.1.254 00:00:00:00:11:11
826 cmd = host + " arp -s " + GW + " " + macaddr
827 self.handle.sendline( cmd )
828 self.handle.expect( "mininet>" )
shahshreyad0c80432014-12-04 16:56:05 -0800829 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800830 main.log.info( "response = " + response )
831 main.log.info(
Jon Hallefbd9792015-03-05 16:11:36 -0800832 "Mac address of gateway " +
Jon Hall7eb38402015-01-08 17:19:54 -0800833 GW +
834 " changed to " +
835 macaddr )
shahshreyad0c80432014-12-04 16:56:05 -0800836 return main.TRUE
837 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800838 main.log.error( self.name + ": EOF exception found" )
839 main.log.error( self.name + ": " + self.handle.before )
shahshreyad0c80432014-12-04 16:56:05 -0800840 return main.FALSE
841
Jon Hall7eb38402015-01-08 17:19:54 -0800842 def verifyStaticGWandMAC( self, host ):
843 """
844 Verify if the static gateway and mac address assignment"""
shahshreyad0c80432014-12-04 16:56:05 -0800845 if self.handle:
846 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800847 # h1 arp -an
848 cmd = host + " arp -an "
849 self.handle.sendline( cmd )
850 self.handle.expect( "mininet>" )
shahshreyad0c80432014-12-04 16:56:05 -0800851 response = self.handle.before
Jon Hall7eb38402015-01-08 17:19:54 -0800852 main.log.info( host + " arp -an = " + response )
shahshreyad0c80432014-12-04 16:56:05 -0800853 return main.TRUE
854 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800855 main.log.error( self.name + ": EOF exception found" )
856 main.log.error( self.name + ": " + self.handle.before )
shahshreyad0c80432014-12-04 16:56:05 -0800857 return main.FALSE
858
Jon Hall7eb38402015-01-08 17:19:54 -0800859 def getMacAddress( self, host ):
860 """
861 Verifies the host's ip configured or not."""
862 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -0700863 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800864 response = self.execute(
865 cmd=host +
866 " ifconfig",
867 prompt="mininet>",
868 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800869 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800870 main.log.error( self.name + ": EOF exception found" )
871 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700872 main.cleanup()
873 main.exit()
adminbae64d82013-08-01 10:50:15 -0700874
Ahmed El-Hassanyf720e202014-04-04 16:11:36 -0700875 pattern = r'HWaddr\s([0-9A-F]{2}[:-]){5}([0-9A-F]{2})'
kelvin-onlabd3b64892015-01-20 13:26:24 -0800876 macAddressSearch = re.search( pattern, response, re.I )
877 macAddress = macAddressSearch.group().split( " " )[ 1 ]
Jon Hall7eb38402015-01-08 17:19:54 -0800878 main.log.info(
879 self.name +
880 ": Mac-Address of Host " +
881 host +
882 " is " +
kelvin-onlabd3b64892015-01-20 13:26:24 -0800883 macAddress )
884 return macAddress
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700885 else:
Jon Hall7eb38402015-01-08 17:19:54 -0800886 main.log.error( self.name + ": Connection failed to the host" )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700887
Jon Hall7eb38402015-01-08 17:19:54 -0800888 def getInterfaceMACAddress( self, host, interface ):
889 """
890 Return the IP address of the interface on the given host"""
891 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -0700892 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800893 response = self.execute( cmd=host + " ifconfig " + interface,
894 prompt="mininet>", timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800895 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800896 main.log.error( self.name + ": EOF exception found" )
897 main.log.error( self.name + ": " + self.handle.before )
898 main.cleanup()
899 main.exit()
900
901 pattern = r'HWaddr\s([0-9A-F]{2}[:-]){5}([0-9A-F]{2})'
kelvin-onlabd3b64892015-01-20 13:26:24 -0800902 macAddressSearch = re.search( pattern, response, re.I )
903 if macAddressSearch is None:
Jon Hall7eb38402015-01-08 17:19:54 -0800904 main.log.info( "No mac address found in %s" % response )
905 return main.FALSE
kelvin-onlabd3b64892015-01-20 13:26:24 -0800906 macAddress = macAddressSearch.group().split( " " )[ 1 ]
Jon Hall7eb38402015-01-08 17:19:54 -0800907 main.log.info(
908 "Mac-Address of " +
909 host +
910 ":" +
911 interface +
912 " is " +
kelvin-onlabd3b64892015-01-20 13:26:24 -0800913 macAddress )
914 return macAddress
Jon Hall7eb38402015-01-08 17:19:54 -0800915 else:
916 main.log.error( "Connection failed to the host" )
917
918 def getIPAddress( self, host ):
919 """
920 Verifies the host's ip configured or not."""
921 if self.handle:
922 try:
923 response = self.execute(
924 cmd=host +
925 " ifconfig",
926 prompt="mininet>",
927 timeout=10 )
928 except pexpect.EOF:
929 main.log.error( self.name + ": EOF exception found" )
930 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700931 main.cleanup()
932 main.exit()
adminbae64d82013-08-01 10:50:15 -0700933
934 pattern = "inet\saddr:(\d+\.\d+\.\d+\.\d+)"
kelvin-onlabd3b64892015-01-20 13:26:24 -0800935 ipAddressSearch = re.search( pattern, response )
Jon Hall7eb38402015-01-08 17:19:54 -0800936 main.log.info(
937 self.name +
938 ": IP-Address of Host " +
939 host +
940 " is " +
kelvin-onlabd3b64892015-01-20 13:26:24 -0800941 ipAddressSearch.group( 1 ) )
942 return ipAddressSearch.group( 1 )
Jon Hall7eb38402015-01-08 17:19:54 -0800943 else:
944 main.log.error( self.name + ": Connection failed to the host" )
Jon Hallfbc828e2015-01-06 17:30:19 -0800945
Jon Hall7eb38402015-01-08 17:19:54 -0800946 def getSwitchDPID( self, switch ):
947 """
948 return the datapath ID of the switch"""
949 if self.handle:
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700950 cmd = "py %s.dpid" % switch
Jon Hall6094a362014-04-11 14:46:56 -0700951 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800952 response = self.execute(
953 cmd=cmd,
954 prompt="mininet>",
955 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800956 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800957 main.log.error( self.name + ": EOF exception found" )
958 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -0700959 main.cleanup()
960 main.exit()
Jon Hall28bf54b2014-12-17 16:25:44 -0800961 pattern = r'^(?P<dpid>\w)+'
Jon Hall7eb38402015-01-08 17:19:54 -0800962 result = re.search( pattern, response, re.MULTILINE )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700963 if result is None:
Jon Hall7eb38402015-01-08 17:19:54 -0800964 main.log.info(
965 "Couldn't find DPID for switch %s, found: %s" %
966 ( switch, response ) )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700967 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -0800968 return str( result.group( 0 ) ).lower()
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700969 else:
Jon Hall7eb38402015-01-08 17:19:54 -0800970 main.log.error( "Connection failed to the host" )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700971
Jon Hall7eb38402015-01-08 17:19:54 -0800972 def getDPID( self, switch ):
admin2580a0e2014-07-29 11:24:34 -0700973 if self.handle:
Jon Hall7eb38402015-01-08 17:19:54 -0800974 self.handle.sendline( "" )
975 self.expect( "mininet>" )
976 cmd = "py %s.dpid" % switch
admin2580a0e2014-07-29 11:24:34 -0700977 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800978 response = self.execute(
979 cmd=cmd,
980 prompt="mininet>",
981 timeout=10 )
982 self.handle.expect( "mininet>" )
admin2580a0e2014-07-29 11:24:34 -0700983 response = self.handle.before
984 return response
985 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -0800986 main.log.error( self.name + ": EOF exception found" )
987 main.log.error( self.name + ": " + self.handle.before )
admin2580a0e2014-07-29 11:24:34 -0700988 main.cleanup()
989 main.exit()
990
Jon Hall7eb38402015-01-08 17:19:54 -0800991 def getInterfaces( self, node ):
992 """
993 return information dict about interfaces connected to the node"""
994 if self.handle:
995 cmd = 'py "\\n".join(["name=%s,mac=%s,ip=%s,enabled=%s"' +\
kelvin-onlabedcff052015-01-16 12:53:55 -0800996 ' % (i.name, i.MAC(), i.IP(), i.isUp())'
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -0700997 cmd += ' for i in %s.intfs.values()])' % node
Jon Hall6094a362014-04-11 14:46:56 -0700998 try:
Jon Hall7eb38402015-01-08 17:19:54 -0800999 response = self.execute(
1000 cmd=cmd,
1001 prompt="mininet>",
1002 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001003 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001004 main.log.error( self.name + ": EOF exception found" )
1005 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001006 main.cleanup()
1007 main.exit()
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -07001008 return response
1009 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001010 main.log.error( "Connection failed to the node" )
Ahmed El-Hassanyfd329182014-04-10 11:38:16 -07001011
Jon Hall7eb38402015-01-08 17:19:54 -08001012 def dump( self ):
1013 main.log.info( self.name + ": Dump node info" )
Jon Hall6094a362014-04-11 14:46:56 -07001014 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001015 response = self.execute(
1016 cmd='dump',
1017 prompt='mininet>',
1018 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001019 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001020 main.log.error( self.name + ": EOF exception found" )
1021 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001022 main.cleanup()
1023 main.exit()
Ahmed El-Hassanyd1f71702014-04-04 16:12:45 -07001024 return response
Jon Hallfbc828e2015-01-06 17:30:19 -08001025
Jon Hall7eb38402015-01-08 17:19:54 -08001026 def intfs( self ):
1027 main.log.info( self.name + ": List interfaces" )
Jon Hall6094a362014-04-11 14:46:56 -07001028 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001029 response = self.execute(
1030 cmd='intfs',
1031 prompt='mininet>',
1032 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001033 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001034 main.log.error( self.name + ": EOF exception found" )
1035 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001036 main.cleanup()
1037 main.exit()
Jon Hall668ed802014-04-08 17:17:59 -07001038 return response
Jon Hallfbc828e2015-01-06 17:30:19 -08001039
Jon Hall7eb38402015-01-08 17:19:54 -08001040 def net( self ):
1041 main.log.info( self.name + ": List network connections" )
Jon Hall6094a362014-04-11 14:46:56 -07001042 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001043 response = self.execute( cmd='net', prompt='mininet>', timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001044 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001045 main.log.error( self.name + ": EOF exception found" )
1046 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001047 main.cleanup()
1048 main.exit()
Jon Hall668ed802014-04-08 17:17:59 -07001049 return response
Jon Hall7eb38402015-01-08 17:19:54 -08001050
Jon Hallafa8a472015-06-12 14:02:42 -07001051 def links( self ):
1052 main.log.info( self.name + ": List network links" )
1053 try:
1054 response = self.execute( cmd='links', prompt='mininet>',
Jon Hall3b489db2015-10-05 14:38:37 -07001055 timeout=20 )
Jon Hallafa8a472015-06-12 14:02:42 -07001056 except pexpect.EOF:
1057 main.log.error( self.name + ": EOF exception found" )
1058 main.log.error( self.name + ": " + self.handle.before )
1059 main.cleanup()
1060 main.exit()
1061 return response
1062
GlennRC61321f22015-07-16 13:36:54 -07001063 def iperftcpAll(self, hosts, timeout=6):
kelvin-onlab7cce9382015-07-17 10:21:03 -07001064 '''
1065 Runs the iperftcp function with a given set of hosts and specified timeout.
GlennRC61321f22015-07-16 13:36:54 -07001066
kelvin-onlab7cce9382015-07-17 10:21:03 -07001067 @parm:
1068 timeout: The defualt timeout is 6 sec to allow enough time for a successful test to complete,
1069 and short enough to stop an unsuccessful test from quiting and cleaning up mininet.
1070 '''
1071 for host1 in hosts:
1072 for host2 in hosts:
1073 if host1 != host2:
1074 if self.iperftcp(host1, host2, timeout) == main.FALSE:
1075 main.log.error(self.name + ": iperftcp test failed for " + host1 + " and " + host2)
GlennRC61321f22015-07-16 13:36:54 -07001076
1077 def iperftcp(self, host1="h1", host2="h2", timeout=6):
kelvin-onlab7cce9382015-07-17 10:21:03 -07001078 '''
1079 Creates an iperf TCP test between two hosts. Returns main.TRUE if test results
1080 are valid.
GlennRC61321f22015-07-16 13:36:54 -07001081
kelvin-onlab7cce9382015-07-17 10:21:03 -07001082 @parm:
1083 timeout: The defualt timeout is 6 sec to allow enough time for a successful test to complete,
1084 and short enough to stop an unsuccessful test from quiting and cleaning up mininet.
1085 '''
1086 main.log.info( self.name + ": Simple iperf TCP test between two hosts" )
1087 try:
1088 # Setup the mininet command
1089 cmd1 = 'iperf ' + host1 + " " + host2
1090 self.handle.sendline( cmd1 )
1091 outcome = self.handle.expect( "mininet>", timeout )
1092 response = self.handle.before
GlennRC61321f22015-07-16 13:36:54 -07001093
kelvin-onlab7cce9382015-07-17 10:21:03 -07001094 # checks if there are results in the mininet response
1095 if "Results:" in response:
Jon Hall892818c2015-10-20 17:58:34 -07001096 main.log.report(self.name + ": iperf test completed")
kelvin-onlab7cce9382015-07-17 10:21:03 -07001097 # parse the mn results
1098 response = response.split("\r\n")
1099 response = response[len(response)-2]
1100 response = response.split(": ")
1101 response = response[len(response)-1]
1102 response = response.replace("[", "")
1103 response = response.replace("]", "")
1104 response = response.replace("\'", "")
GlennRC61321f22015-07-16 13:36:54 -07001105
kelvin-onlab7cce9382015-07-17 10:21:03 -07001106 # this is the bandwith two and from the two hosts
1107 bandwidth = response.split(", ")
GlennRC61321f22015-07-16 13:36:54 -07001108
kelvin-onlab7cce9382015-07-17 10:21:03 -07001109 # there should be two elements in the bandwidth list
1110 # ['host1 to host2', 'host2 to host1"]
1111 if len(bandwidth) == 2:
1112 main.log.report(self.name + ": iperf test successful")
1113 return main.TRUE
1114 else:
1115 main.log.error(self.name + ": invalid iperf results")
1116 return main.FALSE
shahshreyae6c7cf42014-11-26 16:39:01 -08001117 else:
kelvin-onlab7cce9382015-07-17 10:21:03 -07001118 main.log.error( self.name + ": iperf test failed" )
Jon Hall7eb38402015-01-08 17:19:54 -08001119 return main.FALSE
GlennRC61321f22015-07-16 13:36:54 -07001120 except pexpect.TIMEOUT:
Jon Hall3b489db2015-10-05 14:38:37 -07001121 main.log.error( self.name + ": TIMEOUT exception found" )
1122 main.log.error( self.name + " response: " +
Jon Hall892818c2015-10-20 17:58:34 -07001123 repr( self.handle.before ) )
Jon Hall3b489db2015-10-05 14:38:37 -07001124 # NOTE: Send ctrl-c to make sure iperf is done
1125 self.handle.sendline( "\x03" )
1126 self.handle.expect( "Interrupt" )
1127 self.handle.expect( "mininet>" )
GlennRC61321f22015-07-16 13:36:54 -07001128 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -08001129 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001130 main.log.error( self.name + ": EOF exception found" )
1131 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001132 main.cleanup()
kelvin-onlab7cce9382015-07-17 10:21:03 -07001133 main.exit()
GlennRC61321f22015-07-16 13:36:54 -07001134
1135 def iperfudpAll(self, hosts, bandwidth="10M"):
1136 '''
1137 Runs the iperfudp function with a given set of hosts and specified
1138 bandwidth
kelvin-onlab7cce9382015-07-17 10:21:03 -07001139
GlennRC61321f22015-07-16 13:36:54 -07001140 @param:
1141 bandwidth: the targeted bandwidth, in megabits ('M')
1142 '''
1143 for host1 in hosts:
1144 for host2 in hosts:
1145 if host1 != host2:
1146 if self.iperfudp(host1, host2, bandwidth) == main.FALSE:
1147 main.log.error(self.name + ": iperfudp test failed for " + host1 + " and " + host2)
1148
1149 def iperfudp( self, bandwidth="10M", host1="h1", host2="h2"):
1150
kelvin-onlab7cce9382015-07-17 10:21:03 -07001151 '''
1152 Creates an iperf UDP test with a specific bandwidth.
1153 Returns true if results are valid.
GlennRC61321f22015-07-16 13:36:54 -07001154
kelvin-onlab7cce9382015-07-17 10:21:03 -07001155 @param:
1156 bandwidth: the targeted bandwidth, in megabits ('M'), to run the test
1157 '''
1158 main.log.info(self.name + ": Simple iperf UDP test between two hosts")
1159 try:
1160 # setup the mininet command
1161 cmd = 'iperfudp ' + bandwidth + " " + host1 + " " + host2
1162 self.handle.sendline(cmd)
1163 self.handle.expect("mininet>")
1164 response = self.handle.before
GlennRC61321f22015-07-16 13:36:54 -07001165
kelvin-onlab7cce9382015-07-17 10:21:03 -07001166 # check if there are in results in the mininet response
1167 if "Results:" in response:
Jon Hall892818c2015-10-20 17:58:34 -07001168 main.log.report(self.name + ": iperfudp test completed")
kelvin-onlab7cce9382015-07-17 10:21:03 -07001169 # parse the results
1170 response = response.split("\r\n")
1171 response = response[len(response)-2]
1172 response = response.split(": ")
1173 response = response[len(response)-1]
1174 response = response.replace("[", "")
1175 response = response.replace("]", "")
1176 response = response.replace("\'", "")
GlennRC61321f22015-07-16 13:36:54 -07001177
kelvin-onlab7cce9382015-07-17 10:21:03 -07001178 mnBandwidth = response.split(", ")
GlennRC61321f22015-07-16 13:36:54 -07001179
kelvin-onlab7cce9382015-07-17 10:21:03 -07001180 # check to see if there are at least three entries
1181 # ['bandwidth', 'host1 to host2', 'host2 to host1']
1182 if len(mnBandwidth) == 3:
1183 # if one entry is blank then something is wrong
1184 for item in mnBandwidth:
1185 if item == "":
1186 main.log.error(self.name + ": Could not parse iperf output")
1187 main.log.error(self.name + ": invalid iperfudp results")
1188 return main.FALSE
1189 # otherwise results are vaild
1190 main.log.report(self.name + ": iperfudp test successful")
1191 return main.TRUE
1192 else:
1193 main.log.error(self.name + ": invalid iperfudp results")
1194 return main.FALSE
GlennRC61321f22015-07-16 13:36:54 -07001195
kelvin-onlab7cce9382015-07-17 10:21:03 -07001196 except pexpect.EOF:
1197 main.log.error( self.name + ": EOF exception found" )
1198 main.log.error( self.name + ": " + self.handle.before )
1199 main.cleanup()
1200 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -08001201
Jon Hall7eb38402015-01-08 17:19:54 -08001202 def nodes( self ):
1203 main.log.info( self.name + ": List all nodes." )
Jon Hall6094a362014-04-11 14:46:56 -07001204 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001205 response = self.execute(
1206 cmd='nodes',
1207 prompt='mininet>',
1208 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001209 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001210 main.log.error( self.name + ": EOF exception found" )
1211 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001212 main.cleanup()
1213 main.exit()
Jon Hall668ed802014-04-08 17:17:59 -07001214 return response
Jon Hallfbc828e2015-01-06 17:30:19 -08001215
Jon Hall7eb38402015-01-08 17:19:54 -08001216 def pingpair( self ):
1217 main.log.info( self.name + ": Ping between first two hosts" )
Jon Hall6094a362014-04-11 14:46:56 -07001218 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001219 response = self.execute(
1220 cmd='pingpair',
1221 prompt='mininet>',
1222 timeout=20 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001223 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001224 main.log.error( self.name + ": EOF exception found" )
1225 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001226 main.cleanup()
1227 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -08001228
Jon Hall7eb38402015-01-08 17:19:54 -08001229 if re.search( ',\s0\%\spacket\sloss', response ):
1230 main.log.info( self.name + ": Ping between two hosts SUCCESSFUL" )
adminbae64d82013-08-01 10:50:15 -07001231 return main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001232 else:
1233 main.log.error( self.name + ": PACKET LOST, HOSTS NOT REACHABLE" )
adminbae64d82013-08-01 10:50:15 -07001234 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -08001235
Jon Hall7eb38402015-01-08 17:19:54 -08001236 def link( self, **linkargs ):
1237 """
GlennRCed771242016-01-13 17:02:47 -08001238 Bring link( s ) between two nodes up or down
1239 """
Jon Hall6094a362014-04-11 14:46:56 -07001240 try:
GlennRCed771242016-01-13 17:02:47 -08001241 args = utilities.parse_args( [ "END1", "END2", "OPTION" ], **linkargs )
1242 end1 = args[ "END1" ] if args[ "END1" ] is not None else ""
1243 end2 = args[ "END2" ] if args[ "END2" ] is not None else ""
1244 option = args[ "OPTION" ] if args[ "OPTION" ] is not None else ""
1245
1246 main.log.info( "Bring link between " + str( end1 ) + " and " + str( end2 ) + " " + str( option ) )
1247 cmd = "link {} {} {}".format( end1, end2, option )
1248 self.handle.sendline( cmd )
Jon Hall7eb38402015-01-08 17:19:54 -08001249 self.handle.expect( "mininet>" )
GlennRCed771242016-01-13 17:02:47 -08001250 response = self.handle.before
1251 main.log.info( response )
1252
1253 return main.TRUE
1254 except pexpect.TIMEOUT:
1255 main.log.exception( self.name + ": Command timed out" )
1256 return None
Jon Hallfbc828e2015-01-06 17:30:19 -08001257 except pexpect.EOF:
GlennRCed771242016-01-13 17:02:47 -08001258 main.log.exception( self.name + ": connection closed." )
Jon Hall6094a362014-04-11 14:46:56 -07001259 main.cleanup()
1260 main.exit()
GlennRCed771242016-01-13 17:02:47 -08001261 except Exception:
1262 main.log.exception( self.name + ": Uncaught exception!" )
1263 main.cleanup()
1264 main.exit()
Jon Hallfbc828e2015-01-06 17:30:19 -08001265
pingping-lin8244a3b2015-09-16 13:36:56 -07001266 def switch( self, **switchargs ):
1267 """
1268 start/stop a switch
1269 """
1270 args = utilities.parse_args( [ "SW", "OPTION" ], **switchargs )
1271 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1272 option = args[ "OPTION" ] if args[ "OPTION" ] is not None else ""
1273 command = "switch " + str( sw ) + " " + str( option )
1274 main.log.info( command )
1275 try:
1276 self.handle.sendline( command )
1277 self.handle.expect( "mininet>" )
1278 except pexpect.TIMEOUT:
1279 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1280 main.cleanup()
1281 main.exit()
1282 except pexpect.EOF:
1283 main.log.error( self.name + ": EOF exception found" )
1284 main.log.error( self.name + ": " + self.handle.before )
1285 main.cleanup()
1286 main.exit()
1287 return main.TRUE
1288
pingping-lin5bb663b2015-09-24 11:47:50 -07001289 def node( self, nodeName, commandStr ):
1290 """
1291 Carry out a command line on a given node
1292 @parm:
1293 nodeName: the node name in Mininet testbed
1294 commandStr: the command line will be carried out on the node
1295 Example: main.Mininet.node( nodeName="h1", commandStr="ls" )
1296 """
1297 command = str( nodeName ) + " " + str( commandStr )
1298 main.log.info( command )
1299
1300 try:
1301 response = self.execute( cmd = command, prompt = "mininet>" )
1302 if re.search( "Unknown command", response ):
1303 main.log.warn( response )
1304 return main.FALSE
1305 except pexpect.TIMEOUT:
1306 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1307 main.cleanup()
1308 main.exit()
1309 except pexpect.EOF:
1310 main.log.error( self.name + ": EOF exception found" )
1311 main.log.error( self.name + ": " + self.handle.before )
1312 main.cleanup()
1313 main.exit()
1314 main.log.info( " response is :" )
1315 main.log.info( response )
1316 return response
1317
Jon Hall7eb38402015-01-08 17:19:54 -08001318 def yank( self, **yankargs ):
1319 """
1320 yank a mininet switch interface to a host"""
1321 main.log.info( 'Yank the switch interface attached to a host' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001322 args = utilities.parse_args( [ "SW", "INTF" ], **yankargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001323 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1324 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
1325 command = "py " + str( sw ) + '.detach("' + str(intf) + '")'
Jon Hall6094a362014-04-11 14:46:56 -07001326 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001327 response = self.execute(
1328 cmd=command,
1329 prompt="mininet>",
1330 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001331 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001332 main.log.error( self.name + ": EOF exception found" )
1333 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001334 main.cleanup()
1335 main.exit()
adminaeedddd2013-08-02 15:14:15 -07001336 return main.TRUE
1337
Jon Hall7eb38402015-01-08 17:19:54 -08001338 def plug( self, **plugargs ):
1339 """
1340 plug the yanked mininet switch interface to a switch"""
1341 main.log.info( 'Plug the switch interface attached to a switch' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001342 args = utilities.parse_args( [ "SW", "INTF" ], **plugargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001343 sw = args[ "SW" ] if args[ "SW" ] is not None else ""
1344 intf = args[ "INTF" ] if args[ "INTF" ] is not None else ""
1345 command = "py " + str( sw ) + '.attach("' + str(intf) + '")'
Jon Hall6094a362014-04-11 14:46:56 -07001346 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001347 response = self.execute(
1348 cmd=command,
1349 prompt="mininet>",
1350 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001351 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001352 main.log.error( self.name + ": EOF exception found" )
1353 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001354 main.cleanup()
1355 main.exit()
adminbae64d82013-08-01 10:50:15 -07001356 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -08001357
Jon Hall7eb38402015-01-08 17:19:54 -08001358 def dpctl( self, **dpctlargs ):
1359 """
1360 Run dpctl command on all switches."""
1361 main.log.info( 'Run dpctl command on all switches' )
kelvin-onlab7d0c9672015-01-20 15:56:22 -08001362 args = utilities.parse_args( [ "CMD", "ARGS" ], **dpctlargs )
Jon Hall7eb38402015-01-08 17:19:54 -08001363 cmd = args[ "CMD" ] if args[ "CMD" ] is not None else ""
1364 cmdargs = args[ "ARGS" ] if args[ "ARGS" ] is not None else ""
1365 command = "dpctl " + cmd + " " + str( cmdargs )
1366 try:
1367 response = self.execute(
1368 cmd=command,
1369 prompt="mininet>",
1370 timeout=10 )
1371 except pexpect.EOF:
1372 main.log.error( self.name + ": EOF exception found" )
1373 main.log.error( self.name + ": " + self.handle.before )
1374 main.cleanup()
1375 main.exit()
1376 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -08001377
kelvin-onlabd3b64892015-01-20 13:26:24 -08001378 def getVersion( self ):
Jon Halld80cc142015-07-06 13:36:05 -07001379 # FIXME: What uses this? This should be refactored to get
Jon Hallff6b4b22015-02-23 09:25:15 -08001380 # version from MN and not some other file
kelvin-onlabd3b64892015-01-20 13:26:24 -08001381 fileInput = path + '/lib/Mininet/INSTALL'
1382 version = super( Mininet, self ).getVersion()
adminbae64d82013-08-01 10:50:15 -07001383 pattern = 'Mininet\s\w\.\w\.\w\w*'
kelvin-onlabd3b64892015-01-20 13:26:24 -08001384 for line in open( fileInput, 'r' ).readlines():
Jon Hall7eb38402015-01-08 17:19:54 -08001385 result = re.match( pattern, line )
adminbae64d82013-08-01 10:50:15 -07001386 if result:
Jon Hall7eb38402015-01-08 17:19:54 -08001387 version = result.group( 0 )
Jon Hallec3c21e2014-11-10 22:22:37 -05001388 return version
adminbae64d82013-08-01 10:50:15 -07001389
kelvin-onlabd3b64892015-01-20 13:26:24 -08001390 def getSwController( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001391 """
Jon Hallec3c21e2014-11-10 22:22:37 -05001392 Parameters:
1393 sw: The name of an OVS switch. Example "s1"
1394 Return:
Jon Hall7eb38402015-01-08 17:19:54 -08001395 The output of the command from the mininet cli
1396 or main.FALSE on timeout"""
1397 command = "sh ovs-vsctl get-controller " + str( sw )
admin2a9548d2014-06-17 14:08:07 -07001398 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001399 response = self.execute(
1400 cmd=command,
1401 prompt="mininet>",
1402 timeout=10 )
admin2a9548d2014-06-17 14:08:07 -07001403 if response:
Jon Hallec3c21e2014-11-10 22:22:37 -05001404 return response
admin2a9548d2014-06-17 14:08:07 -07001405 else:
1406 return main.FALSE
1407 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001408 main.log.error( self.name + ": EOF exception found" )
1409 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07001410 main.cleanup()
1411 main.exit()
adminbae64d82013-08-01 10:50:15 -07001412
Charles Chan029be652015-08-24 01:46:10 +08001413 def assignSwController( self, sw, ip, port="6653", ptcp="" ):
Jon Hall7eb38402015-01-08 17:19:54 -08001414 """
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001415 Description:
1416 Assign switches to the controllers ( for ovs use only )
1417 Required:
1418 sw - Name of the switch. This can be a list or a string.
1419 ip - Ip addresses of controllers. This can be a list or a string.
1420 Optional:
Charles Chan029be652015-08-24 01:46:10 +08001421 port - ONOS use port 6653, if no list of ports is passed, then
1422 the all the controller will use 6653 as their port number
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001423 ptcp - ptcp number, This can be a string or a list that has
1424 the same length as switch. This is optional and not required
1425 when using ovs switches.
1426 NOTE: If switches and ptcp are given in a list type they should have the
1427 same length and should be in the same order, Eg. sw=[ 's1' ... n ]
1428 ptcp=[ '6637' ... n ], s1 has ptcp number 6637 and so on.
Jon Hallf89c8552014-04-02 13:14:06 -07001429
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001430 Return:
1431 Returns main.TRUE if mininet correctly assigned switches to
1432 controllers, otherwise it will return main.FALSE or an appropriate
1433 exception(s)
1434 """
1435 assignResult = main.TRUE
1436 # Initial ovs command
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001437 commandList = []
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001438 command = "sh ovs-vsctl set-controller "
1439 onosIp = ""
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001440 try:
1441 if isinstance( ip, types.StringType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001442 onosIp = "tcp:" + str( ip ) + ":"
kelvin-onlab5c2df432015-06-11 17:29:56 -07001443 if isinstance( port, types.StringType ) or \
1444 isinstance( port, types.IntType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001445 onosIp += str( port )
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001446 elif isinstance( port, types.ListType ):
1447 main.log.error( self.name + ": Only one controller " +
1448 "assigned and a list of ports has" +
1449 " been passed" )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001450 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001451 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001452 main.log.error( self.name + ": Invalid controller port " +
1453 "number. Please specify correct " +
1454 "controller port" )
1455 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001456
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001457 elif isinstance( ip, types.ListType ):
kelvin-onlab5c2df432015-06-11 17:29:56 -07001458 if isinstance( port, types.StringType ) or \
1459 isinstance( port, types.IntType ):
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001460 for ipAddress in ip:
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001461 onosIp += "tcp:" + str( ipAddress ) + ":" + \
1462 str( port ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001463 elif isinstance( port, types.ListType ):
1464 if ( len( ip ) != len( port ) ):
1465 main.log.error( self.name + ": Port list = " +
1466 str( len( port ) ) +
1467 "should be the same as controller" +
1468 " ip list = " + str( len( ip ) ) )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001469 return main.FALSE
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001470 else:
1471 onosIp = ""
1472 for ipAddress, portNum in zip( ip, port ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001473 onosIp += "tcp:" + str( ipAddress ) + ":" + \
1474 str( portNum ) + " "
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001475 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001476 main.log.error( self.name + ": Invalid controller port " +
1477 "number. Please specify correct " +
1478 "controller port" )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001479 return main.FALSE
kelvin-onlabe5edb9e2015-06-12 09:38:47 -07001480 else:
1481 main.log.error( self.name + ": Invalid ip address" )
1482 return main.FALSE
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001483
1484 if isinstance( sw, types.StringType ):
1485 command += sw + " "
1486 if ptcp:
1487 if isinstance( ptcp, types.StringType ):
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001488 command += "ptcp:" + str( ptcp ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001489 elif isinstance( ptcp, types.ListType ):
1490 main.log.error( self.name + ": Only one switch is " +
1491 "being set and multiple PTCP is " +
1492 "being passed " )
1493 else:
1494 main.log.error( self.name + ": Invalid PTCP" )
1495 ptcp = ""
1496 command += onosIp
1497 commandList.append( command )
1498
1499 elif isinstance( sw, types.ListType ):
1500 if ptcp:
1501 if isinstance( ptcp, types.ListType ):
1502 if len( ptcp ) != len( sw ):
1503 main.log.error( self.name + ": PTCP length = " +
1504 str( len( ptcp ) ) +
1505 " is not the same as switch" +
1506 " length = " +
1507 str( len( sw ) ) )
1508 return main.FALSE
1509 else:
1510 for switch, ptcpNum in zip( sw, ptcp ):
1511 tempCmd = "sh ovs-vsctl set-controller "
kelvin-onlabf713d7c2015-06-11 14:29:05 -07001512 tempCmd += switch + " ptcp:" + \
Jon Halld80cc142015-07-06 13:36:05 -07001513 str( ptcpNum ) + " "
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001514 tempCmd += onosIp
1515 commandList.append( tempCmd )
1516 else:
1517 main.log.error( self.name + ": Invalid PTCP" )
1518 return main.FALSE
1519 else:
1520 for switch in sw:
1521 tempCmd = "sh ovs-vsctl set-controller "
1522 tempCmd += switch + " " + onosIp
1523 commandList.append( tempCmd )
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001524 else:
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001525 main.log.error( self.name + ": Invalid switch type " )
1526 return main.FALSE
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001527
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001528 for cmd in commandList:
1529 try:
kelvin-onlabfa6ada82015-06-11 13:06:24 -07001530 self.execute( cmd=cmd, prompt="mininet>", timeout=5 )
kelvin-onlab4f9f7e02015-06-11 14:07:20 -07001531 except pexpect.TIMEOUT:
1532 main.log.error( self.name + ": pexpect.TIMEOUT found" )
1533 return main.FALSE
1534 except pexpect.EOF:
1535 main.log.error( self.name + ": EOF exception found" )
1536 main.log.error( self.name + ": " + self.handle.before )
1537 main.cleanup()
1538 main.exit()
1539 return main.TRUE
1540 except Exception:
1541 main.log.exception( self.name + ": Uncaught exception!" )
1542 main.cleanup()
1543 main.exit()
adminbae64d82013-08-01 10:50:15 -07001544
kelvin-onlabd3b64892015-01-20 13:26:24 -08001545 def deleteSwController( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001546 """
1547 Removes the controller target from sw"""
1548 command = "sh ovs-vsctl del-controller " + str( sw )
Jon Hall0819fd92014-05-23 12:08:13 -07001549 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001550 response = self.execute(
1551 cmd=command,
1552 prompt="mininet>",
1553 timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -08001554 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001555 main.log.error( self.name + ": EOF exception found" )
1556 main.log.error( self.name + ": " + self.handle.before )
Jon Hall0819fd92014-05-23 12:08:13 -07001557 main.cleanup()
1558 main.exit()
1559 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001560 main.log.info( response )
Jon Hall0819fd92014-05-23 12:08:13 -07001561
kelvin-onlabd3b64892015-01-20 13:26:24 -08001562 def addSwitch( self, sw, **kwargs ):
Jon Hall7eb38402015-01-08 17:19:54 -08001563 """
Jon Hallb1290e82014-11-18 16:17:48 -05001564 adds a switch to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001565 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001566 dynamic_topo branch
Jon Hallb1290e82014-11-18 16:17:48 -05001567 NOTE: cannot currently specify what type of switch
1568 required params:
Jon Hallefbd9792015-03-05 16:11:36 -08001569 sw = name of the new switch as a string
1570 optional keywords:
Jon Hallb1290e82014-11-18 16:17:48 -05001571 dpid = "dpid"
Jon Hallefbd9792015-03-05 16:11:36 -08001572 returns: main.FALSE on an error, else main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001573 """
1574 dpid = kwargs.get( 'dpid', '' )
Jon Hallffb386d2014-11-21 13:43:38 -08001575 command = "addswitch " + str( sw ) + " " + str( dpid )
Jon Hallb1290e82014-11-18 16:17:48 -05001576 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001577 response = self.execute(
1578 cmd=command,
1579 prompt="mininet>",
1580 timeout=10 )
1581 if re.search( "already exists!", 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( "Error", response ):
1585 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001586 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001587 elif re.search( "usage:", response ):
1588 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001589 return main.FALSE
1590 else:
1591 return main.TRUE
1592 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001593 main.log.error( self.name + ": EOF exception found" )
Jon Halld80cc142015-07-06 13:36:05 -07001594 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001595 main.cleanup()
1596 main.exit()
1597
kelvin-onlabd3b64892015-01-20 13:26:24 -08001598 def delSwitch( self, sw ):
Jon Hall7eb38402015-01-08 17:19:54 -08001599 """
Jon Hallbe6dfc42015-01-12 17:37:25 -08001600 delete a switch from the mininet topology
1601 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001602 dynamic_topo branch
Jon Hallbe6dfc42015-01-12 17:37:25 -08001603 required params:
Jon Hallefbd9792015-03-05 16:11:36 -08001604 sw = name of the switch as a string
1605 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001606 command = "delswitch " + str( sw )
Jon Hallb1290e82014-11-18 16:17:48 -05001607 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001608 response = self.execute(
1609 cmd=command,
1610 prompt="mininet>",
1611 timeout=10 )
1612 if re.search( "no switch named", 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( "Error", response ):
1616 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001617 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001618 elif re.search( "usage:", response ):
1619 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001620 return main.FALSE
1621 else:
1622 return main.TRUE
1623 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001624 main.log.error( self.name + ": EOF exception found" )
1625 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001626 main.cleanup()
1627 main.exit()
1628
kelvin-onlabd3b64892015-01-20 13:26:24 -08001629 def addLink( self, node1, node2 ):
Jon Hall7eb38402015-01-08 17:19:54 -08001630 """
1631 add a link to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001632 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001633 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001634 NOTE: cannot currently specify what type of link
1635 required params:
1636 node1 = the string node name of the first endpoint of the link
1637 node2 = the string node name of the second endpoint of the link
Jon Hallefbd9792015-03-05 16:11:36 -08001638 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001639 command = "addlink " + str( node1 ) + " " + str( node2 )
Jon Hallb1290e82014-11-18 16:17:48 -05001640 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001641 response = self.execute(
1642 cmd=command,
1643 prompt="mininet>",
1644 timeout=10 )
1645 if re.search( "doesnt exist!", 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( "Error", response ):
1649 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001650 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001651 elif re.search( "usage:", response ):
1652 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001653 return main.FALSE
1654 else:
1655 return main.TRUE
1656 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001657 main.log.error( self.name + ": EOF exception found" )
1658 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001659 main.cleanup()
1660 main.exit()
1661
kelvin-onlabd3b64892015-01-20 13:26:24 -08001662 def delLink( self, node1, node2 ):
Jon Hall7eb38402015-01-08 17:19:54 -08001663 """
1664 delete a link from the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001665 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001666 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001667 required params:
1668 node1 = the string node name of the first endpoint of the link
1669 node2 = the string node name of the second endpoint of the link
Jon Hallefbd9792015-03-05 16:11:36 -08001670 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001671 command = "dellink " + str( node1 ) + " " + str( node2 )
Jon Hallb1290e82014-11-18 16:17:48 -05001672 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001673 response = self.execute(
1674 cmd=command,
1675 prompt="mininet>",
1676 timeout=10 )
1677 if re.search( "no node named", 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( "Error", response ):
1681 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001682 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001683 elif re.search( "usage:", response ):
1684 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001685 return main.FALSE
1686 else:
1687 return main.TRUE
1688 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001689 main.log.error( self.name + ": EOF exception found" )
1690 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001691 main.cleanup()
1692 main.exit()
1693
kelvin-onlabd3b64892015-01-20 13:26:24 -08001694 def addHost( self, hostname, **kwargs ):
Jon Hall7eb38402015-01-08 17:19:54 -08001695 """
Jon Hallb1290e82014-11-18 16:17:48 -05001696 Add a host to the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001697 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001698 dynamic_topo branch
Jon Hallb1290e82014-11-18 16:17:48 -05001699 NOTE: cannot currently specify what type of host
1700 required params:
1701 hostname = the string hostname
1702 optional key-value params
1703 switch = "switch name"
Jon Hallefbd9792015-03-05 16:11:36 -08001704 returns: main.FALSE on an error, else main.TRUE
Jon Hall7eb38402015-01-08 17:19:54 -08001705 """
1706 switch = kwargs.get( 'switch', '' )
Jon Hallffb386d2014-11-21 13:43:38 -08001707 command = "addhost " + str( hostname ) + " " + str( switch )
Jon Hallb1290e82014-11-18 16:17:48 -05001708 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001709 response = self.execute(
1710 cmd=command,
1711 prompt="mininet>",
1712 timeout=10 )
1713 if re.search( "already 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( "doesnt exists!", response ):
1717 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001718 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001719 elif re.search( "Error", response ):
1720 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001721 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001722 elif re.search( "usage:", response ):
1723 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001724 return main.FALSE
1725 else:
1726 return main.TRUE
1727 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001728 main.log.error( self.name + ": EOF exception found" )
1729 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001730 main.cleanup()
1731 main.exit()
1732
kelvin-onlabd3b64892015-01-20 13:26:24 -08001733 def delHost( self, hostname ):
Jon Hall7eb38402015-01-08 17:19:54 -08001734 """
1735 delete a host from the mininet topology
Jon Hallbe6dfc42015-01-12 17:37:25 -08001736 NOTE: This uses a custom mn function. MN repo should be on
Jon Hall272a4db2015-01-12 17:43:48 -08001737 dynamic_topo branch
Jon Hall7eb38402015-01-08 17:19:54 -08001738 NOTE: this uses a custom mn function
1739 required params:
1740 hostname = the string hostname
Jon Hallefbd9792015-03-05 16:11:36 -08001741 returns: main.FALSE on an error, else main.TRUE"""
Jon Hallffb386d2014-11-21 13:43:38 -08001742 command = "delhost " + str( hostname )
Jon Hallb1290e82014-11-18 16:17:48 -05001743 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001744 response = self.execute(
1745 cmd=command,
1746 prompt="mininet>",
1747 timeout=10 )
1748 if re.search( "no host named", 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( "Error", response ):
1752 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001753 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001754 elif re.search( "usage:", response ):
1755 main.log.warn( response )
Jon Hallb1290e82014-11-18 16:17:48 -05001756 return main.FALSE
1757 else:
1758 return main.TRUE
1759 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001760 main.log.error( self.name + ": EOF exception found" )
1761 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05001762 main.cleanup()
1763 main.exit()
Jon Hall0819fd92014-05-23 12:08:13 -07001764
Jon Hall7eb38402015-01-08 17:19:54 -08001765 def disconnect( self ):
kelvin-onlaba1484582015-02-02 15:46:20 -08001766 """
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001767 Called at the end of the test to stop the mininet and
1768 disconnect the handle.
kelvin-onlaba1484582015-02-02 15:46:20 -08001769 """
Jon Halld80cc142015-07-06 13:36:05 -07001770 self.handle.sendline( '' )
Jon Halld61331b2015-02-17 16:35:47 -08001771 i = self.handle.expect( [ 'mininet>', pexpect.EOF, pexpect.TIMEOUT ],
Jon Halld80cc142015-07-06 13:36:05 -07001772 timeout=2 )
Jon Hall390696c2015-05-05 17:13:41 -07001773 response = main.TRUE
kelvin-onlaba1484582015-02-02 15:46:20 -08001774 if i == 0:
Jon Hall390696c2015-05-05 17:13:41 -07001775 response = self.stopNet()
Jon Halld61331b2015-02-17 16:35:47 -08001776 elif i == 1:
1777 return main.TRUE
kelvin-onlaba1484582015-02-02 15:46:20 -08001778 # print "Disconnecting Mininet"
1779 if self.handle:
1780 self.handle.sendline( "exit" )
1781 self.handle.expect( "exit" )
1782 self.handle.expect( "(.*)" )
kelvin-onlaba1484582015-02-02 15:46:20 -08001783 else:
1784 main.log.error( "Connection failed to the host" )
kelvin-onlaba1484582015-02-02 15:46:20 -08001785 return response
1786
Jon Halld80cc142015-07-06 13:36:05 -07001787 def stopNet( self, fileName="", timeout=5 ):
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001788 """
Jon Hall21270ac2015-02-16 17:59:55 -08001789 Stops mininet.
Jon Hallefbd9792015-03-05 16:11:36 -08001790 Returns main.TRUE if the mininet successfully stops and
Jon Hall21270ac2015-02-16 17:59:55 -08001791 main.FALSE if the pexpect handle does not exist.
1792
Jon Halld61331b2015-02-17 16:35:47 -08001793 Will cleanup and exit the test if mininet fails to stop
kelvin-onlab00ac67b2015-02-04 09:52:02 -08001794 """
Jon Halld61331b2015-02-17 16:35:47 -08001795 main.log.info( self.name + ": Stopping mininet..." )
adminbae64d82013-08-01 10:50:15 -07001796 response = ''
1797 if self.handle:
Jon Hall6094a362014-04-11 14:46:56 -07001798 try:
Jon Halld80cc142015-07-06 13:36:05 -07001799 self.handle.sendline( "" )
kelvin-onlab56a3f462015-02-06 14:04:43 -08001800 i = self.handle.expect( [ 'mininet>',
1801 '\$',
1802 pexpect.EOF,
1803 pexpect.TIMEOUT ],
1804 timeout )
1805 if i == 0:
1806 main.log.info( "Exiting mininet..." )
Jon Hall7eb38402015-01-08 17:19:54 -08001807 response = self.execute(
1808 cmd="exit",
1809 prompt="(.*)",
1810 timeout=120 )
Jon Halld80cc142015-07-06 13:36:05 -07001811 main.log.info( self.name + ": Stopped" )
Jon Hall7eb38402015-01-08 17:19:54 -08001812 self.handle.sendline( "sudo mn -c" )
shahshreya328c2a72014-11-17 10:19:50 -08001813 response = main.TRUE
Jon Hallafa8a472015-06-12 14:02:42 -07001814
kelvin-onlab56a3f462015-02-06 14:04:43 -08001815 if i == 1:
1816 main.log.info( " Mininet trying to exit while not " +
1817 "in the mininet prompt" )
1818 elif i == 2:
1819 main.log.error( "Something went wrong exiting mininet" )
1820 elif i == 3: # timeout
1821 main.log.error( "Something went wrong exiting mininet " +
1822 "TIMEOUT" )
Jon Hallafa8a472015-06-12 14:02:42 -07001823
Hari Krishnab35c6d02015-03-18 11:13:51 -07001824 if fileName:
Jon Halld80cc142015-07-06 13:36:05 -07001825 self.handle.sendline( "" )
1826 self.handle.expect( '\$' )
1827 self.handle.sendline(
1828 "sudo kill -9 \`ps -ef | grep \"" +
1829 fileName +
1830 "\" | grep -v grep | awk '{print $2}'\`" )
Jon Hallfbc828e2015-01-06 17:30:19 -08001831 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001832 main.log.error( self.name + ": EOF exception found" )
1833 main.log.error( self.name + ": " + self.handle.before )
Jon Hall6094a362014-04-11 14:46:56 -07001834 main.cleanup()
1835 main.exit()
Jon Hall7eb38402015-01-08 17:19:54 -08001836 else:
1837 main.log.error( self.name + ": Connection failed to the host" )
adminbae64d82013-08-01 10:50:15 -07001838 response = main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -08001839 return response
1840
Jon Halla5cb3412015-08-18 14:08:22 -07001841 def arping( self, srcHost="", dstHost="10.128.20.211", ethDevice="" ):
kelvin-onlab65782a82015-05-07 14:12:13 -07001842 """
1843 Description:
1844 Sends arp message from mininet host for hosts discovery
1845 Required:
1846 host - hosts name
1847 Optional:
1848 ip - ip address that does not exist in the network so there would
1849 be no reply.
1850 """
kelvin-onlabf0594d72015-05-19 17:25:12 -07001851 if ethDevice:
1852 ethDevice = '-I ' + ethDevice + ' '
Jon Halla5cb3412015-08-18 14:08:22 -07001853 cmd = srcHost + " arping -c1 " + ethDevice + dstHost
admin07529932013-11-22 14:58:28 -08001854 try:
Jon Halla5cb3412015-08-18 14:08:22 -07001855 main.log.info( "Sending: " + cmd )
kelvin-onlab65782a82015-05-07 14:12:13 -07001856 self.handle.sendline( cmd )
Jon Halla5cb3412015-08-18 14:08:22 -07001857 i = self.handle.expect( [ "mininet>", "arping: " ] )
1858 if i == 0:
1859 return main.TRUE
1860 elif i == 1:
1861 response = self.handle.before + self.handle.after
1862 self.handle.expect( "mininet>" )
1863 response += self.handle.before + self.handle.after
1864 main.log.warn( "Error sending arping, output was: " +
1865 response )
1866 return main.FALSE
1867 except pexpect.TIMEOUT:
1868 main.log.error( self.name + ": TIMEOUT exception found" )
1869 main.log.warn( self.handle.before )
1870 return main.FALSE
kelvin-onlab65782a82015-05-07 14:12:13 -07001871 except pexpect.EOF:
1872 main.log.error( self.name + ": EOF exception found" )
1873 main.log.error( self.name + ": " + self.handle.before )
1874 main.cleanup()
1875 main.exit()
admin07529932013-11-22 14:58:28 -08001876
Jon Hall7eb38402015-01-08 17:19:54 -08001877 def decToHex( self, num ):
1878 return hex( num ).split( 'x' )[ 1 ]
Jon Hallfbc828e2015-01-06 17:30:19 -08001879
Jon Hall7eb38402015-01-08 17:19:54 -08001880 def getSwitchFlowCount( self, switch ):
1881 """
1882 return the Flow Count of the switch"""
admin2a9548d2014-06-17 14:08:07 -07001883 if self.handle:
1884 cmd = "sh ovs-ofctl dump-aggregate %s" % switch
1885 try:
Jon Hall7eb38402015-01-08 17:19:54 -08001886 response = self.execute(
1887 cmd=cmd,
1888 prompt="mininet>",
1889 timeout=10 )
admin2a9548d2014-06-17 14:08:07 -07001890 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08001891 main.log.error( self.name + ": EOF exception found" )
1892 main.log.error( self.name + " " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07001893 main.cleanup()
1894 main.exit()
1895 pattern = "flow_count=(\d+)"
Jon Hall7eb38402015-01-08 17:19:54 -08001896 result = re.search( pattern, response, re.MULTILINE )
admin2a9548d2014-06-17 14:08:07 -07001897 if result is None:
Jon Hall7eb38402015-01-08 17:19:54 -08001898 main.log.info(
1899 "Couldn't find flows on switch %s, found: %s" %
1900 ( switch, response ) )
admin2a9548d2014-06-17 14:08:07 -07001901 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08001902 return result.group( 1 )
admin2a9548d2014-06-17 14:08:07 -07001903 else:
Jon Hall7eb38402015-01-08 17:19:54 -08001904 main.log.error( "Connection failed to the Mininet host" )
Jon Hallfbc828e2015-01-06 17:30:19 -08001905
GlennRC68467eb2015-11-16 18:01:01 -08001906 def flowTableComp( self, flowTable1, flowTable2 ):
1907 # This function compares the selctors and treatments of each flow
1908 try:
1909 if len(flowTable1) != len(flowTable2):
1910 main.log.warn( "Flow table lengths do not match" )
1911 return main.FALSE
GlennRCfa65fce2015-12-16 13:16:08 -08001912 dFields = ["n_bytes", "cookie", "n_packets", "duration"]
1913 for flow1, flow2 in zip(flowTable1, flowTable2):
Jon Hallacd1b182015-12-17 11:43:20 -08001914 for field in dFields:
1915 try:
1916 flow1.pop( field )
1917 except KeyError as e:
1918 main.log.warn( e )
1919 main.log.debug( flow1 )
1920 try:
1921 flow2.pop( field )
1922 except KeyError as e:
1923 main.log.warn( e )
1924 main.log.debug( flow2 )
GlennRC68467eb2015-11-16 18:01:01 -08001925 for i in range( len(flowTable1) ):
GlennRC17bbcf52015-12-14 17:31:50 -08001926 if flowTable1[i] not in flowTable2:
1927 main.log.warn( "Flow tables do not match:" )
1928 main.log.warn( "Old flow:\n{}\n not in new flow table".format( flowTable1[i] ) )
GlennRC68467eb2015-11-16 18:01:01 -08001929 return main.FALSE
Jon Hall9043c902015-07-30 14:23:44 -07001930 return main.TRUE
GlennRC68467eb2015-11-16 18:01:01 -08001931 except Exception:
1932 main.log.exception( "Uncaught exception!" )
1933 main.cleanup()
1934 main.exit()
Jon Hall9043c902015-07-30 14:23:44 -07001935
GlennRC528ad292015-11-12 10:38:18 -08001936 def parseFlowTable( self, flowTable, version="", debug=True ):
GlennRC956ea742015-11-05 16:14:15 -08001937 '''
1938 Discription: Parses flows into json format.
1939 NOTE: this can parse any string thats separated with commas
1940 Arguments:
1941 Required:
1942 flows: a list of strings that represnt flows
1943 Optional:
1944 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
1945 debug: prints out the final result
1946 returns: A list of flows in json format
1947 '''
GlennRC528ad292015-11-12 10:38:18 -08001948 jsonFlowTable = []
1949 for flow in flowTable:
GlennRC956ea742015-11-05 16:14:15 -08001950 jsonFlow = {}
GlennRC528ad292015-11-12 10:38:18 -08001951 # split up the fields of the flow
1952 parsedFlow = flow.split(", ")
1953 # get rid of any spaces in front of the field
1954 for i in range( len(parsedFlow) ):
1955 item = parsedFlow[i]
1956 if item[0] == " ":
1957 parsedFlow[i] = item[1:]
1958 # grab the selector and treatment from the parsed flow
1959 # the last element is the selector and the treatment
1960 temp = parsedFlow.pop(-1)
1961 # split up the selector and the treatment
1962 temp = temp.split(" ")
1963 index = 0
1964 # parse the flags
1965 # NOTE: This only parses one flag
1966 flag = {}
1967 if version == "1.3":
1968 flag = {"flag":[temp[index]]}
1969 index += 1
1970 # the first element is the selector and split it up
1971 sel = temp[index]
1972 index += 1
1973 sel = sel.split(",")
1974 # the priority is stuck in the selecter so put it back
1975 # in the flow
1976 parsedFlow.append(sel.pop(0))
1977 # parse selector
1978 criteria = []
1979 for item in sel:
1980 # this is the type of the packet e.g. "arp"
1981 if "=" not in item:
1982 criteria.append( {"type":item} )
1983 else:
1984 field = item.split("=")
1985 criteria.append( {field[0]:field[1]} )
GlennRC68467eb2015-11-16 18:01:01 -08001986 selector = {"selector": {"criteria":sorted(criteria)} }
GlennRC528ad292015-11-12 10:38:18 -08001987 treat = temp[index]
1988 # get rid of the action part e.g. "action=output:2"
1989 # we will add it back later
1990 treat = treat.split("=")
1991 treat.pop(0)
1992 # parse treatment
1993 action = []
1994 for item in treat:
1995 field = item.split(":")
1996 action.append( {field[0]:field[1]} )
1997 # create the treatment field and add the actions
GlennRC68467eb2015-11-16 18:01:01 -08001998 treatment = {"treatment": {"action":sorted(action)} }
GlennRC528ad292015-11-12 10:38:18 -08001999 # parse the rest of the flow
2000 for item in parsedFlow:
2001 field = item.split("=")
2002 jsonFlow.update( {field[0]:field[1]} )
2003 # add the treatment and the selector to the json flow
2004 jsonFlow.update( selector )
2005 jsonFlow.update( treatment )
2006 jsonFlow.update( flag )
GlennRC956ea742015-11-05 16:14:15 -08002007
GlennRC528ad292015-11-12 10:38:18 -08002008 if debug: main.log.debug( "\033[94mJson flow:\033[0m\n{}\n".format(jsonFlow) )
GlennRC956ea742015-11-05 16:14:15 -08002009
GlennRC528ad292015-11-12 10:38:18 -08002010 # add the json flow to the json flow table
2011 jsonFlowTable.append( jsonFlow )
GlennRC956ea742015-11-05 16:14:15 -08002012
GlennRC528ad292015-11-12 10:38:18 -08002013 return jsonFlowTable
2014
Jon Hall0a543792015-12-14 11:00:26 -08002015 def getFlowTable( self, sw, version="", debug=False):
GlennRC956ea742015-11-05 16:14:15 -08002016 '''
2017 Discription: Returns the flow table(s) on a switch or switches in a list.
2018 Each element is a flow.
2019 Arguments:
2020 Required:
2021 sw: The switch name ("s1") to retrive the flow table. Can also be
2022 a list of switches.
2023 Optional:
2024 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
2025 debug: prints out the final result
2026 '''
2027 try:
2028 switches = []
2029 if type(sw) is list:
Jon Hallca7ac292015-11-11 09:28:12 -08002030 switches.extend(sw)
GlennRC956ea742015-11-05 16:14:15 -08002031 else: switches.append(sw)
2032
2033 flows = []
2034 for s in switches:
2035 cmd = "sh ovs-ofctl dump-flows " + s
2036
GlennRC528ad292015-11-12 10:38:18 -08002037 if "1.0" == version:
2038 cmd += " -F OpenFlow10-table_id"
2039 elif "1.3" == version:
GlennRC956ea742015-11-05 16:14:15 -08002040 cmd += " -O OpenFlow13"
GlennRC956ea742015-11-05 16:14:15 -08002041
2042 main.log.info( "Sending: " + cmd )
2043 self.handle.sendline( cmd )
2044 self.handle.expect( "mininet>" )
2045 response = self.handle.before
2046 response = response.split( "\r\n" )
2047 # dump the first two elements and the last
2048 # the first element is the command that was sent
2049 # the second is the table header
2050 # the last element is empty
2051 response = response[2:-1]
2052 flows.extend( response )
2053
2054 if debug: print "Flows:\n{}\n\n".format(flows)
2055
GlennRC528ad292015-11-12 10:38:18 -08002056 return self.parseFlowTable( flows, version, debug )
GlennRC956ea742015-11-05 16:14:15 -08002057
2058 except pexpect.TIMEOUT:
2059 main.log.exception( self.name + ": Command timed out" )
2060 return None
2061 except pexpect.EOF:
2062 main.log.exception( self.name + ": connection closed." )
2063 main.cleanup()
2064 main.exit()
2065 except Exception:
2066 main.log.exception( self.name + ": Uncaught exception!" )
2067 main.cleanup()
2068 main.exit()
2069
2070 def checkFlowId( self, sw, flowId, version="1.3", debug=True ):
2071 '''
2072 Discription: Checks whether the ID provided matches a flow ID in Mininet
2073 Arguments:
2074 Required:
2075 sw: The switch name ("s1") to retrive the flow table. Can also be
2076 a list of switches.
2077 flowId: the flow ID in hex format. Can also be a list of IDs
2078 Optional:
2079 version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
2080 debug: prints out the final result
2081 returns: main.TRUE if all IDs are present, otherwise returns main.FALSE
2082 NOTE: prints out IDs that are not present
2083 '''
2084 try:
2085 main.log.info( "Getting flows from Mininet" )
2086 flows = self.getFlowTable( sw, version, debug )
2087
2088 if debug: print "flow ids:\n{}\n\n".format(flowId)
2089
2090 # Check flowId is a list or a string
2091 if type( flowId ) is str:
2092 result = False
2093 for f in flows:
2094 if flowId in f.get( 'cookie' ):
2095 result = True
2096 break
2097 # flowId is a list
2098 else:
2099 result = True
2100 # Get flow IDs from Mininet
2101 mnFlowIds = [ f.get( 'cookie' ) for f in flows ]
2102 # Save the IDs that are not in Mininet
2103 absentIds = [ x for x in flowId if x not in mnFlowIds ]
2104
2105 if debug: print "mn flow ids:\n{}\n\n".format(mnFlowIds)
2106
2107 # Print out the IDs that are not in Mininet
2108 if absentIds:
2109 main.log.warn( "Absent ids: {}".format( absentIds ) )
2110 result = False
2111
2112 return main.TRUE if result else main.FALSE
2113
2114 except Exception:
2115 main.log.exception( self.name + ": Uncaught exception!" )
2116 main.cleanup()
2117 main.exit()
2118
2119
Charles Chan029be652015-08-24 01:46:10 +08002120 def startTcpdump( self, filename, intf="eth0", port="port 6653" ):
Jon Hall7eb38402015-01-08 17:19:54 -08002121 """
Jon Hallefbd9792015-03-05 16:11:36 -08002122 Runs tpdump on an interface and saves the file
Jon Hall7eb38402015-01-08 17:19:54 -08002123 intf can be specified, or the default eth0 is used"""
admin2a9548d2014-06-17 14:08:07 -07002124 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002125 self.handle.sendline( "" )
2126 self.handle.expect( "mininet>" )
2127 self.handle.sendline(
2128 "sh sudo tcpdump -n -i " +
2129 intf +
2130 " " +
2131 port +
2132 " -w " +
2133 filename.strip() +
2134 " &" )
2135 self.handle.sendline( "" )
2136 i = self.handle.expect( [ 'No\ssuch\device',
2137 'listening\son',
2138 pexpect.TIMEOUT,
2139 "mininet>" ],
2140 timeout=10 )
2141 main.log.warn( self.handle.before + self.handle.after )
2142 self.handle.sendline( "" )
2143 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002144 if i == 0:
Jon Hall7eb38402015-01-08 17:19:54 -08002145 main.log.error(
2146 self.name +
2147 ": tcpdump - No such device exists. " +
2148 "tcpdump attempted on: " +
2149 intf )
admin2a9548d2014-06-17 14:08:07 -07002150 return main.FALSE
2151 elif i == 1:
Jon Hall7eb38402015-01-08 17:19:54 -08002152 main.log.info( self.name + ": tcpdump started on " + intf )
admin2a9548d2014-06-17 14:08:07 -07002153 return main.TRUE
2154 elif i == 2:
Jon Hall7eb38402015-01-08 17:19:54 -08002155 main.log.error(
2156 self.name +
2157 ": tcpdump command timed out! Check interface name," +
2158 " given interface was: " +
2159 intf )
admin2a9548d2014-06-17 14:08:07 -07002160 return main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08002161 elif i == 3:
2162 main.log.info( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002163 return main.TRUE
2164 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002165 main.log.error( self.name + ": tcpdump - unexpected response" )
admin2a9548d2014-06-17 14:08:07 -07002166 return main.FALSE
2167 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002168 main.log.error( self.name + ": EOF exception found" )
2169 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002170 main.cleanup()
2171 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -08002172 except Exception:
2173 main.log.exception( self.name + ": Uncaught exception!" )
admin2a9548d2014-06-17 14:08:07 -07002174 main.cleanup()
2175 main.exit()
2176
kelvin-onlabd3b64892015-01-20 13:26:24 -08002177 def stopTcpdump( self ):
Jon Hallefbd9792015-03-05 16:11:36 -08002178 """
2179 pkills tcpdump"""
admin2a9548d2014-06-17 14:08:07 -07002180 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002181 self.handle.sendline( "sh sudo pkill tcpdump" )
2182 self.handle.expect( "mininet>" )
2183 self.handle.sendline( "" )
2184 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002185 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002186 main.log.error( self.name + ": EOF exception found" )
2187 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -07002188 main.cleanup()
2189 main.exit()
Jon Hallfebb1c72015-03-05 13:30:09 -08002190 except Exception:
2191 main.log.exception( self.name + ": Uncaught exception!" )
admin2a9548d2014-06-17 14:08:07 -07002192 main.cleanup()
2193 main.exit()
2194
Jon Halld80cc142015-07-06 13:36:05 -07002195 def getPorts( self, nodeName, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002196 """
2197 Read ports from a Mininet switch.
2198
2199 Returns a json structure containing information about the
2200 ports of the given switch.
2201 """
2202 response = self.getInterfaces( nodeName )
2203 # TODO: Sanity check on response. log if no such switch exists
2204 ports = []
2205 for line in response.split( "\n" ):
2206 if not line.startswith( "name=" ):
2207 continue
2208 portVars = {}
2209 for var in line.split( "," ):
2210 key, value = var.split( "=" )
2211 portVars[ key ] = value
2212 isUp = portVars.pop( 'enabled', "True" )
2213 isUp = "True" in isUp
2214 if verbose:
2215 main.log.info( "Reading switch port %s(%s)" %
2216 ( portVars[ 'name' ], portVars[ 'mac' ] ) )
2217 mac = portVars[ 'mac' ]
Jon Halld80cc142015-07-06 13:36:05 -07002218 if mac == 'None':
Jon Hallafa8a472015-06-12 14:02:42 -07002219 mac = None
2220 ips = []
2221 ip = portVars[ 'ip' ]
2222 if ip == 'None':
2223 ip = None
2224 ips.append( ip )
2225 name = portVars[ 'name' ]
2226 if name == 'None':
2227 name = None
2228 portRe = r'[^\-]\d\-eth(?P<port>\d+)'
2229 if name == 'lo':
2230 portNo = 0xfffe # TODO: 1.0 value - Should we just return lo?
2231 else:
2232 portNo = re.search( portRe, name ).group( 'port' )
2233 ports.append( { 'of_port': portNo,
2234 'mac': str( mac ).replace( '\'', '' ),
2235 'name': name,
2236 'ips': ips,
2237 'enabled': isUp } )
2238 return ports
2239
Jon Halld80cc142015-07-06 13:36:05 -07002240 def getSwitches( self, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002241 """
2242 Read switches from Mininet.
2243
2244 Returns a dictionary whose keys are the switch names and the value is
2245 a dictionary containing information about the switch.
2246 """
Jon Halla22481b2015-07-28 17:46:01 -07002247 # NOTE: To support new Mininet switch classes, just append the new
2248 # class to the switchClasses variable
Jon Hallafa8a472015-06-12 14:02:42 -07002249
Jon Halla22481b2015-07-28 17:46:01 -07002250 # Regex patterns to parse 'dump' output
2251 # Example Switches:
Jon Hallafa8a472015-06-12 14:02:42 -07002252 # <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 -07002253 # <OVSSwitch{ 'protocols': 'OpenFlow10' } s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=25974>
Jon Halla22481b2015-07-28 17:46:01 -07002254 # <OVSSwitchNS s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None pid=22550>
2255 # <OVSBridge s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=26830>
2256 # <UserSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None pid=14737>
2257 switchClasses = r"(OVSSwitch)|(OVSBridge)|(OVSSwitchNS)|(IVSSwitch)|(LinuxBridge)|(UserSwitch)"
2258 swRE = r"<(?P<class>" + switchClasses + r")" +\
2259 r"(?P<options>\{.*\})?\s" +\
2260 r"(?P<name>[^:]+)\:\s" +\
2261 r"(?P<ports>([^,]+,)*[^,\s]+)" +\
2262 r"\spid=(?P<pid>(\d)+)"
Jon Hallafa8a472015-06-12 14:02:42 -07002263 # Update mn port info
2264 self.update()
Jon Halld80cc142015-07-06 13:36:05 -07002265 output = {}
Jon Hallafa8a472015-06-12 14:02:42 -07002266 dump = self.dump().split( "\n" )
2267 for line in dump:
Jon Halla22481b2015-07-28 17:46:01 -07002268 result = re.search( swRE, line, re.I )
2269 if result:
Jon Hallafa8a472015-06-12 14:02:42 -07002270 name = result.group( 'name' )
2271 dpid = str( self.getSwitchDPID( name ) ).zfill( 16 )
Jon Halla22481b2015-07-28 17:46:01 -07002272 pid = result.group( 'pid' )
2273 swClass = result.group( 'class' )
2274 options = result.group( 'options' )
Jon Hallafa8a472015-06-12 14:02:42 -07002275 if verbose:
2276 main.log.info( "Reading switch %s(%s)" % ( name, dpid ) )
2277 ports = self.getPorts( name )
Jon Halla22481b2015-07-28 17:46:01 -07002278 output[ name ] = { "dpid": dpid,
2279 "ports": ports,
2280 "swClass": swClass,
2281 "pid": pid,
2282 "options": options }
Jon Hallafa8a472015-06-12 14:02:42 -07002283 return output
2284
Jon Halld80cc142015-07-06 13:36:05 -07002285 def getHosts( self, verbose=False ):
Jon Hallafa8a472015-06-12 14:02:42 -07002286 """
2287 Read hosts from Mininet.
2288
2289 Returns a dictionary whose keys are the host names and the value is
2290 a dictionary containing information about the host.
2291 """
2292 # Regex patterns to parse dump output
2293 # Example host: <Host h1: h1-eth0:10.0.0.1 pid=5227>
kelvin-onlab299ab062015-07-15 10:58:27 -07002294 # <Host h1: pid=12725>
2295 # <VLANHost h12: h12-eth0.100.100.100:100.1.0.3 pid=30186>
2296 # <dualStackHost h19: h19-eth0:10.1.0.9 pid=30200>
2297 # <IPv6Host h18: h18-eth0:10.0.0.18 pid=30198>
Jon Hallafa8a472015-06-12 14:02:42 -07002298 # NOTE: Does not correctly match hosts with multi-links
2299 # <Host h2: h2-eth0:10.0.0.2,h2-eth1:10.0.1.2 pid=14386>
2300 # FIXME: Fix that
kelvin-onlabd48a68c2015-07-13 16:01:36 -07002301 hostRE = r"Host\s(?P<name>[^:]+)\:((\s(?P<ifname>[^:]+)\:" +\
Jon Halld80cc142015-07-06 13:36:05 -07002302 "(?P<ip>[^\s]+))|(\s)\spid=(?P<pid>[^>]+))"
Jon Hallafa8a472015-06-12 14:02:42 -07002303 # update mn port info
2304 self.update()
2305 # Get mininet dump
2306 dump = self.dump().split( "\n" )
Jon Hall5b0120a2015-06-12 17:35:53 -07002307 hosts = {}
Jon Hallafa8a472015-06-12 14:02:42 -07002308 for line in dump:
kelvin-onlabd48a68c2015-07-13 16:01:36 -07002309 if "Host" in line :
Jon Hallafa8a472015-06-12 14:02:42 -07002310 result = re.search( hostRE, line )
2311 name = result.group( 'name' )
2312 interfaces = []
2313 response = self.getInterfaces( name )
2314 # Populate interface info
2315 for line in response.split( "\n" ):
2316 if line.startswith( "name=" ):
2317 portVars = {}
2318 for var in line.split( "," ):
2319 key, value = var.split( "=" )
2320 portVars[ key ] = value
2321 isUp = portVars.pop( 'enabled', "True" )
2322 isUp = "True" in isUp
2323 if verbose:
2324 main.log.info( "Reading host port %s(%s)" %
2325 ( portVars[ 'name' ],
2326 portVars[ 'mac' ] ) )
2327 mac = portVars[ 'mac' ]
Jon Halld80cc142015-07-06 13:36:05 -07002328 if mac == 'None':
Jon Hallafa8a472015-06-12 14:02:42 -07002329 mac = None
2330 ips = []
2331 ip = portVars[ 'ip' ]
2332 if ip == 'None':
2333 ip = None
2334 ips.append( ip )
2335 intfName = portVars[ 'name' ]
2336 if name == 'None':
2337 name = None
2338 interfaces.append( {
2339 "name": intfName,
2340 "ips": ips,
2341 "mac": str( mac ),
2342 "isUp": isUp } )
Jon Hall5b0120a2015-06-12 17:35:53 -07002343 hosts[ name ] = { "interfaces": interfaces }
Jon Hallafa8a472015-06-12 14:02:42 -07002344 return hosts
2345
2346 def getLinks( self ):
2347 """
2348 Gathers information about current Mininet links. These links may not
2349 be up if one of the ports is down.
2350
2351 Returns a list of dictionaries with link endpoints.
2352
2353 The dictionary structure is:
Jon Halld80cc142015-07-06 13:36:05 -07002354 { 'node1': str( node1 name )
2355 'node2': str( node2 name )
2356 'port1': str( port1 of_port )
2357 'port2': str( port2 of_port ) }
Jon Hallafa8a472015-06-12 14:02:42 -07002358 Note: The port number returned is the eth#, not necessarily the of_port
2359 number. In Mininet, for OVS switch, these should be the same. For
2360 hosts, this is just the eth#.
2361 """
2362 self.update()
2363 response = self.links().split( '\n' )
2364
2365 # Examples:
2366 # s1-eth3<->s2-eth1 (OK OK)
2367 # s13-eth3<->h27-eth0 (OK OK)
2368 linkRE = "(?P<node1>[\w]+)\-eth(?P<port1>[\d]+)\<\-\>" +\
2369 "(?P<node2>[\w]+)\-eth(?P<port2>[\d]+)"
2370 links = []
2371 for line in response:
2372 match = re.search( linkRE, line )
2373 if match:
2374 node1 = match.group( 'node1' )
2375 node2 = match.group( 'node2' )
2376 port1 = match.group( 'port1' )
2377 port2 = match.group( 'port2' )
2378 links.append( { 'node1': node1,
2379 'node2': node2,
2380 'port1': port1,
2381 'port2': port2 } )
2382 return links
2383
2384 def compareSwitches( self, switches, switchesJson, portsJson ):
Jon Hall7eb38402015-01-08 17:19:54 -08002385 """
2386 Compare mn and onos switches
Jon Hallafa8a472015-06-12 14:02:42 -07002387 switchesJson: parsed json object from the onos devices api
Jon Hall3d87d502014-10-17 18:37:42 -04002388
Jon Hallafa8a472015-06-12 14:02:42 -07002389 Dependencies:
2390 1. numpy - "sudo pip install numpy"
2391 """
2392 from numpy import uint64
Jon Hall3d87d502014-10-17 18:37:42 -04002393 # created sorted list of dpid's in MN and ONOS for comparison
Jon Hall7eb38402015-01-08 17:19:54 -08002394 mnDPIDs = []
Jon Hallafa8a472015-06-12 14:02:42 -07002395 for swName, switch in switches.iteritems():
Jon Hall7eb38402015-01-08 17:19:54 -08002396 mnDPIDs.append( switch[ 'dpid' ].lower() )
Jon Hall3d87d502014-10-17 18:37:42 -04002397 mnDPIDs.sort()
kelvin-onlabd3b64892015-01-20 13:26:24 -08002398 if switchesJson == "": # if rest call fails
Jon Hall7eb38402015-01-08 17:19:54 -08002399 main.log.error(
2400 self.name +
Jon Hallfeff3082015-05-19 10:23:26 -07002401 ".compareSwitches(): Empty JSON object given from ONOS" )
Jon Hall3d87d502014-10-17 18:37:42 -04002402 return main.FALSE
kelvin-onlabd3b64892015-01-20 13:26:24 -08002403 onos = switchesJson
Jon Hall7eb38402015-01-08 17:19:54 -08002404 onosDPIDs = []
Jon Hall3d87d502014-10-17 18:37:42 -04002405 for switch in onos:
Jon Hall7eb38402015-01-08 17:19:54 -08002406 if switch[ 'available' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002407 onosDPIDs.append(
2408 switch[ 'id' ].replace(
2409 ":",
2410 '' ).replace(
2411 "of",
2412 '' ).lower() )
Jon Hall3d87d502014-10-17 18:37:42 -04002413 onosDPIDs.sort()
Jon Hall3d87d502014-10-17 18:37:42 -04002414
Jon Hall7eb38402015-01-08 17:19:54 -08002415 if mnDPIDs != onosDPIDs:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002416 switchResults = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002417 main.log.error( "Switches in MN but not in ONOS:" )
Jon Hall7eb38402015-01-08 17:19:54 -08002418 list1 = [ switch for switch in mnDPIDs if switch not in onosDPIDs ]
Jon Hallafa8a472015-06-12 14:02:42 -07002419 main.log.error( str( list1 ) )
2420 main.log.error( "Switches in ONOS but not in MN:" )
Jon Hall7eb38402015-01-08 17:19:54 -08002421 list2 = [ switch for switch in onosDPIDs if switch not in mnDPIDs ]
Jon Hallafa8a472015-06-12 14:02:42 -07002422 main.log.error( str( list2 ) )
Jon Hall7eb38402015-01-08 17:19:54 -08002423 else: # list of dpid's match in onos and mn
kelvin-onlabd3b64892015-01-20 13:26:24 -08002424 switchResults = main.TRUE
Jon Hallafa8a472015-06-12 14:02:42 -07002425 finalResults = switchResults
Jon Hall3d87d502014-10-17 18:37:42 -04002426
Jon Hall7eb38402015-01-08 17:19:54 -08002427 # FIXME: this does not look for extra ports in ONOS, only checks that
2428 # ONOS has what is in MN
kelvin-onlabd3b64892015-01-20 13:26:24 -08002429 portsResults = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002430
Jon Hall7eb38402015-01-08 17:19:54 -08002431 # PORTS
Jon Hallafa8a472015-06-12 14:02:42 -07002432 for name, mnSwitch in switches.iteritems():
kelvin-onlabd3b64892015-01-20 13:26:24 -08002433 mnPorts = []
2434 onosPorts = []
2435 switchResult = main.TRUE
2436 for port in mnSwitch[ 'ports' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002437 if port[ 'enabled' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002438 mnPorts.append( int( port[ 'of_port' ] ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002439 for onosSwitch in portsJson:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002440 if onosSwitch[ 'device' ][ 'available' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002441 if onosSwitch[ 'device' ][ 'id' ].replace(
2442 ':',
2443 '' ).replace(
2444 "of",
2445 '' ) == mnSwitch[ 'dpid' ]:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002446 for port in onosSwitch[ 'ports' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002447 if port[ 'isEnabled' ]:
2448 if port[ 'port' ] == 'local':
kelvin-onlabd3b64892015-01-20 13:26:24 -08002449 # onosPorts.append( 'local' )
2450 onosPorts.append( long( uint64( -2 ) ) )
Jon Hallb1290e82014-11-18 16:17:48 -05002451 else:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002452 onosPorts.append( int( port[ 'port' ] ) )
Jon Hallb1290e82014-11-18 16:17:48 -05002453 break
kelvin-onlabd3b64892015-01-20 13:26:24 -08002454 mnPorts.sort( key=float )
2455 onosPorts.sort( key=float )
Jon Hallafa8a472015-06-12 14:02:42 -07002456
kelvin-onlabd3b64892015-01-20 13:26:24 -08002457 mnPortsLog = mnPorts
2458 onosPortsLog = onosPorts
2459 mnPorts = [ x for x in mnPorts ]
2460 onosPorts = [ x for x in onosPorts ]
Jon Hall38481722014-11-04 16:50:05 -05002461
Jon Hall7eb38402015-01-08 17:19:54 -08002462 # TODO: handle other reserved port numbers besides LOCAL
2463 # NOTE: Reserved ports
2464 # Local port: -2 in Openflow, ONOS shows 'local', we store as
2465 # long( uint64( -2 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002466 for mnPort in mnPortsLog:
2467 if mnPort in onosPorts:
Jon Hall7eb38402015-01-08 17:19:54 -08002468 # don't set results to true here as this is just one of
2469 # many checks and it might override a failure
kelvin-onlabd3b64892015-01-20 13:26:24 -08002470 mnPorts.remove( mnPort )
2471 onosPorts.remove( mnPort )
Jon Hallafa8a472015-06-12 14:02:42 -07002472
Jon Hall7eb38402015-01-08 17:19:54 -08002473 # NOTE: OVS reports this as down since there is no link
Jon Hallb1290e82014-11-18 16:17:48 -05002474 # So ignoring these for now
Jon Hall7eb38402015-01-08 17:19:54 -08002475 # TODO: Come up with a better way of handling these
kelvin-onlabd3b64892015-01-20 13:26:24 -08002476 if 65534 in mnPorts:
2477 mnPorts.remove( 65534 )
2478 if long( uint64( -2 ) ) in onosPorts:
2479 onosPorts.remove( long( uint64( -2 ) ) )
2480 if len( mnPorts ): # the ports of this switch don't match
2481 switchResult = main.FALSE
2482 main.log.warn( "Ports in MN but not ONOS: " + str( mnPorts ) )
2483 if len( onosPorts ): # the ports of this switch don't match
2484 switchResult = main.FALSE
Jon Hall7eb38402015-01-08 17:19:54 -08002485 main.log.warn(
2486 "Ports in ONOS but not MN: " +
kelvin-onlabd3b64892015-01-20 13:26:24 -08002487 str( onosPorts ) )
2488 if switchResult == main.FALSE:
Jon Hallafa8a472015-06-12 14:02:42 -07002489 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002490 "The list of ports for switch %s(%s) does not match:" %
Jon Hallafa8a472015-06-12 14:02:42 -07002491 ( name, mnSwitch[ 'dpid' ] ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002492 main.log.warn( "mn_ports[] = " + str( mnPortsLog ) )
2493 main.log.warn( "onos_ports[] = " + str( onosPortsLog ) )
2494 portsResults = portsResults and switchResult
Jon Hallafa8a472015-06-12 14:02:42 -07002495 finalResults = finalResults and portsResults
2496 return finalResults
Jon Hall72cf1dc2014-10-20 21:04:50 -04002497
Jon Hallafa8a472015-06-12 14:02:42 -07002498 def compareLinks( self, switches, links, linksJson ):
Jon Hall7eb38402015-01-08 17:19:54 -08002499 """
2500 Compare mn and onos links
kelvin-onlabd3b64892015-01-20 13:26:24 -08002501 linksJson: parsed json object from the onos links api
Jon Hall72cf1dc2014-10-20 21:04:50 -04002502
Jon Hallafa8a472015-06-12 14:02:42 -07002503 """
Jon Hall7eb38402015-01-08 17:19:54 -08002504 # FIXME: this does not look for extra links in ONOS, only checks that
Jon Hallefbd9792015-03-05 16:11:36 -08002505 # ONOS has what is in MN
kelvin-onlabd3b64892015-01-20 13:26:24 -08002506 onos = linksJson
Jon Hall72cf1dc2014-10-20 21:04:50 -04002507
Jon Halld80cc142015-07-06 13:36:05 -07002508 mnLinks = []
Jon Hallafa8a472015-06-12 14:02:42 -07002509 for l in links:
2510 try:
2511 node1 = switches[ l[ 'node1' ] ]
2512 node2 = switches[ l[ 'node2' ] ]
2513 enabled = True
2514 for port in node1[ 'ports' ]:
2515 if port[ 'of_port' ] == l[ 'port1' ]:
2516 enabled = enabled and port[ 'enabled' ]
2517 for port in node2[ 'ports' ]:
Jon Halld80cc142015-07-06 13:36:05 -07002518 if port[ 'of_port' ] == l[ 'port2' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002519 enabled = enabled and port[ 'enabled' ]
2520 if enabled:
2521 mnLinks.append( l )
2522 except KeyError:
2523 pass
kelvin-onlabd3b64892015-01-20 13:26:24 -08002524 if 2 * len( mnLinks ) == len( onos ):
2525 linkResults = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002526 else:
kelvin-onlabd3b64892015-01-20 13:26:24 -08002527 linkResults = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002528 main.log.error(
Jon Hall328ddca2015-01-28 15:57:15 -08002529 "Mininet has " + str( len( mnLinks ) ) +
2530 " bidirectional links and ONOS has " +
2531 str( len( onos ) ) + " unidirectional links" )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002532
Jon Hall7eb38402015-01-08 17:19:54 -08002533 # iterate through MN links and check if an ONOS link exists in
2534 # both directions
kelvin-onlabd3b64892015-01-20 13:26:24 -08002535 for link in mnLinks:
Jon Hall7eb38402015-01-08 17:19:54 -08002536 # TODO: Find a more efficient search method
Jon Hall72cf1dc2014-10-20 21:04:50 -04002537 node1 = None
2538 port1 = None
2539 node2 = None
2540 port2 = None
kelvin-onlabd3b64892015-01-20 13:26:24 -08002541 firstDir = main.FALSE
2542 secondDir = main.FALSE
Jon Hallafa8a472015-06-12 14:02:42 -07002543 for swName, switch in switches.iteritems():
2544 if swName == link[ 'node1' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002545 node1 = switch[ 'dpid' ]
2546 for port in switch[ 'ports' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002547 if str( port[ 'of_port' ] ) == str( link[ 'port1' ] ):
Jon Hall7eb38402015-01-08 17:19:54 -08002548 port1 = port[ 'of_port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002549 if node1 is not None and node2 is not None:
2550 break
Jon Hallafa8a472015-06-12 14:02:42 -07002551 if swName == link[ 'node2' ]:
Jon Hall7eb38402015-01-08 17:19:54 -08002552 node2 = switch[ 'dpid' ]
2553 for port in switch[ 'ports' ]:
Jon Hallafa8a472015-06-12 14:02:42 -07002554 if str( port[ 'of_port' ] ) == str( link[ 'port2' ] ):
Jon Hall7eb38402015-01-08 17:19:54 -08002555 port2 = port[ 'of_port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002556 if node1 is not None and node2 is not None:
2557 break
2558
kelvin-onlabd3b64892015-01-20 13:26:24 -08002559 for onosLink in onos:
2560 onosNode1 = onosLink[ 'src' ][ 'device' ].replace(
Jon Hallafa8a472015-06-12 14:02:42 -07002561 ":", '' ).replace( "of", '' )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002562 onosNode2 = onosLink[ 'dst' ][ 'device' ].replace(
Jon Hallafa8a472015-06-12 14:02:42 -07002563 ":", '' ).replace( "of", '' )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002564 onosPort1 = onosLink[ 'src' ][ 'port' ]
2565 onosPort2 = onosLink[ 'dst' ][ 'port' ]
Jon Hall72cf1dc2014-10-20 21:04:50 -04002566
Jon Hall72cf1dc2014-10-20 21:04:50 -04002567 # check onos link from node1 to node2
kelvin-onlabd3b64892015-01-20 13:26:24 -08002568 if str( onosNode1 ) == str( node1 ) and str(
2569 onosNode2 ) == str( node2 ):
2570 if int( onosPort1 ) == int( port1 ) and int(
2571 onosPort2 ) == int( port2 ):
2572 firstDir = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002573 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002574 main.log.warn(
2575 'The port numbers do not match for ' +
2576 str( link ) +
Jon Hallefbd9792015-03-05 16:11:36 -08002577 ' between ONOS and MN. When checking ONOS for ' +
Jon Hall7eb38402015-01-08 17:19:54 -08002578 'link %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002579 ( node1, port1, node2, port2 ) +
Jon Hall7eb38402015-01-08 17:19:54 -08002580 ' ONOS has the values %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002581 ( onosNode1, onosPort1, onosNode2, onosPort2 ) )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002582
2583 # check onos link from node2 to node1
kelvin-onlabd3b64892015-01-20 13:26:24 -08002584 elif ( str( onosNode1 ) == str( node2 ) and
2585 str( onosNode2 ) == str( node1 ) ):
2586 if ( int( onosPort1 ) == int( port2 )
2587 and int( onosPort2 ) == int( port1 ) ):
2588 secondDir = main.TRUE
Jon Hall72cf1dc2014-10-20 21:04:50 -04002589 else:
Jon Hall7eb38402015-01-08 17:19:54 -08002590 main.log.warn(
2591 'The port numbers do not match for ' +
2592 str( link ) +
Jon Hallefbd9792015-03-05 16:11:36 -08002593 ' between ONOS and MN. When checking ONOS for ' +
Jon Hall7eb38402015-01-08 17:19:54 -08002594 'link %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002595 ( node1, port1, node2, port2 ) +
Jon Hall7eb38402015-01-08 17:19:54 -08002596 ' ONOS has the values %s/%s -> %s/%s' %
Jon Hallafa8a472015-06-12 14:02:42 -07002597 ( onosNode2, onosPort2, onosNode1, onosPort1 ) )
Jon Hall7eb38402015-01-08 17:19:54 -08002598 else: # this is not the link you're looking for
Jon Hall72cf1dc2014-10-20 21:04:50 -04002599 pass
kelvin-onlabd3b64892015-01-20 13:26:24 -08002600 if not firstDir:
Jon Hallafa8a472015-06-12 14:02:42 -07002601 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002602 'ONOS does not have the link %s/%s -> %s/%s' %
2603 ( node1, port1, node2, port2 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002604 if not secondDir:
Jon Hallafa8a472015-06-12 14:02:42 -07002605 main.log.error(
Jon Hall7eb38402015-01-08 17:19:54 -08002606 'ONOS does not have the link %s/%s -> %s/%s' %
2607 ( node2, port2, node1, port1 ) )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002608 linkResults = linkResults and firstDir and secondDir
2609 return linkResults
Jon Hall72cf1dc2014-10-20 21:04:50 -04002610
Jon Hallafa8a472015-06-12 14:02:42 -07002611 def compareHosts( self, hosts, hostsJson ):
Jon Hallff6b4b22015-02-23 09:25:15 -08002612 """
Jon Hallafa8a472015-06-12 14:02:42 -07002613 Compare mn and onos Hosts.
2614 Since Mininet hosts are quiet, ONOS will only know of them when they
2615 speak. For this reason, we will only check that the hosts in ONOS
2616 stores are in Mininet, and not vice versa.
Jon Hallff6b4b22015-02-23 09:25:15 -08002617
Jon Hallafa8a472015-06-12 14:02:42 -07002618 Arguments:
2619 hostsJson: parsed json object from the onos hosts api
2620 Returns:
2621 """
Jon Hallff6b4b22015-02-23 09:25:15 -08002622 import json
2623 hostResults = main.TRUE
Jon Hallff6b4b22015-02-23 09:25:15 -08002624 for onosHost in hostsJson:
2625 onosMAC = onosHost[ 'mac' ].lower()
2626 match = False
Jon Halld80cc142015-07-06 13:36:05 -07002627 for mnHost, info in hosts.iteritems():
2628 for mnIntf in info[ 'interfaces' ]:
2629 if onosMAC == mnIntf[ 'mac' ].lower():
Jon Hallff6b4b22015-02-23 09:25:15 -08002630 match = True
2631 for ip in mnIntf[ 'ips' ]:
Jon Hallfeff3082015-05-19 10:23:26 -07002632 if ip in onosHost[ 'ipAddresses' ]:
Jon Hallff6b4b22015-02-23 09:25:15 -08002633 pass # all is well
2634 else:
2635 # misssing ip
Jon Halld80cc142015-07-06 13:36:05 -07002636 main.log.error( "ONOS host " +
2637 onosHost[ 'id' ] +
2638 " has a different IP(" +
Jon Hallafa8a472015-06-12 14:02:42 -07002639 str( onosHost[ 'ipAddresses' ] ) +
2640 ") than the Mininet host(" +
Jon Halld80cc142015-07-06 13:36:05 -07002641 str( ip ) +
2642 ")." )
Jon Hallff6b4b22015-02-23 09:25:15 -08002643 output = json.dumps(
Jon Halld80cc142015-07-06 13:36:05 -07002644 onosHost,
2645 sort_keys=True,
2646 indent=4,
2647 separators=( ',', ': ' ) )
Jon Hallff6b4b22015-02-23 09:25:15 -08002648 main.log.info( output )
2649 hostResults = main.FALSE
2650 if not match:
2651 hostResults = main.FALSE
2652 main.log.error( "ONOS host " + onosHost[ 'id' ] + " has no " +
2653 "corresponding Mininet host." )
2654 output = json.dumps( onosHost,
2655 sort_keys=True,
2656 indent=4,
2657 separators=( ',', ': ' ) )
2658 main.log.info( output )
Jon Hallff6b4b22015-02-23 09:25:15 -08002659 return hostResults
2660
Jon Hallafa8a472015-06-12 14:02:42 -07002661 def getHostsOld( self ):
Jon Hall7eb38402015-01-08 17:19:54 -08002662 """
2663 Returns a list of all hosts
2664 Don't ask questions just use it"""
2665 self.handle.sendline( "" )
2666 self.handle.expect( "mininet>" )
Jon Hall72cf1dc2014-10-20 21:04:50 -04002667
Jon Hall7eb38402015-01-08 17:19:54 -08002668 self.handle.sendline( "py [ host.name for host in net.hosts ]" )
2669 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002670
kelvin-onlabd3b64892015-01-20 13:26:24 -08002671 handlePy = self.handle.before
2672 handlePy = handlePy.split( "]\r\n", 1 )[ 1 ]
2673 handlePy = handlePy.rstrip()
admin2a9548d2014-06-17 14:08:07 -07002674
Jon Hall7eb38402015-01-08 17:19:54 -08002675 self.handle.sendline( "" )
2676 self.handle.expect( "mininet>" )
admin2a9548d2014-06-17 14:08:07 -07002677
kelvin-onlabd3b64892015-01-20 13:26:24 -08002678 hostStr = handlePy.replace( "]", "" )
2679 hostStr = hostStr.replace( "'", "" )
2680 hostStr = hostStr.replace( "[", "" )
kelvin-onlab2ccad6e2015-05-18 10:36:54 -07002681 hostStr = hostStr.replace( " ", "" )
kelvin-onlabd3b64892015-01-20 13:26:24 -08002682 hostList = hostStr.split( "," )
andrewonlab3f0a4af2014-10-17 12:25:14 -04002683
kelvin-onlabd3b64892015-01-20 13:26:24 -08002684 return hostList
adminbae64d82013-08-01 10:50:15 -07002685
kelvin-onlabfa6ada82015-06-11 13:06:24 -07002686 def getSwitch( self ):
2687 """
2688 Returns a list of all switches
2689 Again, don't ask question just use it...
2690 """
2691 # get host list...
2692 hostList = self.getHosts()
2693 # Make host set
2694 hostSet = set( hostList )
2695
2696 # Getting all the nodes in mininet
2697 self.handle.sendline( "" )
2698 self.handle.expect( "mininet>" )
2699
2700 self.handle.sendline( "py [ node.name for node in net.values() ]" )
2701 self.handle.expect( "mininet>" )
2702
2703 handlePy = self.handle.before
2704 handlePy = handlePy.split( "]\r\n", 1 )[ 1 ]
2705 handlePy = handlePy.rstrip()
2706
2707 self.handle.sendline( "" )
2708 self.handle.expect( "mininet>" )
2709
2710 nodesStr = handlePy.replace( "]", "" )
2711 nodesStr = nodesStr.replace( "'", "" )
2712 nodesStr = nodesStr.replace( "[", "" )
2713 nodesStr = nodesStr.replace( " ", "" )
2714 nodesList = nodesStr.split( "," )
2715
2716 nodesSet = set( nodesList )
2717 # discarding default controller(s) node
2718 nodesSet.discard( 'c0' )
2719 nodesSet.discard( 'c1' )
2720 nodesSet.discard( 'c2' )
2721
2722 switchSet = nodesSet - hostSet
2723 switchList = list( switchSet )
2724
2725 return switchList
2726
Jon Hall7eb38402015-01-08 17:19:54 -08002727 def update( self ):
2728 """
2729 updates the port address and status information for
2730 each port in mn"""
2731 # TODO: Add error checking. currently the mininet command has no output
Jon Hallefbd9792015-03-05 16:11:36 -08002732 main.log.info( "Updating MN port information" )
Jon Hallb1290e82014-11-18 16:17:48 -05002733 try:
Jon Hall7eb38402015-01-08 17:19:54 -08002734 self.handle.sendline( "" )
2735 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002736
Jon Hall7eb38402015-01-08 17:19:54 -08002737 self.handle.sendline( "update" )
2738 self.handle.expect( "update" )
2739 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002740
Jon Hall7eb38402015-01-08 17:19:54 -08002741 self.handle.sendline( "" )
2742 self.handle.expect( "mininet>" )
Jon Hall38481722014-11-04 16:50:05 -05002743
Jon Hallb1290e82014-11-18 16:17:48 -05002744 return main.TRUE
2745 except pexpect.EOF:
Jon Hall7eb38402015-01-08 17:19:54 -08002746 main.log.error( self.name + ": EOF exception found" )
2747 main.log.error( self.name + ": " + self.handle.before )
Jon Hallb1290e82014-11-18 16:17:48 -05002748 main.cleanup()
2749 main.exit()
2750
Jon Halld80cc142015-07-06 13:36:05 -07002751 def assignVLAN( self, host, intf, vlan ):
kaouthera3f13ca22015-05-05 15:01:41 -07002752 """
2753 Add vlan tag to a host.
2754 Dependencies:
2755 This class depends on the "vlan" package
2756 $ sudo apt-get install vlan
2757 Configuration:
2758 Load the 8021q module into the kernel
2759 $sudo modprobe 8021q
2760
2761 To make this setup permanent:
2762 $ sudo su -c 'echo "8021q" >> /etc/modules'
2763 """
2764 if self.handle:
2765 try:
Jon Halld80cc142015-07-06 13:36:05 -07002766 # get the ip address of the host
2767 main.log.info( "Get the ip address of the host" )
2768 ipaddr = self.getIPAddress( host )
2769 print repr( ipaddr )
kaouthera3f13ca22015-05-05 15:01:41 -07002770
Jon Halld80cc142015-07-06 13:36:05 -07002771 # remove IP from interface intf
2772 # Ex: h1 ifconfig h1-eth0 inet 0
2773 main.log.info( "Remove IP from interface " )
2774 cmd2 = host + " ifconfig " + intf + " " + " inet 0 "
2775 self.handle.sendline( cmd2 )
2776 self.handle.expect( "mininet>" )
2777 response = self.handle.before
2778 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002779
Jon Halld80cc142015-07-06 13:36:05 -07002780 # create VLAN interface
2781 # Ex: h1 vconfig add h1-eth0 100
2782 main.log.info( "Create Vlan" )
2783 cmd3 = host + " vconfig add " + intf + " " + vlan
2784 self.handle.sendline( cmd3 )
2785 self.handle.expect( "mininet>" )
2786 response = self.handle.before
2787 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002788
Jon Halld80cc142015-07-06 13:36:05 -07002789 # assign the host's IP to the VLAN interface
2790 # Ex: h1 ifconfig h1-eth0.100 inet 10.0.0.1
2791 main.log.info( "Assign the host IP to the vlan interface" )
2792 vintf = intf + "." + vlan
2793 cmd4 = host + " ifconfig " + vintf + " " + " inet " + ipaddr
2794 self.handle.sendline( cmd4 )
2795 self.handle.expect( "mininet>" )
2796 response = self.handle.before
2797 main.log.info( "====> %s ", response )
kaouthera3f13ca22015-05-05 15:01:41 -07002798
2799 return main.TRUE
2800 except pexpect.EOF:
2801 main.log.error( self.name + ": EOF exception found" )
2802 main.log.error( self.name + ": " + self.handle.before )
2803 return main.FALSE
2804
Jon Hall892818c2015-10-20 17:58:34 -07002805 def createHostComponent( self, name ):
2806 """
2807 Creates a new mininet cli component with the same parameters as self.
2808 This new component is intended to be used to login to the hosts created
2809 by mininet.
2810
2811 Arguments:
2812 name - The string of the name of this component. The new component
2813 will be assigned to main.<name> .
2814 In addition, main.<name>.name = str( name )
2815 """
2816 try:
2817 # look to see if this component already exists
2818 getattr( main, name )
2819 except AttributeError:
2820 # namespace is clear, creating component
2821 main.componentDictionary[name] = main.componentDictionary[self.name].copy()
2822 main.componentDictionary[name]['connect_order'] = str( int( main.componentDictionary[name]['connect_order'] ) + 1 )
2823 main.componentInit( name )
2824 except Exception:
2825 main.log.exception( self.name + ": Uncaught exception!" )
2826 main.cleanup()
2827 main.exit()
2828 else:
2829 # namespace is not clear!
2830 main.log.error( name + " component already exists!" )
2831 # FIXME: Should we exit here?
2832 main.cleanup()
2833 main.exit()
2834
2835 def removeHostComponent( self, name ):
2836 """
2837 Remove host component
2838 Arguments:
2839 name - The string of the name of the component to delete.
2840 """
2841 try:
2842 # Get host component
2843 component = getattr( main, name )
2844 except AttributeError:
2845 main.log.error( "Component " + name + " does not exist." )
2846 return
2847 try:
2848 # Disconnect from component
2849 component.disconnect()
2850 # Delete component
2851 delattr( main, name )
2852 # Delete component from ComponentDictionary
2853 del( main.componentDictionary[name] )
2854 except Exception:
2855 main.log.exception( self.name + ": Uncaught exception!" )
2856 main.cleanup()
2857 main.exit()
2858
2859 def startHostCli( self, host=None ):
2860 """
2861 Use the mininet m utility to connect to the host's cli
2862 """
2863 # These are fields that can be used by scapy packets. Initialized to None
2864 self.hostIp = None
2865 self.hostMac = None
2866 try:
2867 if not host:
2868 host = self.name
2869 self.handle.sendline( self.home + "/util/m " + host )
2870 self.handle.expect( self.hostPrompt )
2871 return main.TRUE
2872 except pexpect.TIMEOUT:
2873 main.log.exception( self.name + ": Command timed out" )
2874 return main.FALSE
2875 except pexpect.EOF:
2876 main.log.exception( self.name + ": connection closed." )
2877 main.cleanup()
2878 main.exit()
2879 except Exception:
2880 main.log.exception( self.name + ": Uncaught exception!" )
2881 main.cleanup()
2882 main.exit()
2883
GlennRC956ea742015-11-05 16:14:15 -08002884 def startScapy( self, mplsPath="" ):
Jon Hall892818c2015-10-20 17:58:34 -07002885 """
2886 Start the Scapy cli
GlennRC956ea742015-11-05 16:14:15 -08002887 optional:
2888 mplsPath - The path where the MPLS class is located
2889 NOTE: This can be a relative path from the user's home dir
Jon Hall892818c2015-10-20 17:58:34 -07002890 """
GlennRC956ea742015-11-05 16:14:15 -08002891 mplsLines = ['import imp',
2892 'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format(mplsPath),
2893 'from mplsClass import MPLS',
2894 'bind_layers(Ether, MPLS, type = 0x8847)',
2895 'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
2896 'bind_layers(MPLS, IP)']
2897
Jon Hall892818c2015-10-20 17:58:34 -07002898 try:
2899 self.handle.sendline( "scapy" )
2900 self.handle.expect( self.scapyPrompt )
2901 self.handle.sendline( "conf.color_theme = NoTheme()" )
2902 self.handle.expect( self.scapyPrompt )
GlennRC956ea742015-11-05 16:14:15 -08002903 if mplsPath:
2904 main.log.info( "Adding MPLS class" )
2905 main.log.info( "MPLS class path: " + mplsPath )
2906 for line in mplsLines:
2907 main.log.info( "sending line: " + line )
2908 self.handle.sendline( line )
2909 self.handle.expect( self.scapyPrompt )
Jon Hall892818c2015-10-20 17:58:34 -07002910 return main.TRUE
2911 except pexpect.TIMEOUT:
2912 main.log.exception( self.name + ": Command timed out" )
2913 return main.FALSE
2914 except pexpect.EOF:
2915 main.log.exception( self.name + ": connection closed." )
2916 main.cleanup()
2917 main.exit()
2918 except Exception:
2919 main.log.exception( self.name + ": Uncaught exception!" )
2920 main.cleanup()
2921 main.exit()
2922
2923 def stopScapy( self ):
2924 """
2925 Exit the Scapy cli
2926 """
2927 try:
2928 self.handle.sendline( "exit()" )
2929 self.handle.expect( self.hostPrompt )
2930 return main.TRUE
2931 except pexpect.TIMEOUT:
2932 main.log.exception( self.name + ": Command timed out" )
2933 return main.FALSE
2934 except pexpect.EOF:
2935 main.log.exception( self.name + ": connection closed." )
2936 main.cleanup()
2937 main.exit()
2938 except Exception:
2939 main.log.exception( self.name + ": Uncaught exception!" )
2940 main.cleanup()
2941 main.exit()
2942
2943 def buildEther( self, **kwargs ):
2944 """
2945 Build an Ethernet frame
2946
2947 Will create a frame class with the given options. If a field is
2948 left blank it will default to the below value unless it is
2949 overwritten by the next frame.
2950 Default frame:
2951 ###[ Ethernet ]###
2952 dst= ff:ff:ff:ff:ff:ff
2953 src= 00:00:00:00:00:00
2954 type= 0x800
2955
2956 Returns main.TRUE or main.FALSE on error
2957 """
2958 try:
2959 # Set the Ethernet frame
2960 cmd = 'ether = Ether( '
2961 options = []
2962 for key, value in kwargs.iteritems():
2963 if isinstance( value, str ):
2964 value = '"' + value + '"'
2965 options.append( str( key ) + "=" + str( value ) )
2966 cmd += ", ".join( options )
2967 cmd += ' )'
2968 self.handle.sendline( cmd )
2969 self.handle.expect( self.scapyPrompt )
2970 if "Traceback" in self.handle.before:
2971 # KeyError, SyntaxError, ...
2972 main.log.error( "Error in sending command: " + self.handle.before )
2973 return main.FALSE
2974 self.handle.sendline( "packet = ether" )
2975 self.handle.expect( self.scapyPrompt )
2976 if "Traceback" in self.handle.before:
2977 # KeyError, SyntaxError, ...
2978 main.log.error( "Error in sending command: " + self.handle.before )
2979 return main.FALSE
2980 return main.TRUE
2981 except pexpect.TIMEOUT:
2982 main.log.exception( self.name + ": Command timed out" )
2983 return main.FALSE
2984 except pexpect.EOF:
2985 main.log.exception( self.name + ": connection closed." )
2986 main.cleanup()
2987 main.exit()
2988 except Exception:
2989 main.log.exception( self.name + ": Uncaught exception!" )
2990 main.cleanup()
2991 main.exit()
2992
2993 def buildIP( self, **kwargs ):
2994 """
2995 Build an IP frame
2996
2997 Will create a frame class with the given options. If a field is
2998 left blank it will default to the below value unless it is
2999 overwritten by the next frame.
3000 Default frame:
3001 ###[ IP ]###
3002 version= 4
3003 ihl= None
3004 tos= 0x0
3005 len= None
3006 id= 1
3007 flags=
3008 frag= 0
3009 ttl= 64
3010 proto= hopopt
3011 chksum= None
3012 src= 127.0.0.1
3013 dst= 127.0.0.1
3014 \options\
3015
3016 Returns main.TRUE or main.FALSE on error
3017 """
3018 try:
3019 # Set the IP frame
3020 cmd = 'ip = IP( '
3021 options = []
3022 for key, value in kwargs.iteritems():
3023 if isinstance( value, str ):
3024 value = '"' + value + '"'
3025 options.append( str( key ) + "=" + str( value ) )
3026 cmd += ", ".join( options )
3027 cmd += ' )'
3028 self.handle.sendline( cmd )
3029 self.handle.expect( self.scapyPrompt )
3030 if "Traceback" in self.handle.before:
3031 # KeyError, SyntaxError, ...
3032 main.log.error( "Error in sending command: " + self.handle.before )
3033 return main.FALSE
3034 self.handle.sendline( "packet = ether/ip" )
3035 self.handle.expect( self.scapyPrompt )
3036 if "Traceback" in self.handle.before:
3037 # KeyError, SyntaxError, ...
3038 main.log.error( "Error in sending command: " + self.handle.before )
3039 return main.FALSE
3040 return main.TRUE
3041 except pexpect.TIMEOUT:
3042 main.log.exception( self.name + ": Command timed out" )
3043 return main.FALSE
3044 except pexpect.EOF:
3045 main.log.exception( self.name + ": connection closed." )
3046 main.cleanup()
3047 main.exit()
3048 except Exception:
3049 main.log.exception( self.name + ": Uncaught exception!" )
3050 main.cleanup()
3051 main.exit()
3052
3053 def buildIPv6( self, **kwargs ):
3054 """
3055 Build an IPv6 frame
3056
3057 Will create a frame class with the given options. If a field is
3058 left blank it will default to the below value unless it is
3059 overwritten by the next frame.
3060 Default frame:
3061 ###[ IPv6 ]###
3062 version= 6
3063 tc= 0
3064 fl= 0
3065 plen= None
3066 nh= No Next Header
3067 hlim= 64
3068 src= ::1
3069 dst= ::1
3070
3071 Returns main.TRUE or main.FALSE on error
3072 """
3073 try:
3074 # Set the IPv6 frame
3075 cmd = 'ipv6 = IPv6( '
3076 options = []
3077 for key, value in kwargs.iteritems():
3078 if isinstance( value, str ):
3079 value = '"' + value + '"'
3080 options.append( str( key ) + "=" + str( value ) )
3081 cmd += ", ".join( options )
3082 cmd += ' )'
3083 self.handle.sendline( cmd )
3084 self.handle.expect( self.scapyPrompt )
3085 if "Traceback" in self.handle.before:
3086 # KeyError, SyntaxError, ...
3087 main.log.error( "Error in sending command: " + self.handle.before )
3088 return main.FALSE
3089 self.handle.sendline( "packet = ether/ipv6" )
3090 self.handle.expect( self.scapyPrompt )
3091 if "Traceback" in self.handle.before:
3092 # KeyError, SyntaxError, ...
3093 main.log.error( "Error in sending command: " + self.handle.before )
3094 return main.FALSE
3095 return main.TRUE
3096 except pexpect.TIMEOUT:
3097 main.log.exception( self.name + ": Command timed out" )
3098 return main.FALSE
3099 except pexpect.EOF:
3100 main.log.exception( self.name + ": connection closed." )
3101 main.cleanup()
3102 main.exit()
3103 except Exception:
3104 main.log.exception( self.name + ": Uncaught exception!" )
3105 main.cleanup()
3106 main.exit()
3107
3108 def buildTCP( self, ipVersion=4, **kwargs ):
3109 """
3110 Build an TCP frame
3111
3112 Will create a frame class with the given options. If a field is
3113 left blank it will default to the below value unless it is
3114 overwritten by the next frame.
3115
GlennRC956ea742015-11-05 16:14:15 -08003116 NOTE: Some arguments require quotes around them. It's up to you to
3117 know which ones and to add them yourself. Arguments with an asterisk
3118 do not need quotes.
3119
Jon Hall892818c2015-10-20 17:58:34 -07003120 Options:
3121 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
3122 frame to use to encapsulate into
3123 Default frame:
3124 ###[ TCP ]###
GlennRC956ea742015-11-05 16:14:15 -08003125 sport= ftp_data *
3126 dport= http *
Jon Hall892818c2015-10-20 17:58:34 -07003127 seq= 0
3128 ack= 0
3129 dataofs= None
3130 reserved= 0
3131 flags= S
3132 window= 8192
3133 chksum= None
3134 urgptr= 0
3135 options= {}
3136
3137 Returns main.TRUE or main.FALSE on error
3138 """
3139 try:
3140 # Set the TCP frame
3141 cmd = 'tcp = TCP( '
3142 options = []
3143 for key, value in kwargs.iteritems():
Jon Hall892818c2015-10-20 17:58:34 -07003144 options.append( str( key ) + "=" + str( value ) )
3145 cmd += ", ".join( options )
3146 cmd += ' )'
3147 self.handle.sendline( cmd )
3148 self.handle.expect( self.scapyPrompt )
3149 if "Traceback" in self.handle.before:
3150 # KeyError, SyntaxError, ...
3151 main.log.error( "Error in sending command: " + self.handle.before )
3152 return main.FALSE
3153 if str( ipVersion ) is '4':
3154 self.handle.sendline( "packet = ether/ip/tcp" )
3155 elif str( ipVersion ) is '6':
3156 self.handle.sendline( "packet = ether/ipv6/tcp" )
3157 else:
3158 main.log.error( "Unrecognized option for ipVersion, given " +
3159 repr( ipVersion ) )
3160 return main.FALSE
3161 self.handle.expect( self.scapyPrompt )
3162 if "Traceback" in self.handle.before:
3163 # KeyError, SyntaxError, ...
3164 main.log.error( "Error in sending command: " + self.handle.before )
3165 return main.FALSE
3166 return main.TRUE
3167 except pexpect.TIMEOUT:
3168 main.log.exception( self.name + ": Command timed out" )
3169 return main.FALSE
3170 except pexpect.EOF:
3171 main.log.exception( self.name + ": connection closed." )
3172 main.cleanup()
3173 main.exit()
3174 except Exception:
3175 main.log.exception( self.name + ": Uncaught exception!" )
3176 main.cleanup()
3177 main.exit()
3178
3179 def buildUDP( self, ipVersion=4, **kwargs ):
3180 """
3181 Build an UDP frame
3182
3183 Will create a frame class with the given options. If a field is
3184 left blank it will default to the below value unless it is
3185 overwritten by the next frame.
3186
GlennRC956ea742015-11-05 16:14:15 -08003187 NOTE: Some arguments require quotes around them. It's up to you to
3188 know which ones and to add them yourself. Arguments with an asterisk
3189 do not need quotes.
3190
Jon Hall892818c2015-10-20 17:58:34 -07003191 Options:
3192 ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
3193 frame to use to encapsulate into
3194 Default frame:
3195 ###[ UDP ]###
GlennRC956ea742015-11-05 16:14:15 -08003196 sport= domain *
3197 dport= domain *
Jon Hall892818c2015-10-20 17:58:34 -07003198 len= None
3199 chksum= None
3200
3201 Returns main.TRUE or main.FALSE on error
3202 """
3203 try:
3204 # Set the UDP frame
3205 cmd = 'udp = UDP( '
3206 options = []
3207 for key, value in kwargs.iteritems():
Jon Hall892818c2015-10-20 17:58:34 -07003208 options.append( str( key ) + "=" + str( value ) )
3209 cmd += ", ".join( options )
3210 cmd += ' )'
3211 self.handle.sendline( cmd )
3212 self.handle.expect( self.scapyPrompt )
3213 if "Traceback" in self.handle.before:
3214 # KeyError, SyntaxError, ...
3215 main.log.error( "Error in sending command: " + self.handle.before )
3216 return main.FALSE
3217 if str( ipVersion ) is '4':
3218 self.handle.sendline( "packet = ether/ip/udp" )
3219 elif str( ipVersion ) is '6':
3220 self.handle.sendline( "packet = ether/ipv6/udp" )
3221 else:
3222 main.log.error( "Unrecognized option for ipVersion, given " +
3223 repr( ipVersion ) )
3224 return main.FALSE
3225 self.handle.expect( self.scapyPrompt )
3226 if "Traceback" in self.handle.before:
3227 # KeyError, SyntaxError, ...
3228 main.log.error( "Error in sending command: " + self.handle.before )
3229 return main.FALSE
3230 return main.TRUE
3231 except pexpect.TIMEOUT:
3232 main.log.exception( self.name + ": Command timed out" )
3233 return main.FALSE
3234 except pexpect.EOF:
3235 main.log.exception( self.name + ": connection closed." )
3236 main.cleanup()
3237 main.exit()
3238 except Exception:
3239 main.log.exception( self.name + ": Uncaught exception!" )
3240 main.cleanup()
3241 main.exit()
3242
3243 def buildICMP( self, **kwargs ):
3244 """
3245 Build an ICMP frame
3246
3247 Will create a frame class with the given options. If a field is
3248 left blank it will default to the below value unless it is
3249 overwritten by the next frame.
3250 Default frame:
3251 ###[ ICMP ]###
3252 type= echo-request
3253 code= 0
3254 chksum= None
3255 id= 0x0
3256 seq= 0x0
3257
3258 Returns main.TRUE or main.FALSE on error
3259 """
3260 try:
3261 # Set the ICMP frame
3262 cmd = 'icmp = ICMP( '
3263 options = []
3264 for key, value in kwargs.iteritems():
3265 if isinstance( value, str ):
3266 value = '"' + value + '"'
3267 options.append( str( key ) + "=" + str( value ) )
3268 cmd += ", ".join( options )
3269 cmd += ' )'
3270 self.handle.sendline( cmd )
3271 self.handle.expect( self.scapyPrompt )
3272 if "Traceback" in self.handle.before:
3273 # KeyError, SyntaxError, ...
3274 main.log.error( "Error in sending command: " + self.handle.before )
3275 return main.FALSE
3276 self.handle.sendline( "packet = ether/ip/icmp" )
3277 self.handle.expect( self.scapyPrompt )
3278 if "Traceback" in self.handle.before:
3279 # KeyError, SyntaxError, ...
3280 main.log.error( "Error in sending command: " + self.handle.before )
3281 return main.FALSE
3282 return main.TRUE
3283 except pexpect.TIMEOUT:
3284 main.log.exception( self.name + ": Command timed out" )
3285 return main.FALSE
3286 except pexpect.EOF:
3287 main.log.exception( self.name + ": connection closed." )
3288 main.cleanup()
3289 main.exit()
3290 except Exception:
3291 main.log.exception( self.name + ": Uncaught exception!" )
3292 main.cleanup()
3293 main.exit()
3294
GlennRC073e8bc2015-10-27 17:11:28 -07003295 def sendPacket( self, iface=None, packet=None, timeout=1 ):
Jon Hall892818c2015-10-20 17:58:34 -07003296 """
3297 Send a packet with either the given scapy packet command, or use the
3298 packet saved in the variable 'packet'.
3299
3300 Examples of a valid string for packet:
3301
3302 Simple IP packet
3303 packet='Ether(dst="a6:d9:26:df:1d:4b")/IP(dst="10.0.0.2")'
3304
3305 A Ping with two vlan tags
3306 packet='Ether(dst='ff:ff:ff:ff:ff:ff')/Dot1Q(vlan=1)/Dot1Q(vlan=10)/
3307 IP(dst='255.255.255.255', src='192.168.0.1')/ICMP()'
3308
3309 Returns main.TRUE or main.FALSE on error
3310 """
3311 try:
3312 # TODO: add all params, or use kwargs
3313 sendCmd = 'srp( '
3314 if packet:
3315 sendCmd += packet
3316 else:
3317 sendCmd += "packet"
GlennRC073e8bc2015-10-27 17:11:28 -07003318 if iface:
3319 sendCmd += ", iface='{}'".format( iface )
3320
Jon Hall892818c2015-10-20 17:58:34 -07003321 sendCmd += ', timeout=' + str( timeout ) + ')'
3322 self.handle.sendline( sendCmd )
3323 self.handle.expect( self.scapyPrompt )
3324 if "Traceback" in self.handle.before:
3325 # KeyError, SyntaxError, ...
3326 main.log.error( "Error in sending command: " + self.handle.before )
3327 return main.FALSE
3328 # TODO: Check # of packets sent?
3329 return main.TRUE
3330 except pexpect.TIMEOUT:
3331 main.log.exception( self.name + ": Command timed out" )
3332 return main.FALSE
3333 except pexpect.EOF:
3334 main.log.exception( self.name + ": connection closed." )
3335 main.cleanup()
3336 main.exit()
3337 except Exception:
3338 main.log.exception( self.name + ": Uncaught exception!" )
3339 main.cleanup()
3340 main.exit()
3341
3342 def startFilter( self, ifaceName=None, sniffCount=1, pktFilter="ip" ):
3343 """
3344 Listen for packets using the given filters
3345
3346 Options:
3347 ifaceName - the name of the interface to listen on. If none is given,
3348 defaults to <host name>-eth0
3349 pktFilter - A string in Berkeley Packet Filter (BPF) format which
3350 specifies which packets to sniff
3351 sniffCount - The number of matching packets to capture before returning
3352
3353 Returns main.TRUE or main.FALSE on error
3354 """
3355 try:
3356 # TODO: add all params, or use kwargs
3357 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
3358 # Set interface
3359 self.handle.sendline( ' conf.iface = "' + ifaceName + '"' )
3360 self.handle.expect( self.scapyPrompt )
3361 cmd = 'pkt = sniff(count = ' + str( sniffCount ) +\
3362 ', filter = "' + str( pktFilter ) + '")'
3363 self.handle.sendline( cmd )
3364 self.handle.expect( '"\)\r\n' )
3365 # TODO: parse this?
3366 return main.TRUE
3367 except pexpect.TIMEOUT:
3368 main.log.exception( self.name + ": Command timed out" )
3369 return main.FALSE
3370 except pexpect.EOF:
3371 main.log.exception( self.name + ": connection closed." )
3372 main.cleanup()
3373 main.exit()
3374 except Exception:
3375 main.log.exception( self.name + ": Uncaught exception!" )
3376 main.cleanup()
3377 main.exit()
3378
3379 def checkFilter( self ):
3380 """
3381 Check that a filter returned and returns the reponse
3382 """
3383 try:
3384 i = self.handle.expect( [ self.scapyPrompt, pexpect.TIMEOUT ] )
3385 if i == 0:
3386 return main.TRUE
3387 else:
3388 return main.FALSE
3389 except pexpect.EOF:
3390 main.log.exception( self.name + ": connection closed." )
3391 main.cleanup()
3392 main.exit()
3393 except Exception:
3394 main.log.exception( self.name + ": Uncaught exception!" )
3395 main.cleanup()
3396 main.exit()
3397
3398 def killFilter( self ):
3399 """
3400 Kill a scapy filter
3401 """
3402 try:
3403 self.handle.send( "\x03" ) # Send a ctrl-c to kill the filter
3404 self.handle.expect( self.scapyPrompt )
3405 return self.handle.before
3406 except pexpect.TIMEOUT:
3407 main.log.exception( self.name + ": Command timed out" )
3408 return None
3409 except pexpect.EOF:
3410 main.log.exception( self.name + ": connection closed." )
3411 main.cleanup()
3412 main.exit()
3413 except Exception:
3414 main.log.exception( self.name + ": Uncaught exception!" )
3415 main.cleanup()
3416 main.exit()
3417
3418 def readPackets( self ):
3419 """
3420 Read all the packets captured by the previous filter
3421 """
3422 try:
3423 self.handle.sendline( "for p in pkt: p \n")
3424 self.handle.expect( "for p in pkt: p \r\n... \r\n" )
3425 self.handle.expect( self.scapyPrompt )
3426 except pexpect.TIMEOUT:
3427 main.log.exception( self.name + ": Command timed out" )
3428 return None
3429 except pexpect.EOF:
3430 main.log.exception( self.name + ": connection closed." )
3431 main.cleanup()
3432 main.exit()
3433 except Exception:
3434 main.log.exception( self.name + ": Uncaught exception!" )
3435 main.cleanup()
3436 main.exit()
3437 return self.handle.before
3438
3439 def updateSelf( self ):
3440 """
3441 Updates local MAC and IP fields
3442 """
3443 self.hostMac = self.getMac()
3444 self.hostIp = self.getIp()
3445
3446 def getMac( self, ifaceName=None ):
3447 """
3448 Save host's MAC address
3449 """
3450 try:
3451 ifaceName = str( ifaceName ) if ifaceName else self.name + "-eth0"
3452 cmd = 'get_if_hwaddr("' + str( ifaceName ) + '")'
3453 self.handle.sendline( cmd )
3454 self.handle.expect( self.scapyPrompt )
3455 pattern = r'(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))'
3456 match = re.search( pattern, self.handle.before )
3457 if match:
3458 return match.group()
3459 else:
3460 # the command will have an exception if iface doesn't exist
3461 return None
3462 except pexpect.TIMEOUT:
3463 main.log.exception( self.name + ": Command timed out" )
3464 return None
3465 except pexpect.EOF:
3466 main.log.exception( self.name + ": connection closed." )
3467 main.cleanup()
3468 main.exit()
3469 except Exception:
3470 main.log.exception( self.name + ": Uncaught exception!" )
3471 main.cleanup()
3472 main.exit()
3473
3474 def getIp( self, ifaceName=None ):
3475 """
3476 Save host's IP address
3477 """
3478 try:
3479 ifaceName = ifaceName if ifaceName else self.name + "-eth0"
3480 cmd = 'get_if_addr("' + str( ifaceName ) + '")'
3481 self.handle.sendline( cmd )
3482 self.handle.expect( self.scapyPrompt )
3483
3484 pattern = r'(((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9]))'
3485 match = re.search( pattern, self.handle.before )
3486 if match:
3487 # NOTE: The command will return 0.0.0.0 if the iface doesn't exist
3488 return match.group()
3489 else:
3490 return None
3491 except pexpect.TIMEOUT:
3492 main.log.exception( self.name + ": Command timed out" )
3493 return None
3494 except pexpect.EOF:
3495 main.log.exception( self.name + ": connection closed." )
3496 main.cleanup()
3497 main.exit()
3498 except Exception:
3499 main.log.exception( self.name + ": Uncaught exception!" )
3500 main.cleanup()
3501 main.exit()
3502
adminbae64d82013-08-01 10:50:15 -07003503if __name__ != "__main__":
kelvin-onlab50907142015-04-01 13:37:45 -07003504 sys.modules[ __name__ ] = MininetCliDriver()