Merge into master from pull request #73:
oft: change default port to 6653 (https://github.com/floodlight/oftest/pull/73)
diff --git a/src/python/oftest/controller.py b/src/python/oftest/controller.py
index 4feb99e..3bfbcb3 100644
--- a/src/python/oftest/controller.py
+++ b/src/python/oftest/controller.py
@@ -103,6 +103,7 @@
self.switch_addr = None
self.connect_cv = Condition()
self.message_cv = Condition()
+ self.tx_lock = Lock()
# Used to wake up the event loop from another thread
self.waker = ofutils.EventDescriptor()
@@ -693,8 +694,10 @@
msg_len,
msg_version,
msg_xid)
- if self.switch_socket.sendall(outpkt) is not None:
- raise AssertionError("failed to send message to switch")
+
+ with self.tx_lock:
+ if self.switch_socket.sendall(outpkt) is not None:
+ raise AssertionError("failed to send message to switch")
return 0 # for backwards compatibility
diff --git a/tests-1.3/flow_stats.py b/tests-1.3/flow_stats.py
new file mode 100644
index 0000000..4a82a89
--- /dev/null
+++ b/tests-1.3/flow_stats.py
@@ -0,0 +1,174 @@
+# Distributed under the OpenFlow Software License (see LICENSE)
+# Copyright (c) 2010 The Board of Trustees of The Leland Stanford Junior University
+# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
+"""
+Flow stats test cases
+
+These tests check the behavior of the flow stats request.
+"""
+
+import logging
+import random
+
+from oftest import config
+import oftest.base_tests as base_tests
+import ofp
+import oftest.packet as scapy
+
+from oftest.testutils import *
+from oftest.parse import parse_ipv6
+
+class AllFlowStats(base_tests.SimpleDataPlane):
+ """
+ Retrieve all flows and verify the stats entries match the flow-mods sent
+ """
+ def runTest(self):
+ port1, port2, port3 = openflow_ports(3)
+ delete_all_flows(self.controller)
+
+ flow1 = ofp.message.flow_add(
+ table_id=0,
+ priority=0x11,
+ idle_timeout=0x21,
+ hard_timeout=0x31,
+ flags=ofp.OFPFF_NO_PKT_COUNTS,
+ cookie=1,
+ match=ofp.match([
+ ofp.oxm.in_port(port1),
+ ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|1)]),
+ instructions=[
+ ofp.instruction.write_actions(
+ actions=[
+ ofp.action.output(
+ port=port1,
+ max_len=ofp.OFPCML_NO_BUFFER)])],
+ buffer_id=ofp.OFP_NO_BUFFER)
+
+ flow2 = ofp.message.flow_add(
+ table_id=0,
+ priority=0x12,
+ idle_timeout=0x22,
+ hard_timeout=0x32,
+ flags=ofp.OFPFF_NO_BYT_COUNTS,
+ cookie=2,
+ match=ofp.match([
+ ofp.oxm.in_port(port2),
+ ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|2)]),
+ instructions=[
+ ofp.instruction.write_actions(
+ actions=[
+ ofp.action.output(
+ port=port2,
+ max_len=ofp.OFPCML_NO_BUFFER)])],
+ buffer_id=ofp.OFP_NO_BUFFER)
+
+ flow3 = ofp.message.flow_add(
+ table_id=0,
+ priority=0x13,
+ idle_timeout=0x23,
+ hard_timeout=0x33,
+ flags=ofp.OFPFF_CHECK_OVERLAP,
+ cookie=3,
+ match=ofp.match([
+ ofp.oxm.in_port(port3),
+ ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|3)]),
+ instructions=[
+ ofp.instruction.write_actions(
+ actions=[
+ ofp.action.output(
+ port=port3,
+ max_len=ofp.OFPCML_NO_BUFFER)])],
+ buffer_id=ofp.OFP_NO_BUFFER)
+
+ flows = [flow1, flow2, flow3]
+ for flow in flows:
+ logging.debug(flow.show())
+ self.controller.message_send(flow)
+
+ flows_by_cookie = { flow.cookie: flow for flow in flows }
+
+ do_barrier(self.controller)
+
+ logging.info("Sending flow stats request")
+ stats = get_flow_stats(self, ofp.match())
+ logging.info("Received %d flow stats entries", len(stats))
+
+ seen_cookies = set()
+ for entry in stats:
+ logging.debug(entry.show())
+ self.assertTrue(entry.cookie in flows_by_cookie, "Unexpected cookie")
+ self.assertTrue(entry.cookie not in seen_cookies, "Duplicate cookie")
+ flow = flows_by_cookie[entry.cookie]
+ seen_cookies.add(entry.cookie)
+
+ self.assertEqual(entry.table_id, flow.table_id)
+ self.assertEqual(entry.priority, flow.priority)
+ self.assertEqual(entry.idle_timeout, flow.idle_timeout)
+ self.assertEqual(entry.hard_timeout, flow.hard_timeout)
+ self.assertEqual(entry.flags, flow.flags)
+ self.assertEqual(entry.cookie, flow.cookie)
+ self.assertEqual(sorted(entry.match.oxm_list), sorted(flow.match.oxm_list))
+ self.assertEqual(sorted(entry.instructions), sorted(flow.instructions))
+
+ self.assertEqual(seen_cookies, set([1,2,3]))
+
+class CookieFlowStats(base_tests.SimpleDataPlane):
+ """
+ Retrieve flows using various masks on the cookie
+ """
+ def runTest(self):
+ delete_all_flows(self.controller)
+
+ # Also used as masks
+ cookies = [
+ 0x0000000000000000,
+ 0xDDDDDDDD00000000,
+ 0x00000000DDDDDDDD,
+ 0xDDDDDDDDDDDDDDDD,
+ 0xDDDD0000DDDD0000,
+ 0x0000DDDD0000DDDD,
+ 0xDD00DD00DD00DD00,
+ 0xD0D0D0D0D0D0D0D0,
+ 0xF000000000000000,
+ 0xFF00000000000000,
+ 0xFFF0000000000000,
+ 0xFFFF000000000000,
+ ]
+
+ for i in range(0, 10):
+ cookies.append(random.getrandbits(64))
+
+ # Generate the matching cookies for each combination of cookie and mask
+ matches = {}
+ for mask in cookies:
+ for cookie in cookies:
+ matching = []
+ for cookie2 in cookies:
+ if cookie & mask == cookie2 & mask:
+ matching.append(cookie2)
+ matches[(cookie, mask)] = sorted(matching)
+
+ # Generate a flow for each cookie
+ flows = {}
+ for idx, cookie in enumerate(cookies):
+ flows[cookie] = ofp.message.flow_add(
+ table_id=0,
+ cookie=cookie,
+ match=ofp.match([ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|idx)]),
+ buffer_id=ofp.OFP_NO_BUFFER)
+
+ # Install flows
+ for flow in flows.values():
+ self.controller.message_send(flow)
+ do_barrier(self.controller)
+
+ # For each combination of cookie and match, verify the correct flows
+ # are retrieved
+ for (cookie, mask), expected_cookies in matches.iteritems():
+ stats = get_flow_stats(self, ofp.match(), cookie=cookie, cookie_mask=mask)
+ received_cookies = sorted([entry.cookie for entry in stats])
+ logging.debug("expected 0x%016x/0x%016x: %s", cookie, mask,
+ ' '.join(["0x%016x" % x for x in expected_cookies]))
+ logging.debug("received 0x%016x/0x%016x: %s", cookie, mask,
+ ' '.join(["0x%016x" % x for x in received_cookies]))
+ self.assertEqual(expected_cookies, received_cookies)