blob: 48d3389ad7ced1f9820a2c58067d616878bbc2e6 [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
2'''
3Created on 26-Oct-2012
4
5@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
6
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
11 (at your option) any later version.
12
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
23'''
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
adminbae64d82013-08-01 10:50:15 -070028sys.path.append("../")
29from drivers.common.cli.emulatordriver import Emulator
adminbae64d82013-08-01 10:50:15 -070030
31class RemoteMininetDriver(Emulator):
32 '''
adminaeedddd2013-08-02 15:14:15 -070033 RemoteMininetCliDriver is the basic driver which will handle the Mininet functions
Jon Hallfbc828e2015-01-06 17:30:19 -080034 The main different between this and the MininetCliDriver is that this one does not build the mininet.
35 It assumes that there is already a mininet running on the target.
adminbae64d82013-08-01 10:50:15 -070036 '''
37 def __init__(self):
38 super(Emulator, self).__init__()
39 self.handle = self
40 self.wrapped = sys.modules[__name__]
41 self.flag = 0
42
43 def connect(self, **connectargs):
44 #,user_name, ip_address, pwd,options):
45 # Here the main is the TestON instance after creating all the log handles.
46 for key in connectargs:
Jon Hallfbc828e2015-01-06 17:30:19 -080047 vars(self)[key] = connectargs[key]
48
adminbae64d82013-08-01 10:50:15 -070049 self.name = self.options['name']
50 self.handle = super(RemoteMininetDriver, self).connect(user_name = self.user_name, ip_address = self.ip_address,port = None, pwd = self.pwd)
Jon Hallfbc828e2015-01-06 17:30:19 -080051
adminbae64d82013-08-01 10:50:15 -070052 self.ssh_handle = self.handle
Jon Hallfbc828e2015-01-06 17:30:19 -080053
54 # Copying the readme file to process the
adminbae64d82013-08-01 10:50:15 -070055 if self.handle :
56 return main.TRUE
57
58 else :
Jon Hallfbc828e2015-01-06 17:30:19 -080059 main.log.error("Connection failed to the host "+self.user_name+"@"+self.ip_address)
adminbae64d82013-08-01 10:50:15 -070060 main.log.error("Failed to connect to the Mininet")
61 return main.FALSE
admin98ad0092014-07-23 16:51:07 -070062
63#*********************************************************************************************
64#*********************************************************************************************
Jon Hallfbc828e2015-01-06 17:30:19 -080065# checkForLoss will determine if any of the pings had any packets lost during the course of
admin98ad0092014-07-23 16:51:07 -070066# the pingLong.
67#*********************************************************************************************
68#*********************************************************************************************
69
admin2580a0e2014-07-29 11:24:34 -070070 def checkForLoss(self, pingList):
Jon Hall6c794f32014-08-14 13:33:13 -070071 '''
72 Returns main.FALSE for 0% packet loss and
73 Returns main.ERROR if "found multiple mininet" is found and
74 Returns main.TRUE else
75 '''
Jon Hall368769f2014-11-19 15:43:35 -080076 #TODO: maybe we want to return the % loss instead? This way we can set an acceptible loss %.
77 #EX: 393 packets transmitted, 380 received, 3% packet loss, time 78519ms
78 # we may need to return a float to get around rounding errors
79
admin2580a0e2014-07-29 11:24:34 -070080 self.handle.sendline("")
81 self.handle.expect("\$")
Jon Hall368769f2014-11-19 15:43:35 -080082 #Clear any output waiting in the bg from killing pings
83 self.handle.sendline("")
84 self.handle.expect("\$")
admin2580a0e2014-07-29 11:24:34 -070085 self.handle.sendline("cat " + pingList)
86 self.handle.expect(pingList)
87 self.handle.expect("\$")
88 outputs = self.handle.before + self.handle.after
89 if re.search(" 0% packet loss",outputs):
admin98ad0092014-07-23 16:51:07 -070090 return main.FALSE
admin2580a0e2014-07-29 11:24:34 -070091 elif re.search("found multiple mininet",outputs):
92 return main.ERROR
shahshreyaf4d4d0c2014-10-10 12:11:10 -070093 else:
Jon Hall2ef1e9e2014-11-18 14:27:05 -050094 main.log.error("Error, unexpected output in the ping file")
95 main.log.warn( outputs )
shahshreyaf4d4d0c2014-10-10 12:11:10 -070096 return main.TRUE
97
admin98ad0092014-07-23 16:51:07 -070098
99
adminbae64d82013-08-01 10:50:15 -0700100 def pingLong(self,**pingParams):
adminaeedddd2013-08-02 15:14:15 -0700101 '''
Jon Hallfbc828e2015-01-06 17:30:19 -0800102 Starts a continuous ping on the mininet host outputing to a file in the /tmp dir.
adminaeedddd2013-08-02 15:14:15 -0700103 '''
Jon Hall6c794f32014-08-14 13:33:13 -0700104 self.handle.sendline("")
105 self.handle.expect("\$")
admin98ad0092014-07-23 16:51:07 -0700106 args = utilities.parse_args(["SRC","TARGET","PINGTIME"],**pingParams)
Jon Hall6c794f32014-08-14 13:33:13 -0700107 precmd = "sudo rm /tmp/ping." + args["SRC"]
admin530b4c92013-08-14 16:54:35 -0700108 self.execute(cmd=precmd,prompt="(.*)",timeout=10)
Jon Hall94fd0472014-12-08 11:52:42 -0800109 command = "sudo mininet/util/m " + args["SRC"] + " ping "+args ["TARGET"]+" -i .2 -w " + str(args['PINGTIME']) + " -D > /tmp/ping." + args["SRC"] + " &"
Jon Hallfbc828e2015-01-06 17:30:19 -0800110 main.log.info( command )
adminbae64d82013-08-01 10:50:15 -0700111 self.execute(cmd=command,prompt="(.*)",timeout=10)
Jon Hall6c794f32014-08-14 13:33:13 -0700112 self.handle.sendline("")
113 self.handle.expect("\$")
adminbae64d82013-08-01 10:50:15 -0700114 return main.TRUE
115
116 def pingstatus(self,**pingParams):
adminaeedddd2013-08-02 15:14:15 -0700117 '''
118 Tails the respective ping output file and check that there is a moving "64 bytes"
119 '''
Jon Hall6c794f32014-08-14 13:33:13 -0700120 self.handle.sendline("")
121 self.handle.expect("\$")
adminbae64d82013-08-01 10:50:15 -0700122 args = utilities.parse_args(["SRC"],**pingParams)
123 self.handle.sendline("tail /tmp/ping." + args["SRC"])
124 self.handle.expect("tail")
125 self.handle.expect("\$")
126 result = self.handle.before + self.handle.after
Jon Hall6c794f32014-08-14 13:33:13 -0700127 self.handle.sendline("")
128 self.handle.expect("\$")
adminbae64d82013-08-01 10:50:15 -0700129 if re.search('Unreachable', result ):
Jon Hallfbc828e2015-01-06 17:30:19 -0800130 main.log.info("Unreachable found in ping logs...")
adminbae64d82013-08-01 10:50:15 -0700131 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800132 elif re.search('64\sbytes', result):
133 main.log.info("Pings look good")
adminbae64d82013-08-01 10:50:15 -0700134 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -0800135 else:
136 main.log.info("No, or faulty ping data...")
adminbae64d82013-08-01 10:50:15 -0700137 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800138
Jon Hall6c794f32014-08-14 13:33:13 -0700139 def pingKill(self, testONUser, testONIP):
adminaeedddd2013-08-02 15:14:15 -0700140 '''
141 Kills all continuous ping processes.
142 Then copies all the ping files to the TestStation.
143 '''
Jon Hall6c794f32014-08-14 13:33:13 -0700144 self.handle.sendline("")
145 self.handle.expect("\$")
Jon Hallfbc828e2015-01-06 17:30:19 -0800146 command = "sudo kill -SIGINT `pgrep ping`"
147 main.log.info( command )
adminbae64d82013-08-01 10:50:15 -0700148 self.execute(cmd=command,prompt="(.*)",timeout=10)
Jon Hallfbc828e2015-01-06 17:30:19 -0800149
adminbae64d82013-08-01 10:50:15 -0700150 main.log.info( "Transferring ping files to TestStation" )
Jon Hallfbc828e2015-01-06 17:30:19 -0800151 command = "scp /tmp/ping.* "+ str(testONUser) + "@" + str(testONIP) + ":/tmp/"
adminbae64d82013-08-01 10:50:15 -0700152 self.execute(cmd=command,prompt="100%",timeout=20)
Jon Hall2ef1e9e2014-11-18 14:27:05 -0500153 #Make sure the output is cleared
154 self.handle.sendline("")
155 self.handle.expect("\$")
156 self.handle.sendline("")
157 self.handle.expect("\$")
Jon Hall6c794f32014-08-14 13:33:13 -0700158 self.handle.sendline("")
Jon Hall368769f2014-11-19 15:43:35 -0800159 i=self.handle.expect(["password","\$"])
160 if i == 0:
161 main.log.error("Error, sudo asking for password")
162 main.log.error(self.handle.before)
163 return main.FALSE
164 else:
165 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -0800166
admin2580a0e2014-07-29 11:24:34 -0700167 def pingLongKill(self):
Jon Hall6c794f32014-08-14 13:33:13 -0700168 self.handle.sendline("")
169 self.handle.expect("\$")
admin2580a0e2014-07-29 11:24:34 -0700170 command = "sudo kill -SIGING `pgrep ping`"
171 main.log.info(command)
172 self.execute(cmd=command,prompt="(.*)",timeout=10)
Jon Hall6c794f32014-08-14 13:33:13 -0700173 self.handle.sendline("")
174 self.handle.expect("\$")
adminbae64d82013-08-01 10:50:15 -0700175 return main.TRUE
Jon Hallfbc828e2015-01-06 17:30:19 -0800176
shahshreya28bb18e2014-11-17 10:26:23 -0800177 def pingHostOptical(self,**pingParams):
178 '''
179 This function is only for Packey Optical related ping
180 Use the next pingHost() function for all normal scenarios)
181 Ping from one mininet host to another
182 Currently the only supported Params: SRC and TARGET
183 '''
184 args = utilities.parse_args(["SRC","TARGET"],**pingParams)
185 #command = args["SRC"] + " ping -" + args["CONTROLLER"] + " " +args ["TARGET"]
186 command = args["SRC"] + " ping "+args ["TARGET"]+" -c 1 -i 1 -W 8"
187 try:
188 main.log.warn("Sending: " + command)
189 #response = self.execute(cmd=command,prompt="mininet",timeout=10 )
190 self.handle.sendline(command)
191 i = self.handle.expect([command,pexpect.TIMEOUT])
192 if i == 1:
193 main.log.error(self.name + ": timeout when waiting for response from mininet")
194 main.log.error("response: " + str(self.handle.before))
195 i = self.handle.expect(["mininet>",pexpect.TIMEOUT])
196 if i == 1:
197 main.log.error(self.name + ": timeout when waiting for response from mininet")
198 main.log.error("response: " + str(self.handle.before))
199 response = self.handle.before
200 except pexpect.EOF:
201 main.log.error(self.name + ": EOF exception found")
202 main.log.error(self.name + ": " + self.handle.before)
203 main.cleanup()
204 main.exit()
205 main.log.info(self.name+": Ping Response: "+ response )
206 #if utilities.assert_matches(expect=',\s0\%\spacket\sloss',actual=response,onpass="No Packet loss",onfail="Host is not reachable"):
207 if re.search(',\s0\%\spacket\sloss',response):
208 main.log.info(self.name+": no packets lost, host is reachable")
209 main.last_result = main.TRUE
210 return main.TRUE
211 else :
212 main.log.error(self.name+": PACKET LOST, HOST IS NOT REACHABLE")
213 main.last_result = main.FALSE
214 return main.FALSE
215
adminbae64d82013-08-01 10:50:15 -0700216 def pingHost(self,**pingParams):
Jon Hallfbc828e2015-01-06 17:30:19 -0800217 '''
218 Pings between two hosts on remote mininet
219 '''
Jon Hall6c794f32014-08-14 13:33:13 -0700220 self.handle.sendline("")
221 self.handle.expect("\$")
adminbae64d82013-08-01 10:50:15 -0700222 args = utilities.parse_args(["SRC","TARGET"],**pingParams)
shahshreya28bb18e2014-11-17 10:26:23 -0800223 #command = "mininet/util/m " + args["SRC"] + " ping "+args ["TARGET"]+" -c 4 -W 1 -i .2"
adminbae64d82013-08-01 10:50:15 -0700224 command = "mininet/util/m " + args["SRC"] + " ping "+args ["TARGET"]+" -c 4 -W 1 -i .2"
Jon Hallfbc828e2015-01-06 17:30:19 -0800225 main.log.info ( command )
adminbae64d82013-08-01 10:50:15 -0700226 response = self.execute(cmd=command,prompt="rtt",timeout=10 )
shahshreya28bb18e2014-11-17 10:26:23 -0800227 #self.handle.sendline("")
228 #self.handle.expect("\$")
adminbae64d82013-08-01 10:50:15 -0700229 if utilities.assert_matches(expect=',\s0\%\spacket\sloss',actual=response,onpass="No Packet loss",onfail="Host is not reachable"):
230 main.log.info("NO PACKET LOSS, HOST IS REACHABLE")
Jon Hallfbc828e2015-01-06 17:30:19 -0800231 main.last_result = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700232 return main.TRUE
233 else :
234 main.log.error("PACKET LOST, HOST IS NOT REACHABLE")
235 main.last_result = main.FALSE
236 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800237
238
adminbae64d82013-08-01 10:50:15 -0700239 def checknum(self,num):
240 '''
Jon Hallfbc828e2015-01-06 17:30:19 -0800241 Verifies the correct number of switches are running
adminbae64d82013-08-01 10:50:15 -0700242 '''
243 if self.handle :
244 self.handle.sendline("")
245 self.handle.expect("\$")
246 self.handle.sendline('ifconfig -a | grep "sw.. " | wc -l')
247 self.handle.expect("wc")
248 self.handle.expect("\$")
249 response = self.handle.before
Jon Hallfbc828e2015-01-06 17:30:19 -0800250 self.handle.sendline('ps -ef | grep "bash -ms mininet:sw" | grep -v color | wc -l')
adminbae64d82013-08-01 10:50:15 -0700251 self.handle.expect("color")
252 self.handle.expect("\$")
253 response2 = self.handle.before
254
255 if re.search(num, response):
256 if re.search(num, response2):
257 return main.TRUE
258 else:
259 return main.FALSE
260 else:
261 return main.FALSE
262 else :
Jon Hallfbc828e2015-01-06 17:30:19 -0800263 main.log.error("Connection failed to the host")
adminbae64d82013-08-01 10:50:15 -0700264
Jon Hall73cf9cc2014-11-20 22:28:38 -0800265 def start_tcpdump(self, filename, intf = "eth0", port = "port 6633", user="admin"):
Jon Hallfbc828e2015-01-06 17:30:19 -0800266 '''
admin2a9548d2014-06-17 14:08:07 -0700267 Runs tpdump on an intferface and saves the file
268 intf can be specified, or the default eth0 is used
269 '''
270 try:
271 self.handle.sendline("")
Jon Hall73cf9cc2014-11-20 22:28:38 -0800272 self.handle.sendline("sudo tcpdump -n -i "+ intf + " " + port + " -w " + filename.strip() + " -Z " + user + " &")
admin2a9548d2014-06-17 14:08:07 -0700273 self.handle.sendline("")
274 self.handle.sendline("")
275 i=self.handle.expect(['No\ssuch\device','listening\son',pexpect.TIMEOUT,"\$"],timeout=10)
276 main.log.warn(self.handle.before + self.handle.after)
277 if i == 0:
278 main.log.error(self.name + ": tcpdump - No such device exists. tcpdump attempted on: " + intf)
279 return main.FALSE
280 elif i == 1:
281 main.log.info(self.name + ": tcpdump started on " + intf)
282 return main.TRUE
283 elif i == 2:
284 main.log.error(self.name + ": tcpdump command timed out! Check interface name, given interface was: " + intf)
285 return main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800286 elif i ==3:
admin2a9548d2014-06-17 14:08:07 -0700287 main.log.info(self.name +": " + self.handle.before)
288 return main.TRUE
289 else:
290 main.log.error(self.name + ": tcpdump - unexpected response")
291 return main.FALSE
292 except pexpect.EOF:
293 main.log.error(self.name + ": EOF exception found")
294 main.log.error(self.name + ": " + self.handle.before)
295 main.cleanup()
296 main.exit()
297 except:
298 main.log.info(self.name + ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::")
299 main.log.error( traceback.print_exc() )
300 main.log.info(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::")
301 main.cleanup()
302 main.exit()
303
304 def stop_tcpdump(self):
305 "pkills tcpdump"
306 try:
307 self.handle.sendline("sudo pkill tcpdump")
308 self.handle.sendline("")
309 self.handle.sendline("")
310 self.handle.expect("\$")
311 except pexpect.EOF:
312 main.log.error(self.name + ": EOF exception found")
313 main.log.error(self.name + ": " + self.handle.before)
314 main.cleanup()
315 main.exit()
316 except:
317 main.log.info(self.name + ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::")
318 main.log.error( traceback.print_exc() )
319 main.log.info(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::")
320 main.cleanup()
321 main.exit()
322
shahshreya4d79aab2014-11-07 15:20:41 -0800323 def run_optical_mn_script(self):
shahshreya28bb18e2014-11-17 10:26:23 -0800324 '''
Jon Hallfbc828e2015-01-06 17:30:19 -0800325 This function is only meant for Packet Optical.
shahshreya28bb18e2014-11-17 10:26:23 -0800326 It runs the python script "optical.py" to create the packet layer(mn)
327 topology
328 '''
329 try:
330 self.handle.sendline("")
331 self.handle.expect("\$")
332 self.handle.sendline("cd ~")
333 self.handle.expect("\$")
334 self.handle.sendline("sudo python optical.py")
335 self.handle.expect(">")
336 return main.TRUE
337 except pexpect.EOF:
338 main.log.error(self.name + ": EOF exception found")
339 main.log.error(self.name + ": " + self.handle.before)
340 return main.FALSE
adminbae64d82013-08-01 10:50:15 -0700341
342 def disconnect(self):
Jon Hallfbc828e2015-01-06 17:30:19 -0800343 '''
344 Called at the end of the test to disconnect the handle.
345 '''
adminbae64d82013-08-01 10:50:15 -0700346 response = ''
347 #print "Disconnecting Mininet"
348 if self.handle:
Jon Hall2ef1e9e2014-11-18 14:27:05 -0500349 self.handle.sendline("exit")
adminbae64d82013-08-01 10:50:15 -0700350 self.handle.expect("exit")
351 self.handle.expect("(.*)")
352 response = self.handle.before
353
354 else :
355 main.log.error("Connection failed to the host")
356 response = main.FALSE
Jon Hall2ef1e9e2014-11-18 14:27:05 -0500357 return response
adminbae64d82013-08-01 10:50:15 -0700358
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700359 def get_flowTable(self, protoVersion, sw):
Jon Hall2ef1e9e2014-11-18 14:27:05 -0500360 #TODO document usage
Jon Hall94fd0472014-12-08 11:52:42 -0800361 #TODO add option to look at cookies. ignoreing them for now
santhosh9da93892014-07-28 14:11:19 -0700362 self.handle.sendline("cd")
Jon Hall2ef1e9e2014-11-18 14:27:05 -0500363 self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
Jon Hall94fd0472014-12-08 11:52:42 -0800364 #print "get_flowTable(" + str(protoVersion) +" " + str(sw) +")"
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700365 #NOTE: Use format to force consistent flow table output across versions
366 if protoVersion==1.0:
Jon Hall94fd0472014-12-08 11:52:42 -0800367 command = "sudo ovs-ofctl dump-flows " + sw + " -F OpenFlow10-table_id | awk '{OFS=\",\" ; print $1 $3 $6 $7 $8}' | cut -d ',' -f 2- | sort -n -k1 -r"
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700368 self.handle.sendline(command)
Jon Hall94fd0472014-12-08 11:52:42 -0800369 self.handle.expect(["k1 -r",pexpect.EOF,pexpect.TIMEOUT])
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700370 self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
371 response = self.handle.before
372 #print "response=", response
373 return response
374 elif protoVersion==1.3:
Jon Hall94fd0472014-12-08 11:52:42 -0800375 command = "sudo ovs-ofctl dump-flows " + sw + " -O OpenFlow13 | awk '{OFS=\",\" ; print $1 $3 $6 $7}' | cut -d ',' -f 2- | sort -n -k1 -r"
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700376 self.handle.sendline(command)
Jon Hall94fd0472014-12-08 11:52:42 -0800377 self.handle.expect(["k1 -r",pexpect.EOF,pexpect.TIMEOUT])
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700378 self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700379 response = self.handle.before
380 #print "response=", response
Jon Hall94fd0472014-12-08 11:52:42 -0800381 return response
382 else:
383 main.log.error("Unknown protoVersion in get_flowTable(). given: ("+str(type(protoVersion))+") '"+str(protoVersion)+"'")
384
santhosh19fd8032014-07-29 11:56:17 -0700385
386 def flow_comp(self,flow1,flow2):
387 if flow1==flow2:
388 return main.TRUE
389 else:
Jon Hall6c794f32014-08-14 13:33:13 -0700390 main.log.info("Flow tables do not match, printing tables:")
Jon Hall94fd0472014-12-08 11:52:42 -0800391 main.log.info("Flow Table 1:")
392 main.log.info(flow1)
393 main.log.info("Flow Table 2:")
394 main.log.info(flow2)
santhosh19fd8032014-07-29 11:56:17 -0700395 return main.FALSE
396
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700397 def setIpTablesOUTPUT(self, dst_ip, dst_port, action='add', packet_type='tcp',rule='DROP'):
398 '''
399 Description:
400 add or remove iptables rule to DROP (default) packets from specific IP and PORT
401 Usage:
402 * specify action ('add' or 'remove')
403 when removing, pass in the same argument as you would add. It will
Jon Hallfbc828e2015-01-06 17:30:19 -0800404 delete that specific rule.
405 * specify the destination ip to block with dst_ip
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700406 * specify destination port to block to dst_port
407 * optional packet type to block (default tcp)
408 * optional iptables rule (default DROP)
409 WARNING:
410 * This function uses root privilege iptables command which may result in
411 unwanted network errors. USE WITH CAUTION
412 '''
413 import re
414 import time
415
416 #NOTE*********
417 # The strict checking methods of this driver function is intentional
418 # to discourage any misuse or error of iptables, which can cause
419 # severe network errors
420 #*************
421
422 #NOTE: Sleep needed to give some time for rule to be added and registered
423 # to the instance
424 time.sleep(5)
425
426 action_type = action.lower()
427 if action_type != 'add' and action_type !='remove':
428 main.log.error("Invalid action type. 'add' or 'remove' table rule")
429 if rule != 'DROP' and rule != 'ACCEPT' and rule != 'LOG':
430 #NOTE: Currently only supports rules DROP, ACCEPT, and LOG
431 main.log.error("Invalid rule. 'DROP' or 'ACCEPT' or 'LOG' only.")
432 return
433 return
434 else:
435
Jon Hallfbc828e2015-01-06 17:30:19 -0800436 #If there is no existing rule in the iptables, we will see an
437 #'iptables:'... message. We expect to see this message.
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700438 #Otherwise, if there IS an existing rule, we will get the prompt
439 # back, hence why we expect $ for remove type. We want to remove
440 # an already existing rule
441
442 if action_type == 'add':
443 #NOTE: "iptables:" expect is a result of return from the command
444 # iptables -C ...
Jon Hallfbc828e2015-01-06 17:30:19 -0800445 # Any changes by the iptables command return string
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700446 # will result in failure of the function. (deemed unlikely
447 # at the time of writing this function)
448 #Check for existing rules on current input
449 self.handle.sendline("")
450 self.handle.expect("\$")
451 self.handle.sendline("sudo iptables -C OUTPUT -p "+str(packet_type)+
452 " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
453 i = self.handle.expect(["iptables:", "\$"])
454 print i
455 print self.handle.before
456 print "after: "
457 print self.handle.after
458
459 elif action_type == 'remove':
460 #Check for existing rules on current input
461 self.handle.sendline("")
462 self.handle.expect("\$")
463 self.handle.sendline("sudo iptables -C OUTPUT -p "+str(packet_type)+
464 " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
465 self.handle.expect("\$")
466 print "before: "
467 print self.handle.before
468 actual_string = self.handle.after
469 expect_string = "iptables:"
470 print "Actual String:"
471 print actual_string
472
473 if re.search(expect_string, actual_string):
474 match_result = main.TRUE
475 else:
476 match_result = main.FALSE
Jon Hallfbc828e2015-01-06 17:30:19 -0800477 #If match_result is main.TRUE, it means there is no matching rule.
shahshreyaf4d4d0c2014-10-10 12:11:10 -0700478
479 #If tables does not exist and expected prompt is returned, go ahead and
480 #add iptables rule
481 if match_result == main.TRUE:
482 #Ensure action type is add
483 if action_type == 'add':
484 #-A is the 'append' action of iptables
485 action_add = '-A'
486 try:
487 self.handle.sendline("")
488 self.handle.sendline("sudo iptables "+action_add+" OUTPUT -p "+str(packet_type)+
489 " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
490
491 info_string = "Rules added to "+str(self.name)
492 info_string += "iptable rule added to block IP: "+str(dst_ip)
493 info_string += "Port: "+str(dst_port)+" Rule: "+str(rule)
494
495 main.log.info(info_string)
496
497 self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
498 except pexpect.TIMEOUT:
499 main.log.error(self.name + ": Timeout exception in setIpTables function")
500 except:
501 main.log.error( traceback.print_exc())
502 main.cleanup()
503 main.exit()
504 else:
505 main.log.error("Given rule already exists, but attempted to add it")
506 #If match_result is 0, it means there IS a matching rule provided
507 elif match_result == main.FALSE:
508 #Ensure action type is remove
509 if action_type == 'remove':
510 #-D is the 'delete' rule of iptables
511 action_remove = '-D'
512 try:
513 self.handle.sendline("")
514 #Delete a specific rule specified into the function
515 self.handle.sendline("sudo iptables "+action_remove+" OUTPUT -p "+str(packet_type)+
516 " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
517
518 info_string = "Rules removed from "+str(self.name)
519 info_string += " iptables rule removed from blocking IP: "+str(dst_ip)
520 info_string += " Port: "+str(dst_port)+" Rule: "+str(rule)
521
522 main.log.info(info_string)
523
524 self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
525 except pexpect.TIMEOUT:
526 main.log.error(self.name + ": Timeout exception in setIpTables function")
527 except:
528 main.log.error( traceback.print_exc())
529 main.cleanup()
530 main.exit()
531 else:
532 main.log.error("Given rule does not exist, but attempted to remove it")
533 else:
534 #NOTE: If a bad usage of this function occurs, exit the entire test
535 main.log.error("Bad rule given for iptables. Exiting...")
536 main.cleanup()
537 main.exit()
538
539
adminbae64d82013-08-01 10:50:15 -0700540if __name__ != "__main__":
541 import sys
542 sys.modules[__name__] = RemoteMininetDriver()