Merge branch 'master' of github.com:/floodlight/oftest
diff --git a/tests/basic.py b/tests/basic.py
index bbbf186..bf5798e 100644
--- a/tests/basic.py
+++ b/tests/basic.py
@@ -21,6 +21,7 @@
 import logging
 
 import unittest
+import random
 
 import oftest.controller as controller
 import oftest.cstruct as ofp
@@ -325,6 +326,49 @@
                self.assertEqual(str(outpkt), str(pkt)[:len(str(outpkt))],
                                 'Response packet does not match send packet')
 
+class PacketOutMC(SimpleDataPlane):
+    """
+    Test packet out to multiple output ports
+
+    Send packet out message to controller for 1 to N dataplane ports and
+    verify the packet appears on the appropriate ports
+    """
+    def runTest(self):
+        # Construct packet to send to dataplane
+        # Send packet to dataplane
+        # Poll controller with expect message type packet in
+
+        rc = delete_all_flows(self.controller, basic_logger)
+        self.assertEqual(rc, 0, "Failed to delete all flows")
+
+        # These will get put into function
+        of_ports = basic_port_map.keys()
+        random.shuffle(of_ports)
+        for num_ports in range(1,len(of_ports)+1):
+            for outpkt, opt in [
+               (simple_tcp_packet(), "simple TCP packet"),
+               (simple_eth_packet(), "simple Ethernet packet"),
+               (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
+
+               dp_ports = of_ports[0:num_ports]
+               basic_logger.info("PKT OUT test with " + opt +
+                                 ", ports " + str(dp_ports))
+               msg = message.packet_out()
+               msg.data = str(outpkt)
+               act = action.action_output()
+               for i in range(0,num_ports):
+                  act.port = dp_ports[i]
+                  self.assertTrue(msg.actions.add(act),
+                                  'Could not add action to msg')
+
+               basic_logger.info("PacketOut to: " + str(dp_ports))
+               rv = self.controller.message_send(msg)
+               self.assertTrue(rv == 0, "Error sending out message")
+
+               receive_pkt_check(self.dataplane, outpkt, dp_ports,
+                                 set(of_ports).difference(dp_ports),
+                                 self, basic_logger, basic_config)
+
 class FlowStatsGet(SimpleProtocol):
     """
     Get stats 
diff --git a/tests/testutils.py b/tests/testutils.py
index 0380ade..f1459bf 100644
--- a/tests/testutils.py
+++ b/tests/testutils.py
@@ -224,11 +224,11 @@
     rv = controller.message_send(mod)
     return rv
 
-def receive_pkt_check(dataplane, pkt, yes_ports, no_ports, assert_if, logger,
+def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if, logger,
                       config):
     """
     Check for proper receive packets across all ports
-    @param dataplane The dataplane object
+    @param dp The dataplane object
     @param pkt Expected packet; may be None if yes_ports is empty
     @param yes_ports Set or list of ports that should recieve packet
     @param no_ports Set or list of ports that should not receive packet
@@ -240,17 +240,20 @@
 
     for ofport in yes_ports:
         logger.debug("Checking for pkt on port " + str(ofport))
-        (rcv_port, rcv_pkt, pkt_time) = dataplane.poll(
+        (rcv_port, rcv_pkt, pkt_time) = dp.poll(
             port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
         assert_if.assertTrue(rcv_pkt is not None, 
                              "Did not receive pkt on " + str(ofport))
-        assert_if.assertEqual(str(pkt), str(rcv_pkt),
-                              "Response packet does not match send packet " +
-                              "on port " + str(ofport))
+        if not dataplane.match_exp_pkt(pkt, rcv_pkt):
+            logger.debug("Sent %s" % format_packet(pkt))
+            logger.debug("Resp %s" % format_packet(rcv_pkt))
+        assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
+                             "Response packet does not match send packet " +
+                             "on port " + str(ofport))
 
     for ofport in no_ports:
         logger.debug("Negative check for pkt on port " + str(ofport))
-        (rcv_port, rcv_pkt, pkt_time) = dataplane.poll(
+        (rcv_port, rcv_pkt, pkt_time) = dp.poll(
             port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
         assert_if.assertTrue(rcv_pkt is None, 
                              "Unexpected pkt on port " + str(ofport))