blob: 1bedd29938d7a901ea1691673d7421f1aaaed7b9 [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 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)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 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)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 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))
(rcv_port1, rcv_pkt1, pkt_time1) = self.dataplane.poll(timeout=1)
(rcv_port2, rcv_pkt2, pkt_time2) = self.dataplane.poll(timeout=1)
self.assertTrue(rcv_pkt1 is not None, "Did not receive packet 1")
self.assertTrue(rcv_pkt2 is not None, "Did not receive packet 2")
pa_logger.debug("Packet len " + str(len(rcv_pkt1)) + " in on " +
str(rcv_port1))
pa_logger.debug("Packet len " + str(len(rcv_pkt2)) + " in on " +
str(rcv_port2))
# Check if ports swapped
if (rcv_port1 == egress_port2 and rcv_port2 == egress_port1):
(rcv_port2, rcv_port1) = (rcv_port1, rcv_port2)
(rcv_pkt2, rcv_pkt1) = (rcv_pkt1, rcv_pkt2)
self.assertEqual(rcv_port1, egress_port1,
"Unexpected receive port 1")
self.assertEqual(rcv_port2, egress_port2,
"Unexpected receive port 2")
self.assertEqual(str(pkt), str(rcv_pkt1),
'Response packet does not match send packet 1')
self.assertEqual(str(pkt), str(rcv_pkt2),
'Response packet does not match send packet 2')
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 idx in range(len(of_ports)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
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 egr_idx in range(len(of_ports)):
if egr_idx == idx:
continue
egress_port = of_ports[egr_idx]
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))
for egr_idx in range(len(of_ports)):
if egr_idx == idx:
continue
ofport = of_ports[egr_idx]
(rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
port_number=ofport, timeout=1)
self.assertTrue(rcv_pkt is not None,
"Did not receive packet port " + str(ofport))
pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
+ str(rcv_port))
self.assertEqual(str(pkt), str(rcv_pkt),
'Response packet does not match send packet ' +
"on port " + str(ofport))
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 idx in range(len(of_ports)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
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 egr_idx in range(len(of_ports)):
egress_port = of_ports[egr_idx]
if egr_idx == idx:
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))
for egr_idx in range(len(of_ports)):
ofport = of_ports[egr_idx]
(rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
port_number=ofport, timeout=1)
self.assertTrue(rcv_pkt is not None,
"Did not receive packet port " + str(ofport))
pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
+ str(rcv_port))
self.assertEqual(str(pkt), str(rcv_pkt),
'Response packet does not match send packet ' +
"on port " + str(ofport))
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 idx in range(len(of_ports)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
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))
for egr_idx in range(len(of_ports)):
if egr_idx == idx:
continue
ofport = of_ports[egr_idx]
(rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
port_number=ofport, timeout=1)
self.assertTrue(rcv_pkt is not None,
"Did not receive packet port " + str(ofport))
pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
+ str(rcv_port))
self.assertEqual(str(pkt), str(rcv_pkt),
'Response packet does not match send packet ' +
"on port " + str(ofport))
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 idx in range(len(of_ports)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
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))
for egr_idx in range(len(of_ports)):
ofport = of_ports[egr_idx]
(rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
port_number=ofport, timeout=1)
self.assertTrue(rcv_pkt is not None,
"Did not receive packet port " + str(ofport))
pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
+ str(rcv_port))
self.assertEqual(str(pkt), str(rcv_pkt),
'Response packet does not match send packet ' +
"on port " + str(ofport))
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 idx in range(len(of_ports)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
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))
for egr_idx in range(len(of_ports)):
if egr_idx == idx:
continue
ofport = of_ports[egr_idx]
(rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
port_number=ofport, timeout=1)
self.assertTrue(rcv_pkt is not None,
"Did not receive packet port " + str(ofport))
pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
+ str(rcv_port))
self.assertEqual(str(pkt), str(rcv_pkt),
'Response packet does not match send packet ' +
"on port " + str(ofport))
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 idx in range(len(of_ports)):
rc = delete_all_flows(self.controller, pa_logger)
self.assertEqual(rc, 0, "Failed to delete all flows")
ingress_port = of_ports[idx]
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))
for egr_idx in range(len(of_ports)):
ofport = of_ports[egr_idx]
(rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
port_number=ofport, timeout=1)
self.assertTrue(rcv_pkt is not None,
"Did not receive packet port " + str(ofport))
pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
+ str(rcv_port))
self.assertEqual(str(pkt), str(rcv_pkt),
'Response packet does not match send packet ' +
"on port " + str(ofport))