blob: a8aedeaa66e0db07f8d407e9ff3c4135e2c2daec [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
kelvin-onlabedcff052015-01-16 12:53:55 -08002"""
adminbae64d82013-08-01 10:50:15 -07003Created on 26-Oct-2012
4
kelvin-onlabedcff052015-01-16 12:53:55 -08005author:: Anil Kumar ( anilkumar.s@paxterrasolutions.com )
adminbae64d82013-08-01 10:50:15 -07006
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
kelvin-onlabedcff052015-01-16 12:53:55 -080011 ( at your option ) any later version.
adminbae64d82013-08-01 10:50:15 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
Jon Hallfbc828e2015-01-06 17:30:19 -080019 along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070020
21
22MininetCliDriver is the basic driver which will handle the Mininet functions
kelvin-onlabedcff052015-01-16 12:53:55 -080023"""
admin2a9548d2014-06-17 14:08:07 -070024import traceback
adminbae64d82013-08-01 10:50:15 -070025import pexpect
adminbae64d82013-08-01 10:50:15 -070026import re
27import sys
kelvin-onlabedcff052015-01-16 12:53:55 -080028sys.path.append( "../" )
adminbae64d82013-08-01 10:50:15 -070029from drivers.common.cli.emulatordriver import Emulator
adminbae64d82013-08-01 10:50:15 -070030
kelvin-onlabedcff052015-01-16 12:53:55 -080031
32class RemoteMininetDriver( Emulator ):
33
34 """
adminaeedddd2013-08-02 15:14:15 -070035 RemoteMininetCliDriver is the basic driver which will handle the Mininet functions
Jon Hallfbc828e2015-01-06 17:30:19 -080036 The main different between this and the MininetCliDriver is that this one does not build the mininet.
37 It assumes that there is already a mininet running on the target.
kelvin-onlabedcff052015-01-16 12:53:55 -080038 """
39 def __init__( self ):
40 super( Emulator, self ).__init__()
adminbae64d82013-08-01 10:50:15 -070041 self.handle = self
kelvin-onlabedcff052015-01-16 12:53:55 -080042 self.wrapped = sys.modules[ __name__ ]
adminbae64d82013-08-01 10:50:15 -070043 self.flag = 0
44
kelvin-onlabedcff052015-01-16 12:53:55 -080045 def connect( self, **connectargs ):
46 #,user_name, ip_address, pwd,options ):
47 # Here the main is the TestON instance after creating all the log
48 # handles.
adminbae64d82013-08-01 10:50:15 -070049 for key in connectargs:
kelvin-onlabedcff052015-01-16 12:53:55 -080050 vars( self )[ key ] = connectargs[ key ]
Jon Hallfbc828e2015-01-06 17:30:19 -080051
kelvin-onlabedcff052015-01-16 12:53:55 -080052 self.name = self.options[ 'name' ]
53 self.handle = super(
54 RemoteMininetDriver,
55 self ).connect(
56 user_name=self.user_name,
57 ip_address=self.ip_address,
58 port=None,
59 pwd=self.pwd )
Jon Hallfbc828e2015-01-06 17:30:19 -080060
adminbae64d82013-08-01 10:50:15 -070061 self.ssh_handle = self.handle
Jon Hallfbc828e2015-01-06 17:30:19 -080062
63 # Copying the readme file to process the
kelvin-onlabedcff052015-01-16 12:53:55 -080064 if self.handle:
adminbae64d82013-08-01 10:50:15 -070065 return main.TRUE
66
kelvin-onlabedcff052015-01-16 12:53:55 -080067 else:
68 main.log.error(
69 "Connection failed to the host " +
70 self.user_name +
71 "@" +
72 self.ip_address )
73 main.log.error( "Failed to connect to the Mininet" )
adminbae64d82013-08-01 10:50:15 -070074 return main.FALSE
admin98ad0092014-07-23 16:51:07 -070075
kelvin-onlabedcff052015-01-16 12:53:55 -080076#*************************************************************************
77#*************************************************************************
Jon Hallfbc828e2015-01-06 17:30:19 -080078# checkForLoss will determine if any of the pings had any packets lost during the course of
admin98ad0092014-07-23 16:51:07 -070079# the pingLong.
kelvin-onlabedcff052015-01-16 12:53:55 -080080#*************************************************************************
81#*************************************************************************
admin98ad0092014-07-23 16:51:07 -070082
kelvin-onlabedcff052015-01-16 12:53:55 -080083 def checkForLoss( self, pingList ):
84 """
Jon Hall6c794f32014-08-14 13:33:13 -070085 Returns main.FALSE for 0% packet loss and
86 Returns main.ERROR if "found multiple mininet" is found and
87 Returns main.TRUE else
kelvin-onlabedcff052015-01-16 12:53:55 -080088 """
89 # TODO: maybe we want to return the % loss instead? This way we can set an acceptible loss %.
90 # EX: 393 packets transmitted, 380 received, 3% packet loss, time 78519ms
Jon Hall368769f2014-11-19 15:43:35 -080091 # we may need to return a float to get around rounding errors
92
kelvin-onlabedcff052015-01-16 12:53:55 -080093 self.handle.sendline( "" )
94 self.handle.expect( "\$" )
95 # Clear any output waiting in the bg from killing pings
96 self.handle.sendline( "" )
97 self.handle.expect( "\$" )
98 self.handle.sendline( "cat " + pingList )
99 self.handle.expect( pingList )
100 self.handle.expect( "\$" )
admin2580a0e2014-07-29 11:24:34 -0700101 outputs = self.handle.before + self.handle.after
kelvin-onlabedcff052015-01-16 12:53:55 -0800102 if re.search( " 0% packet loss", outputs ):
admin98ad0092014-07-23 16:51:07 -0700103 return main.FALSE
kelvin-onlabedcff052015-01-16 12:53:55 -0800104 elif re.search( "found multiple mininet", outputs ):
admin2580a0e2014-07-29 11:24:34 -0700105 return main.ERROR
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700106 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800107 main.log.error( "Error, unexpected output in the ping file" )
Jon Hall2ef1e9e2014-11-18 14:27:05 -0500108 main.log.warn( outputs )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700109 return main.TRUE
110
kelvin-onlabedcff052015-01-16 12:53:55 -0800111 def pingLong( self, **pingParams ):
112 """
Jon Hallfbc828e2015-01-06 17:30:19 -0800113 Starts a continuous ping on the mininet host outputing to a file in the /tmp dir.
kelvin-onlabedcff052015-01-16 12:53:55 -0800114 """
115 self.handle.sendline( "" )
116 self.handle.expect( "\$" )
117 args = utilities.parse_args(
118 [ "SRC", "TARGET", "PINGTIME" ], **pingParams )
119 precmd = "sudo rm /tmp/ping." + args[ "SRC" ]
120 self.execute( cmd=precmd, prompt="(.*)", timeout=10 )
121 command = "sudo mininet/util/m " + args[ "SRC" ] + " ping " + args[
122 "TARGET" ] + " -i .2 -w " + str( args[ 'PINGTIME' ] ) + " -D > /tmp/ping." + args[ "SRC" ] + " &"
Jon Hallfbc828e2015-01-06 17:30:19 -0800123 main.log.info( command )
kelvin-onlabedcff052015-01-16 12:53:55 -0800124 self.execute( cmd=command, prompt="(.*)", timeout=10 )
125 self.handle.sendline( "" )
126 self.handle.expect( "\$" )
adminbae64d82013-08-01 10:50:15 -0700127 return main.TRUE
128
kelvin-onlabedcff052015-01-16 12:53:55 -0800129 def pingstatus( self, **pingParams ):
130 """
adminaeedddd2013-08-02 15:14:15 -0700131 Tails the respective ping output file and check that there is a moving "64 bytes"
kelvin-onlabedcff052015-01-16 12:53:55 -0800132 """
133 self.handle.sendline( "" )
134 self.handle.expect( "\$" )
135 args = utilities.parse_args( [ "SRC" ], **pingParams )
136 self.handle.sendline( "tail /tmp/ping." + args[ "SRC" ] )
137 self.handle.expect( "tail" )
138 self.handle.expect( "\$" )
adminbae64d82013-08-01 10:50:15 -0700139 result = self.handle.before + self.handle.after
kelvin-onlabedcff052015-01-16 12:53:55 -0800140 self.handle.sendline( "" )
141 self.handle.expect( "\$" )
142 if re.search( 'Unreachable', result ):
143 main.log.info( "Unreachable found in ping logs..." )
adminbae64d82013-08-01 10:50:15 -0700144 return main.FALSE
kelvin-onlabedcff052015-01-16 12:53:55 -0800145 elif re.search( '64\sbytes', result ):
146 main.log.info( "Pings look good" )
adminbae64d82013-08-01 10:50:15 -0700147 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -0800148 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800149 main.log.info( "No, or faulty ping data..." )
adminbae64d82013-08-01 10:50:15 -0700150 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800151
kelvin-onlabedcff052015-01-16 12:53:55 -0800152 def pingKill( self, testONUser, testONIP ):
153 """
adminaeedddd2013-08-02 15:14:15 -0700154 Kills all continuous ping processes.
155 Then copies all the ping files to the TestStation.
kelvin-onlabedcff052015-01-16 12:53:55 -0800156 """
157 self.handle.sendline( "" )
158 self.handle.expect( "\$" )
Jon Hallfbc828e2015-01-06 17:30:19 -0800159 command = "sudo kill -SIGINT `pgrep ping`"
160 main.log.info( command )
kelvin-onlabedcff052015-01-16 12:53:55 -0800161 self.execute( cmd=command, prompt="(.*)", timeout=10 )
Jon Hallfbc828e2015-01-06 17:30:19 -0800162
adminbae64d82013-08-01 10:50:15 -0700163 main.log.info( "Transferring ping files to TestStation" )
kelvin-onlabedcff052015-01-16 12:53:55 -0800164 command = "scp /tmp/ping.* " + \
165 str( testONUser ) + "@" + str( testONIP ) + ":/tmp/"
166 self.execute( cmd=command, prompt="100%", timeout=20 )
167 # Make sure the output is cleared
168 self.handle.sendline( "" )
169 self.handle.expect( "\$" )
170 self.handle.sendline( "" )
171 self.handle.expect( "\$" )
172 self.handle.sendline( "" )
173 i = self.handle.expect( [ "password", "\$" ] )
Jon Hall368769f2014-11-19 15:43:35 -0800174 if i == 0:
kelvin-onlabedcff052015-01-16 12:53:55 -0800175 main.log.error( "Error, sudo asking for password" )
176 main.log.error( self.handle.before )
Jon Hall368769f2014-11-19 15:43:35 -0800177 return main.FALSE
178 else:
179 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -0800180
kelvin-onlabedcff052015-01-16 12:53:55 -0800181 def pingLongKill( self ):
182 self.handle.sendline( "" )
183 self.handle.expect( "\$" )
admin2580a0e2014-07-29 11:24:34 -0700184 command = "sudo kill -SIGING `pgrep ping`"
kelvin-onlabedcff052015-01-16 12:53:55 -0800185 main.log.info( command )
186 self.execute( cmd=command, prompt="(.*)", timeout=10 )
187 self.handle.sendline( "" )
188 self.handle.expect( "\$" )
adminbae64d82013-08-01 10:50:15 -0700189 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -0800190
kelvin-onlabedcff052015-01-16 12:53:55 -0800191 def pingHostOptical( self, **pingParams ):
192 """
shahshreya28bb18e2014-11-17 10:26:23 -0800193 This function is only for Packey Optical related ping
kelvin-onlabedcff052015-01-16 12:53:55 -0800194 Use the next pingHost() function for all normal scenarios )
shahshreya28bb18e2014-11-17 10:26:23 -0800195 Ping from one mininet host to another
196 Currently the only supported Params: SRC and TARGET
kelvin-onlabedcff052015-01-16 12:53:55 -0800197 """
198 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
199 #command = args[ "SRC" ] + " ping -" + args[ "CONTROLLER" ] + " " +args [ "TARGET" ]
200 command = args[ "SRC" ] + " ping " + \
201 args[ "TARGET" ] + " -c 1 -i 1 -W 8"
shahshreya28bb18e2014-11-17 10:26:23 -0800202 try:
kelvin-onlabedcff052015-01-16 12:53:55 -0800203 main.log.warn( "Sending: " + command )
204 #response = self.execute( cmd=command,prompt="mininet",timeout=10 )
205 self.handle.sendline( command )
206 i = self.handle.expect( [ command, pexpect.TIMEOUT ] )
shahshreya28bb18e2014-11-17 10:26:23 -0800207 if i == 1:
kelvin-onlabedcff052015-01-16 12:53:55 -0800208 main.log.error(
209 self.name +
210 ": timeout when waiting for response from mininet" )
211 main.log.error( "response: " + str( self.handle.before ) )
212 i = self.handle.expect( [ "mininet>", pexpect.TIMEOUT ] )
shahshreya28bb18e2014-11-17 10:26:23 -0800213 if i == 1:
kelvin-onlabedcff052015-01-16 12:53:55 -0800214 main.log.error(
215 self.name +
216 ": timeout when waiting for response from mininet" )
217 main.log.error( "response: " + str( self.handle.before ) )
shahshreya28bb18e2014-11-17 10:26:23 -0800218 response = self.handle.before
219 except pexpect.EOF:
kelvin-onlabedcff052015-01-16 12:53:55 -0800220 main.log.error( self.name + ": EOF exception found" )
221 main.log.error( self.name + ": " + self.handle.before )
shahshreya28bb18e2014-11-17 10:26:23 -0800222 main.cleanup()
223 main.exit()
kelvin-onlabedcff052015-01-16 12:53:55 -0800224 main.log.info( self.name + ": Ping Response: " + response )
225 # if utilities.assert_matches(
226 # expect=',\s0\%\spacket\sloss',actual=response,onpass="No Packet
227 # loss",onfail="Host is not reachable" ):
228 if re.search( ',\s0\%\spacket\sloss', response ):
229 main.log.info( self.name + ": no packets lost, host is reachable" )
shahshreya28bb18e2014-11-17 10:26:23 -0800230 main.last_result = main.TRUE
231 return main.TRUE
kelvin-onlabedcff052015-01-16 12:53:55 -0800232 else:
233 main.log.error(
234 self.name +
235 ": PACKET LOST, HOST IS NOT REACHABLE" )
shahshreya28bb18e2014-11-17 10:26:23 -0800236 main.last_result = main.FALSE
237 return main.FALSE
238
kelvin-onlabedcff052015-01-16 12:53:55 -0800239 def pingHost( self, **pingParams ):
240 """
Jon Hallfbc828e2015-01-06 17:30:19 -0800241 Pings between two hosts on remote mininet
kelvin-onlabedcff052015-01-16 12:53:55 -0800242 """
243 self.handle.sendline( "" )
244 self.handle.expect( "\$" )
245 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
246 #command = "mininet/util/m " + args[ "SRC" ] + " ping "+args [ "TARGET" ]+" -c 4 -W 1 -i .2"
247 command = "mininet/util/m " + \
248 args[ "SRC" ] + " ping " + args[ "TARGET" ] + " -c 4 -W 1 -i .2"
249 main.log.info( command )
250 response = self.execute( cmd=command, prompt="rtt", timeout=10 )
251 # self.handle.sendline( "" )
252 # self.handle.expect( "\$" )
253 if utilities.assert_matches(
254 expect=',\s0\%\spacket\sloss',
255 actual=response,
256 onpass="No Packet loss",
257 onfail="Host is not reachable" ):
258 main.log.info( "NO PACKET LOSS, HOST IS REACHABLE" )
Jon Hallfbc828e2015-01-06 17:30:19 -0800259 main.last_result = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700260 return main.TRUE
kelvin-onlabedcff052015-01-16 12:53:55 -0800261 else:
262 main.log.error( "PACKET LOST, HOST IS NOT REACHABLE" )
adminbae64d82013-08-01 10:50:15 -0700263 main.last_result = main.FALSE
264 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800265
kelvin-onlabedcff052015-01-16 12:53:55 -0800266 def checknum( self, num ):
267 """
Jon Hallfbc828e2015-01-06 17:30:19 -0800268 Verifies the correct number of switches are running
kelvin-onlabedcff052015-01-16 12:53:55 -0800269 """
270 if self.handle:
271 self.handle.sendline( "" )
272 self.handle.expect( "\$" )
273 self.handle.sendline( 'ifconfig -a | grep "sw.. " | wc -l' )
274 self.handle.expect( "wc" )
275 self.handle.expect( "\$" )
adminbae64d82013-08-01 10:50:15 -0700276 response = self.handle.before
kelvin-onlabedcff052015-01-16 12:53:55 -0800277 self.handle.sendline(
278 'ps -ef | grep "bash -ms mininet:sw" | grep -v color | wc -l' )
279 self.handle.expect( "color" )
280 self.handle.expect( "\$" )
adminbae64d82013-08-01 10:50:15 -0700281 response2 = self.handle.before
282
kelvin-onlabedcff052015-01-16 12:53:55 -0800283 if re.search( num, response ):
284 if re.search( num, response2 ):
adminbae64d82013-08-01 10:50:15 -0700285 return main.TRUE
286 else:
287 return main.FALSE
288 else:
289 return main.FALSE
kelvin-onlabedcff052015-01-16 12:53:55 -0800290 else:
291 main.log.error( "Connection failed to the host" )
adminbae64d82013-08-01 10:50:15 -0700292
kelvin-onlabedcff052015-01-16 12:53:55 -0800293 def start_tcpdump(
294 self,
295 filename,
296 intf="eth0",
297 port="port 6633",
298 user="admin" ):
299 """
admin2a9548d2014-06-17 14:08:07 -0700300 Runs tpdump on an intferface and saves the file
301 intf can be specified, or the default eth0 is used
kelvin-onlabedcff052015-01-16 12:53:55 -0800302 """
admin2a9548d2014-06-17 14:08:07 -0700303 try:
kelvin-onlabedcff052015-01-16 12:53:55 -0800304 self.handle.sendline( "" )
305 self.handle.sendline(
306 "sudo tcpdump -n -i " +
307 intf +
308 " " +
309 port +
310 " -w " +
311 filename.strip() +
312 " -Z " +
313 user +
314 " &" )
315 self.handle.sendline( "" )
316 self.handle.sendline( "" )
317 i = self.handle.expect(
318 [ 'No\ssuch\device', 'listening\son', pexpect.TIMEOUT, "\$" ], timeout=10 )
319 main.log.warn( self.handle.before + self.handle.after )
admin2a9548d2014-06-17 14:08:07 -0700320 if i == 0:
kelvin-onlabedcff052015-01-16 12:53:55 -0800321 main.log.error(
322 self.name +
323 ": tcpdump - No such device exists. tcpdump attempted on: " +
324 intf )
admin2a9548d2014-06-17 14:08:07 -0700325 return main.FALSE
326 elif i == 1:
kelvin-onlabedcff052015-01-16 12:53:55 -0800327 main.log.info( self.name + ": tcpdump started on " + intf )
admin2a9548d2014-06-17 14:08:07 -0700328 return main.TRUE
329 elif i == 2:
kelvin-onlabedcff052015-01-16 12:53:55 -0800330 main.log.error(
331 self.name +
332 ": tcpdump command timed out! Check interface name, given interface was: " +
333 intf )
admin2a9548d2014-06-17 14:08:07 -0700334 return main.FALSE
kelvin-onlabedcff052015-01-16 12:53:55 -0800335 elif i == 3:
336 main.log.info( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -0700337 return main.TRUE
338 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800339 main.log.error( self.name + ": tcpdump - unexpected response" )
admin2a9548d2014-06-17 14:08:07 -0700340 return main.FALSE
341 except pexpect.EOF:
kelvin-onlabedcff052015-01-16 12:53:55 -0800342 main.log.error( self.name + ": EOF exception found" )
343 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -0700344 main.cleanup()
345 main.exit()
346 except:
kelvin-onlabedcff052015-01-16 12:53:55 -0800347 main.log.info(
348 self.name +
349 ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" )
admin2a9548d2014-06-17 14:08:07 -0700350 main.log.error( traceback.print_exc() )
kelvin-onlabedcff052015-01-16 12:53:55 -0800351 main.log.info(
352 ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" )
admin2a9548d2014-06-17 14:08:07 -0700353 main.cleanup()
354 main.exit()
355
kelvin-onlabedcff052015-01-16 12:53:55 -0800356 def stop_tcpdump( self ):
admin2a9548d2014-06-17 14:08:07 -0700357 "pkills tcpdump"
358 try:
kelvin-onlabedcff052015-01-16 12:53:55 -0800359 self.handle.sendline( "sudo pkill tcpdump" )
360 self.handle.sendline( "" )
361 self.handle.sendline( "" )
362 self.handle.expect( "\$" )
admin2a9548d2014-06-17 14:08:07 -0700363 except pexpect.EOF:
kelvin-onlabedcff052015-01-16 12:53:55 -0800364 main.log.error( self.name + ": EOF exception found" )
365 main.log.error( self.name + ": " + self.handle.before )
admin2a9548d2014-06-17 14:08:07 -0700366 main.cleanup()
367 main.exit()
368 except:
kelvin-onlabedcff052015-01-16 12:53:55 -0800369 main.log.info(
370 self.name +
371 ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" )
admin2a9548d2014-06-17 14:08:07 -0700372 main.log.error( traceback.print_exc() )
kelvin-onlabedcff052015-01-16 12:53:55 -0800373 main.log.info(
374 ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" )
admin2a9548d2014-06-17 14:08:07 -0700375 main.cleanup()
376 main.exit()
377
kelvin-onlabedcff052015-01-16 12:53:55 -0800378 def run_optical_mn_script( self ):
379 """
Jon Hallfbc828e2015-01-06 17:30:19 -0800380 This function is only meant for Packet Optical.
kelvin-onlabedcff052015-01-16 12:53:55 -0800381 It runs the python script "optical.py" to create the packet layer( mn )
shahshreya28bb18e2014-11-17 10:26:23 -0800382 topology
kelvin-onlabedcff052015-01-16 12:53:55 -0800383 """
shahshreya28bb18e2014-11-17 10:26:23 -0800384 try:
kelvin-onlabedcff052015-01-16 12:53:55 -0800385 self.handle.sendline( "" )
386 self.handle.expect( "\$" )
387 self.handle.sendline( "cd ~" )
388 self.handle.expect( "\$" )
389 self.handle.sendline( "sudo python optical.py" )
390 self.handle.expect( ">" )
shahshreya28bb18e2014-11-17 10:26:23 -0800391 return main.TRUE
392 except pexpect.EOF:
kelvin-onlabedcff052015-01-16 12:53:55 -0800393 main.log.error( self.name + ": EOF exception found" )
394 main.log.error( self.name + ": " + self.handle.before )
shahshreya28bb18e2014-11-17 10:26:23 -0800395 return main.FALSE
adminbae64d82013-08-01 10:50:15 -0700396
kelvin-onlabedcff052015-01-16 12:53:55 -0800397 def disconnect( self ):
398 """
Jon Hallfbc828e2015-01-06 17:30:19 -0800399 Called at the end of the test to disconnect the handle.
kelvin-onlabedcff052015-01-16 12:53:55 -0800400 """
adminbae64d82013-08-01 10:50:15 -0700401 response = ''
kelvin-onlabedcff052015-01-16 12:53:55 -0800402 # print "Disconnecting Mininet"
adminbae64d82013-08-01 10:50:15 -0700403 if self.handle:
kelvin-onlabedcff052015-01-16 12:53:55 -0800404 self.handle.sendline( "exit" )
405 self.handle.expect( "exit" )
406 self.handle.expect( "(.*)" )
adminbae64d82013-08-01 10:50:15 -0700407 response = self.handle.before
408
kelvin-onlabedcff052015-01-16 12:53:55 -0800409 else:
410 main.log.error( "Connection failed to the host" )
adminbae64d82013-08-01 10:50:15 -0700411 response = main.FALSE
Jon Hall2ef1e9e2014-11-18 14:27:05 -0500412 return response
adminbae64d82013-08-01 10:50:15 -0700413
kelvin-onlabedcff052015-01-16 12:53:55 -0800414 def get_flowTable( self, protoVersion, sw ):
415 # TODO document usage
416 # TODO add option to look at cookies. ignoreing them for now
417 self.handle.sendline( "cd" )
418 self.handle.expect( [ "\$", pexpect.EOF, pexpect.TIMEOUT ] )
419 # print "get_flowTable(" + str( protoVersion ) +" " + str( sw ) +")"
420 # NOTE: Use format to force consistent flow table output across
421 # versions
422 if protoVersion == 1.0:
423 command = "sudo ovs-ofctl dump-flows " + sw + \
424 " -F OpenFlow10-table_id | awk '{OFS=\",\" ; print $1 $3 $6 $7 $8}' | cut -d ',' -f 2- | sort -n -k1 -r"
425 self.handle.sendline( command )
426 self.handle.expect( [ "k1 -r", pexpect.EOF, pexpect.TIMEOUT ] )
427 self.handle.expect(
428 [ "OFPST_FLOW", pexpect.EOF, pexpect.TIMEOUT ] )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700429 response = self.handle.before
kelvin-onlabedcff052015-01-16 12:53:55 -0800430 # print "response=", response
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700431 return response
kelvin-onlabedcff052015-01-16 12:53:55 -0800432 elif protoVersion == 1.3:
433 command = "sudo ovs-ofctl dump-flows " + sw + \
434 " -O OpenFlow13 | awk '{OFS=\",\" ; print $1 $3 $6 $7}' | cut -d ',' -f 2- | sort -n -k1 -r"
435 self.handle.sendline( command )
436 self.handle.expect( [ "k1 -r", pexpect.EOF, pexpect.TIMEOUT ] )
437 self.handle.expect(
438 [ "OFPST_FLOW", pexpect.EOF, pexpect.TIMEOUT ] )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700439 response = self.handle.before
kelvin-onlabedcff052015-01-16 12:53:55 -0800440 # print "response=", response
Jon Hall94fd0472014-12-08 11:52:42 -0800441 return response
442 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800443 main.log.error(
444 "Unknown protoVersion in get_flowTable(). given: (" +
445 str(
446 type( protoVersion ) ) +
447 ") '" +
448 str(protoVersion) +
449 "'" )
Jon Hall94fd0472014-12-08 11:52:42 -0800450
kelvin-onlabedcff052015-01-16 12:53:55 -0800451 def flow_comp( self, flow1, flow2 ):
452 if flow1 == flow2:
santhosh19fd8032014-07-29 11:56:17 -0700453 return main.TRUE
454 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800455 main.log.info( "Flow tables do not match, printing tables:" )
456 main.log.info( "Flow Table 1:" )
457 main.log.info( flow1 )
458 main.log.info( "Flow Table 2:" )
459 main.log.info( flow2 )
santhosh19fd8032014-07-29 11:56:17 -0700460 return main.FALSE
461
kelvin-onlabedcff052015-01-16 12:53:55 -0800462 def setIpTablesOUTPUT(
463 self,
464 dst_ip,
465 dst_port,
466 action='add',
467 packet_type='tcp',
468 rule='DROP' ):
469 """
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700470 Description:
kelvin-onlabedcff052015-01-16 12:53:55 -0800471 add or remove iptables rule to DROP ( default ) packets from specific IP and PORT
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700472 Usage:
kelvin-onlabedcff052015-01-16 12:53:55 -0800473 * specify action ( 'add' or 'remove' )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700474 when removing, pass in the same argument as you would add. It will
Jon Hallfbc828e2015-01-06 17:30:19 -0800475 delete that specific rule.
476 * specify the destination ip to block with dst_ip
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700477 * specify destination port to block to dst_port
kelvin-onlabedcff052015-01-16 12:53:55 -0800478 * optional packet type to block ( default tcp )
479 * optional iptables rule ( default DROP )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700480 WARNING:
481 * This function uses root privilege iptables command which may result in
482 unwanted network errors. USE WITH CAUTION
kelvin-onlabedcff052015-01-16 12:53:55 -0800483 """
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700484 import re
485 import time
486
kelvin-onlabedcff052015-01-16 12:53:55 -0800487 # NOTE*********
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700488 # The strict checking methods of this driver function is intentional
489 # to discourage any misuse or error of iptables, which can cause
490 # severe network errors
491 #*************
492
kelvin-onlabedcff052015-01-16 12:53:55 -0800493 # NOTE: Sleep needed to give some time for rule to be added and registered
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700494 # to the instance
kelvin-onlabedcff052015-01-16 12:53:55 -0800495 time.sleep( 5 )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700496
497 action_type = action.lower()
kelvin-onlabedcff052015-01-16 12:53:55 -0800498 if action_type != 'add' and action_type != 'remove':
499 main.log.error(
500 "Invalid action type. 'add' or 'remove' table rule" )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700501 if rule != 'DROP' and rule != 'ACCEPT' and rule != 'LOG':
kelvin-onlabedcff052015-01-16 12:53:55 -0800502 # NOTE: Currently only supports rules DROP, ACCEPT, and LOG
503 main.log.error(
504 "Invalid rule. 'DROP' or 'ACCEPT' or 'LOG' only." )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700505 return
506 return
507 else:
508
kelvin-onlabedcff052015-01-16 12:53:55 -0800509 # If there is no existing rule in the iptables, we will see an
Jon Hallfbc828e2015-01-06 17:30:19 -0800510 #'iptables:'... message. We expect to see this message.
kelvin-onlabedcff052015-01-16 12:53:55 -0800511 # Otherwise, if there IS an existing rule, we will get the prompt
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700512 # back, hence why we expect $ for remove type. We want to remove
513 # an already existing rule
514
515 if action_type == 'add':
kelvin-onlabedcff052015-01-16 12:53:55 -0800516 # NOTE: "iptables:" expect is a result of return from the command
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700517 # iptables -C ...
Jon Hallfbc828e2015-01-06 17:30:19 -0800518 # Any changes by the iptables command return string
kelvin-onlabedcff052015-01-16 12:53:55 -0800519 # will result in failure of the function. ( deemed unlikely
520 # at the time of writing this function )
521 # Check for existing rules on current input
522 self.handle.sendline( "" )
523 self.handle.expect( "\$" )
524 self.handle.sendline(
525 "sudo iptables -C OUTPUT -p " +
526 str( packet_type ) +
527 " -d " +
528 str( dst_ip ) +
529 " --dport " +
530 str( dst_port ) +
531 " -j " +
532 str( rule ) )
533 i = self.handle.expect( [ "iptables:", "\$" ] )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700534 print i
535 print self.handle.before
536 print "after: "
537 print self.handle.after
538
539 elif action_type == 'remove':
kelvin-onlabedcff052015-01-16 12:53:55 -0800540 # Check for existing rules on current input
541 self.handle.sendline( "" )
542 self.handle.expect( "\$" )
543 self.handle.sendline(
544 "sudo iptables -C OUTPUT -p " +
545 str( packet_type ) +
546 " -d " +
547 str( dst_ip ) +
548 " --dport " +
549 str( dst_port ) +
550 " -j " +
551 str( rule ) )
552 self.handle.expect( "\$" )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700553 print "before: "
554 print self.handle.before
555 actual_string = self.handle.after
556 expect_string = "iptables:"
557 print "Actual String:"
558 print actual_string
559
kelvin-onlabedcff052015-01-16 12:53:55 -0800560 if re.search( expect_string, actual_string ):
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700561 match_result = main.TRUE
562 else:
563 match_result = main.FALSE
kelvin-onlabedcff052015-01-16 12:53:55 -0800564 # If match_result is main.TRUE, it means there is no matching rule.
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700565
kelvin-onlabedcff052015-01-16 12:53:55 -0800566 # If tables does not exist and expected prompt is returned, go ahead and
567 # add iptables rule
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700568 if match_result == main.TRUE:
kelvin-onlabedcff052015-01-16 12:53:55 -0800569 # Ensure action type is add
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700570 if action_type == 'add':
571 #-A is the 'append' action of iptables
572 action_add = '-A'
573 try:
kelvin-onlabedcff052015-01-16 12:53:55 -0800574 self.handle.sendline( "" )
575 self.handle.sendline(
576 "sudo iptables " +
577 action_add +
578 " OUTPUT -p " +
579 str( packet_type ) +
580 " -d " +
581 str( dst_ip ) +
582 " --dport " +
583 str( dst_port ) +
584 " -j " +
585 str( rule ) )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700586
kelvin-onlabedcff052015-01-16 12:53:55 -0800587 info_string = "Rules added to " + str( self.name )
588 info_string += "iptable rule added to block IP: " + \
589 str( dst_ip )
590 info_string += "Port: " + \
591 str( dst_port ) + " Rule: " + str( rule )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700592
kelvin-onlabedcff052015-01-16 12:53:55 -0800593 main.log.info( info_string )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700594
kelvin-onlabedcff052015-01-16 12:53:55 -0800595 self.handle.expect(
596 [ "\$", pexpect.EOF, pexpect.TIMEOUT ] )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700597 except pexpect.TIMEOUT:
kelvin-onlabedcff052015-01-16 12:53:55 -0800598 main.log.error(
599 self.name +
600 ": Timeout exception in setIpTables function" )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700601 except:
kelvin-onlabedcff052015-01-16 12:53:55 -0800602 main.log.error( traceback.print_exc() )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700603 main.cleanup()
604 main.exit()
605 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800606 main.log.error(
607 "Given rule already exists, but attempted to add it" )
608 # If match_result is 0, it means there IS a matching rule provided
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700609 elif match_result == main.FALSE:
kelvin-onlabedcff052015-01-16 12:53:55 -0800610 # Ensure action type is remove
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700611 if action_type == 'remove':
612 #-D is the 'delete' rule of iptables
613 action_remove = '-D'
614 try:
kelvin-onlabedcff052015-01-16 12:53:55 -0800615 self.handle.sendline( "" )
616 # Delete a specific rule specified into the function
617 self.handle.sendline(
618 "sudo iptables " +
619 action_remove +
620 " OUTPUT -p " +
621 str( packet_type ) +
622 " -d " +
623 str( dst_ip ) +
624 " --dport " +
625 str( dst_port ) +
626 " -j " +
627 str( rule ) )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700628
kelvin-onlabedcff052015-01-16 12:53:55 -0800629 info_string = "Rules removed from " + str( self.name )
630 info_string += " iptables rule removed from blocking IP: " + \
631 str( dst_ip )
632 info_string += " Port: " + \
633 str( dst_port ) + " Rule: " + str( rule )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700634
kelvin-onlabedcff052015-01-16 12:53:55 -0800635 main.log.info( info_string )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700636
kelvin-onlabedcff052015-01-16 12:53:55 -0800637 self.handle.expect(
638 [ "\$", pexpect.EOF, pexpect.TIMEOUT ] )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700639 except pexpect.TIMEOUT:
kelvin-onlabedcff052015-01-16 12:53:55 -0800640 main.log.error(
641 self.name +
642 ": Timeout exception in setIpTables function" )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700643 except:
kelvin-onlabedcff052015-01-16 12:53:55 -0800644 main.log.error( traceback.print_exc() )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700645 main.cleanup()
646 main.exit()
647 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800648 main.log.error(
649 "Given rule does not exist, but attempted to remove it" )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700650 else:
kelvin-onlabedcff052015-01-16 12:53:55 -0800651 # NOTE: If a bad usage of this function occurs, exit the entire
652 # test
653 main.log.error( "Bad rule given for iptables. Exiting..." )
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700654 main.cleanup()
655 main.exit()
656
657
adminbae64d82013-08-01 10:50:15 -0700658if __name__ != "__main__":
659 import sys
kelvin-onlabedcff052015-01-16 12:53:55 -0800660 sys.modules[ __name__ ] = RemoteMininetDriver()