blob: 535eea10477e7519c393dbe17cfac9ab83eac784 [file] [log] [blame]
"""
Test cases for testing actions taken on packets
See basic.py for other info.
It is recommended that these definitions be kept in their own
namespace as different groups of tests will likely define
similar identifiers.
The function test_set_init is called with a complete configuration
dictionary prior to the invocation of any tests from this file.
The switch is actively attempting to contact the controller at the address
indicated oin oft_config
"""
import copy
import logging
import unittest
import oftest.controller as controller
import oftest.cstruct as ofp
import oftest.message as message
import oftest.dataplane as dataplane
import oftest.action as action
import oftest.parse as parse
import basic
from testutils import *
#@var port_map Local copy of the configuration map from OF port
# numbers to OS interfaces
pa_port_map = None
#@var pa_logger Local logger object
pa_logger = None
#@var pa_config Local copy of global configuration data
pa_config = None
def test_set_init(config):
"""
Set up function for packet action test classes
@param config The configuration dictionary; see oft
"""
global pa_port_map
global pa_logger
global pa_config
pa_logger = logging.getLogger("pkt_act")
pa_logger.info("Initializing test set")
pa_port_map = config["port_map"]
pa_config = config
class DirectPacket(basic.SimpleDataPlane):
"""
Send packet to single egress port
Generate a packet
Generate and install a matching flow
Add action to direct the packet to an egress port
Send the packet to ingress dataplane port
Verify the packet is received at the egress port only
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for idx in range(len(of_ports)):
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
egress_port = of_ports[(idx + 1) % len(of_ports)]
pa_logger.info("Ingress " + str(ingress_port) +
" to egress " + str(egress_port))
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
act.port = egress_port
self.assertTrue(request.actions.add(act), "Could not add action")
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " +
str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
(rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(timeout=1)
self.assertTrue(rcv_pkt is not None, "Did not receive packet")
pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
str(rcv_port))
self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
self.assertEqual(str(pkt), str(rcv_pkt),
'Response packet does not match send packet')
class DirectTwoPorts(basic.SimpleDataPlane):
"""
Send packet to two egress ports
Generate a packet
Generate and install a matching flow
Add action to direct the packet to two egress ports
Send the packet to ingress dataplane port
Verify the packet is received at the two egress ports
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for idx in range(len(of_ports)):
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
egress_port1 = of_ports[(idx + 1) % len(of_ports)]
egress_port2 = of_ports[(idx + 2) % len(of_ports)]
pa_logger.info("Ingress " + str(ingress_port) +
" to egress " + str(egress_port1) + " and " +
str(egress_port2))
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
act.port = egress_port1
self.assertTrue(request.actions.add(act), "Could not add action1")
act.port = egress_port2
self.assertTrue(request.actions.add(act), "Could not add action2")
# pa_logger.info(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " +
str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
yes_ports = set([egress_port1, egress_port2])
no_ports = set(of_ports).difference(yes_ports)
receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
self, pa_logger)
class DirectMCNonIngress(basic.SimpleDataPlane):
"""
Multicast to all non-ingress ports
Generate a packet
Generate and install a matching flow
Add action to direct the packet to all non-ingress ports
Send the packet to ingress dataplane port
Verify the packet is received at all non-ingress ports
Does not use the flood action
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for ingress_port in of_ports:
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
pa_logger.info("Ingress " + str(ingress_port) +
" all non-ingress ports")
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
for egress_port in of_ports:
if egress_port == ingress_port:
continue
act.port = egress_port
self.assertTrue(request.actions.add(act),
"Could not add output to " + str(egress_port))
pa_logger.debug(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " + str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
yes_ports = set(of_ports).difference([ingress_port])
receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
self, pa_logger)
class DirectMC(basic.SimpleDataPlane):
"""
Multicast to all ports including ingress
Generate a packet
Generate and install a matching flow
Add action to direct the packet to all non-ingress ports
Send the packet to ingress dataplane port
Verify the packet is received at all ports
Does not use the flood action
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for ingress_port in of_ports:
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
for egress_port in of_ports:
if egress_port == ingress_port:
act.port = ofp.OFPP_IN_PORT
else:
act.port = egress_port
self.assertTrue(request.actions.add(act),
"Could not add output to " + str(egress_port))
# pa_logger.info(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " + str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
pa_logger)
class Flood(basic.SimpleDataPlane):
"""
Flood to all ports except ingress
Generate a packet
Generate and install a matching flow
Add action to flood the packet
Send the packet to ingress dataplane port
Verify the packet is received at all other ports
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for ingress_port in of_ports:
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
act.port = ofp.OFPP_FLOOD
self.assertTrue(request.actions.add(act),
"Could not add flood port action")
pa_logger.info(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " + str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
yes_ports = set(of_ports).difference([ingress_port])
receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
self, pa_logger)
class FloodPlusIngress(basic.SimpleDataPlane):
"""
Flood to all ports plus send to ingress port
Generate a packet
Generate and install a matching flow
Add action to flood the packet
Add action to send to ingress port
Send the packet to ingress dataplane port
Verify the packet is received at all other ports
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for ingress_port in of_ports:
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
act.port = ofp.OFPP_FLOOD
self.assertTrue(request.actions.add(act),
"Could not add flood port action")
act.port = ofp.OFPP_IN_PORT
self.assertTrue(request.actions.add(act),
"Could not add ingress port for output")
pa_logger.info(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " + str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
pa_logger)
class All(basic.SimpleDataPlane):
"""
Send to OFPP_ALL port
Generate a packet
Generate and install a matching flow
Add action to forward to OFPP_ALL
Send the packet to ingress dataplane port
Verify the packet is received at all other ports
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for ingress_port in of_ports:
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
act.port = ofp.OFPP_ALL
self.assertTrue(request.actions.add(act),
"Could not add ALL port action")
pa_logger.info(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " + str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
yes_ports = set(of_ports).difference([ingress_port])
receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
self, pa_logger)
class AllPlusIngress(basic.SimpleDataPlane):
"""
Send to OFPP_ALL port and ingress port
Generate a packet
Generate and install a matching flow
Add action to forward to OFPP_ALL
Add action to forward to ingress port
Send the packet to ingress dataplane port
Verify the packet is received at all other ports
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for ingress_port in of_ports:
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
act.port = ofp.OFPP_ALL
self.assertTrue(request.actions.add(act),
"Could not add ALL port action")
act.port = ofp.OFPP_IN_PORT
self.assertTrue(request.actions.add(act),
"Could not add ingress port for output")
pa_logger.info(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " + str(ingress_port))
self.dataplane.send(ingress_port, str(pkt))
receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
pa_logger)
class FloodMinusPort(basic.SimpleDataPlane):
"""
Config port with No_Flood and test Flood action
Generate a packet
Generate a matching flow
Add action to forward to OFPP_ALL
Set port to no-flood
Send the packet to ingress dataplane port
Verify the packet is received at all other ports except
the ingress port and the no_flood port
"""
def runTest(self):
global pa_port_map
of_ports = pa_port_map.keys()
of_ports.sort()
self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
pkt = simple_tcp_packet()
match = parse.packet_to_flow_match(pkt)
match.wildcards &= ~ofp.OFPFW_IN_PORT
self.assertTrue(match is not None,
"Could not generate flow match from pkt")
act = action.action_output()
for idx in range(len(of_ports)):
rv = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rv, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
no_flood_idx = (idx + 1) % len(of_ports)
no_flood_port = of_ports[no_flood_idx]
rv = port_config_set(self.controller, no_flood_port,
ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD,
pa_logger)
self.assertEqual(rv, 0, "Failed to set port config")
match.in_port = ingress_port
request = message.flow_mod()
request.match = match
request.buffer_id = 0xffffffff
act.port = ofp.OFPP_FLOOD
self.assertTrue(request.actions.add(act),
"Could not add flood port action")
pa_logger.info(request.show())
pa_logger.info("Inserting flow")
rv = self.controller.message_send(request)
self.assertTrue(rv != -1, "Error installing flow mod")
do_barrier(self.controller)
pa_logger.info("Sending packet to dp port " + str(ingress_port))
pa_logger.info("No flood port is " + str(no_flood_port))
self.dataplane.send(ingress_port, str(pkt))
no_ports = set([ingress_port, no_flood_port])
yes_ports = set(of_ports).difference(no_ports)
receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self,
pa_logger)
# Turn no flood off again
rv = port_config_set(self.controller, no_flood_port,
0, ofp.OFPPC_NO_FLOOD, pa_logger)
self.assertEqual(rv, 0, "Failed to reset port config")
#@todo Should check no other packets received
if __name__ == "__main__":
print "Please run through oft script: ./oft --test_spec=basic"