Added arg3 to take care of 1.3 switches
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 095bae7..b7e3694 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -73,9 +73,9 @@
main.log.info(self.name+": building fresh mininet")
#### for reactive/PARP enabled tests
- cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] + " --mac --controller " + self.options['controller']
+ cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] + " --mac --controller " + self.options['controller'] + " " + self.options['arg3']
#### for proactive flow with static ARP entries
- #cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] + " --mac --arp --controller " + self.options['controller']
+ #cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] + " --mac --arp --controller " + self.options['controller'] + " " + self.options['arg3']
self.handle.sendline(cmdString)
self.handle.expect(["sudo mn",pexpect.EOF,pexpect.TIMEOUT])
while 1:
@@ -839,15 +839,36 @@
onos_ports.append(port['portNumber'])
mn_ports.sort()
onos_ports.sort()
- if mn_ports == onos_ports:
+ #print "mn_ports[] = ", mn_ports
+ #print "onos_ports90 = ", onos_ports
+
+ #if mn_ports == onos_ports:
+ #pass #don't set results to true here as this is just one of many checks and it might override a failure
+
+ #For OF1.3, the OFP_local port number is 0xfffffffe or 4294967294 instead of 0xfffe or 65534 in OF1.0, ONOS topology
+ #sees the correct port number, however MN topolofy as read from line 151 of https://github.com/ucb-sts/sts/blob/
+ #topology_refactoring2/sts/entities/teston_entities.py is 0xfffe which doesn't work correctly with OF1.3 switches.
+ #So a short term fix is to ignore the case when mn_port == 65534 and onos_port ==4294967294.
+ for mn_port,onos_port in zip(mn_ports,onos_ports):
+ if mn_port == onos_port or (mn_port == 65534 and onos_port ==4294967294):
+ continue
+ else:
+ port_results = main.FALSE
+ break
pass #don't set results to true here as this is just one of many checks and it might override a failure
+ '''
else: #the ports of this switch don't match
port_results = main.FALSE
main.log.report("ports in MN switch %s(%s) but not in ONOS:" % (switch['name'],switch['dpid']))
main.log.report( str([port for port in mn_ports if port not in onos_ports]))
main.log.report("ports in ONOS switch %s(%s) but not in MN:" % (switch['name'],switch['dpid']))
main.log.report( str([port for port in onos_ports if port not in mn_ports]))
-
+ '''
+ if port_results == main.FALSE:
+ main.log.report("ports in MN switch %s(%s) but not in ONOS:" % (switch['name'],switch['dpid']))
+ main.log.report( str([port for port in mn_ports if port not in onos_ports]))
+ main.log.report("ports in ONOS switch %s(%s) but not in MN:" % (switch['name'],switch['dpid']))
+ main.log.report( str([port for port in onos_ports if port not in mn_ports]))
#######Links########
# iterate through MN links and check if and ONOS link exists in both directions
@@ -911,27 +932,6 @@
return results
- def links_status(self):
- """
- Returns list of links and their status
- """
- if self.handle :
- cmd = "py 'Links: %s' % [item for sublist in [[(y[0].name, y[1].name, y[0].isUp() and y[1].isUp()) for y in x[0].connectionsTo(x[1])] for x in __import__('itertools').permutations(net.nameToNode.values(), 2) if x[0] != x[1] and x[0].connectionsTo(x[1])] for item in sublist]"
- try:
- response = self.execute(cmd=cmd,prompt="mininet>",timeout=10)
- if not response:
- return None
- for line in response.split('\n'):
- if line.startswith('Links:'):
- return eval(line[len("Links :"):])
- except pexpect.EOF:
- main.log.error(self.name + ": EOF exception found")
- main.log.error(self.name + ": " + self.handle.before)
- main.cleanup()
- main.exit()
- return response
- else:
- main.log.error("Connection failed to the node")
diff --git a/TestON/drivers/common/cli/emulator/remotemininetdriver.py b/TestON/drivers/common/cli/emulator/remotemininetdriver.py
index d6e839d..2acddb4 100644
--- a/TestON/drivers/common/cli/emulator/remotemininetdriver.py
+++ b/TestON/drivers/common/cli/emulator/remotemininetdriver.py
@@ -91,7 +91,10 @@
return main.FALSE
elif re.search("found multiple mininet",outputs):
return main.ERROR
- return main.TRUE
+ else:
+ print outputs
+ return main.TRUE
+
def pingLong(self,**pingParams):
@@ -421,6 +424,7 @@
return main.TRUE
def add_switch(self,sw):
+ #FIXME: Remove hardcoded number of ports
self.handle.sendline("")
self.handle.expect("\$")
self.handle.sendline("sudo ovs-vsctl add-br "+sw)
@@ -472,32 +476,204 @@
response = main.FALSE
return response
- def get_flowTable(self,sw):
+ def get_flowTable(self, protoVersion, sw):
self.handle.sendline("cd")
- self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+ #self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+ print "cd expect status: "
+ print self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
#TODO: Write seperate versions of the function for this, possibly a string that tells it which switch is in use?
#For 1.0 version of OVS
#command = "sudo ovs-ofctl dump-flows " + sw + " | awk '{OFS=\",\" ; print $1 $6 $7 }' |sort -n -k1"
#for 1.3 version of OVS
- command = "sudo ovs-ofctl dump-flows " + sw + " | awk '{OFS=\",\" ; print $1 $3 $7 $8}' |sort -n -k1"
- self.handle.sendline(command)
- self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
- self.handle.expect(["NXST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
- response = self.handle.before
- return response
+ #command = "sudo ovs-ofctl dump-flows " + sw + " | awk '{OFS=\",\" ; print $1 $3 $7 $8}' |sort -n -k1"
+ #NOTE: Use format to force consistent flow table output across versions
+ if protoVersion==1.0:
+ command = "sudo ovs-ofctl dump-flows " + sw + " -F OpenFlow10-table_id | awk '{OFS=\",\" ; print $1 $3 $6 $7 $8}' |sort -n -k1"
+ self.handle.sendline(command)
+ self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
+ self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
+ response = self.handle.before
+ #print "response=", response
+ return response
+ elif protoVersion==1.3:
+ command = "sudo ovs-ofctl dump-flows " + sw + " -O OpenFlow13 | awk '{OFS=\",\" ; print $1 $3 $6 $7}' |sort -n -k1"
+ self.handle.sendline(command)
+ #print "ovs-vsctl Command sent status."
+ #self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
+ #print "sort return status: "
+ #print self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
+ #print self.handle.before
+ self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
+ #print "OFPST_FLOW expected status: "
+ #print self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
+ #print self.handle.before
+ response = self.handle.before
+ #print "response=", response
+ return response
def flow_comp(self,flow1,flow2):
+ #print "Inside flow compare function"
+ #print "Flow1 Table:"
+ #for flow in flow1:
+ #print flow1
+ #print "Flow2 Table"
+ #for flow in flow2:
+ #print flow2
+
if flow1==flow2:
return main.TRUE
else:
main.log.info("Flow tables do not match, printing tables:")
- main.log.info("Flow Table 1:")
- main.log.info(flow1)
- main.log.info("Flow Table 2:")
- main.log.info(flow2)
+ #main.log.info("Flow Table 1:")
+ #main.log.info(flow1)
+ #main.log.info("Flow Table 2:")
+ #main.log.info(flow2)
return main.FALSE
+ def setIpTablesOUTPUT(self, dst_ip, dst_port, action='add', packet_type='tcp',rule='DROP'):
+ '''
+ Description:
+ add or remove iptables rule to DROP (default) packets from specific IP and PORT
+ Usage:
+ * specify action ('add' or 'remove')
+ when removing, pass in the same argument as you would add. It will
+ delete that specific rule.
+ * specify the destination ip to block with dst_ip
+ * specify destination port to block to dst_port
+ * optional packet type to block (default tcp)
+ * optional iptables rule (default DROP)
+ WARNING:
+ * This function uses root privilege iptables command which may result in
+ unwanted network errors. USE WITH CAUTION
+ '''
+ import re
+ import time
+
+ #NOTE*********
+ # The strict checking methods of this driver function is intentional
+ # to discourage any misuse or error of iptables, which can cause
+ # severe network errors
+ #*************
+
+ #NOTE: Sleep needed to give some time for rule to be added and registered
+ # to the instance
+ time.sleep(5)
+
+ action_type = action.lower()
+ if action_type != 'add' and action_type !='remove':
+ main.log.error("Invalid action type. 'add' or 'remove' table rule")
+ if rule != 'DROP' and rule != 'ACCEPT' and rule != 'LOG':
+ #NOTE: Currently only supports rules DROP, ACCEPT, and LOG
+ main.log.error("Invalid rule. 'DROP' or 'ACCEPT' or 'LOG' only.")
+ return
+ return
+ else:
+
+ #If there is no existing rule in the iptables, we will see an
+ #'iptables:'... message. We expect to see this message.
+ #Otherwise, if there IS an existing rule, we will get the prompt
+ # back, hence why we expect $ for remove type. We want to remove
+ # an already existing rule
+
+ if action_type == 'add':
+ #NOTE: "iptables:" expect is a result of return from the command
+ # iptables -C ...
+ # Any changes by the iptables command return string
+ # will result in failure of the function. (deemed unlikely
+ # at the time of writing this function)
+ #Check for existing rules on current input
+ self.handle.sendline("")
+ self.handle.expect("\$")
+ self.handle.sendline("sudo iptables -C OUTPUT -p "+str(packet_type)+
+ " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+ i = self.handle.expect(["iptables:", "\$"])
+ print i
+ print self.handle.before
+ print "after: "
+ print self.handle.after
+
+ elif action_type == 'remove':
+ #Check for existing rules on current input
+ self.handle.sendline("")
+ self.handle.expect("\$")
+ self.handle.sendline("sudo iptables -C OUTPUT -p "+str(packet_type)+
+ " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+ self.handle.expect("\$")
+ print "before: "
+ print self.handle.before
+ actual_string = self.handle.after
+ expect_string = "iptables:"
+ print "Actual String:"
+ print actual_string
+
+ if re.search(expect_string, actual_string):
+ match_result = main.TRUE
+ else:
+ match_result = main.FALSE
+ #If match_result is main.TRUE, it means there is no matching rule.
+
+ #If tables does not exist and expected prompt is returned, go ahead and
+ #add iptables rule
+ if match_result == main.TRUE:
+ #Ensure action type is add
+ if action_type == 'add':
+ #-A is the 'append' action of iptables
+ action_add = '-A'
+ try:
+ self.handle.sendline("")
+ self.handle.sendline("sudo iptables "+action_add+" OUTPUT -p "+str(packet_type)+
+ " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+
+ info_string = "Rules added to "+str(self.name)
+ info_string += "iptable rule added to block IP: "+str(dst_ip)
+ info_string += "Port: "+str(dst_port)+" Rule: "+str(rule)
+
+ main.log.info(info_string)
+
+ self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+ except pexpect.TIMEOUT:
+ main.log.error(self.name + ": Timeout exception in setIpTables function")
+ except:
+ main.log.error( traceback.print_exc())
+ main.cleanup()
+ main.exit()
+ else:
+ main.log.error("Given rule already exists, but attempted to add it")
+ #If match_result is 0, it means there IS a matching rule provided
+ elif match_result == main.FALSE:
+ #Ensure action type is remove
+ if action_type == 'remove':
+ #-D is the 'delete' rule of iptables
+ action_remove = '-D'
+ try:
+ self.handle.sendline("")
+ #Delete a specific rule specified into the function
+ self.handle.sendline("sudo iptables "+action_remove+" OUTPUT -p "+str(packet_type)+
+ " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+
+ info_string = "Rules removed from "+str(self.name)
+ info_string += " iptables rule removed from blocking IP: "+str(dst_ip)
+ info_string += " Port: "+str(dst_port)+" Rule: "+str(rule)
+
+ main.log.info(info_string)
+
+ self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+ except pexpect.TIMEOUT:
+ main.log.error(self.name + ": Timeout exception in setIpTables function")
+ except:
+ main.log.error( traceback.print_exc())
+ main.cleanup()
+ main.exit()
+ else:
+ main.log.error("Given rule does not exist, but attempted to remove it")
+ else:
+ #NOTE: If a bad usage of this function occurs, exit the entire test
+ main.log.error("Bad rule given for iptables. Exiting...")
+ main.cleanup()
+ main.exit()
+
+
if __name__ != "__main__":
import sys
sys.modules[__name__] = RemoteMininetDriver()