Added basic table stats get test
diff --git a/tests/basic.py b/tests/basic.py
index 8296be3..0e91ad5 100644
--- a/tests/basic.py
+++ b/tests/basic.py
@@ -250,6 +250,27 @@
self.assertTrue(response is not None, "Did not get response")
basic_logger.debug(response.show())
+class TableStatsGet(SimpleProtocol):
+ """
+ Get table stats
+
+ Simply verify table stats get transaction
+ """
+ def runTest(self):
+ basic_logger.info("Running TableStatsGet")
+ basic_logger.info("Inserting trial flow")
+ request = message.flow_mod()
+ request.match.wildcards = ofp.OFPFW_ALL
+ request.buffer_id = 0xffffffff
+ rv = self.controller.message_send(request)
+ self.assertTrue(rv != -1, "Failed to insert test flow")
+
+ basic_logger.info("Sending table stats request")
+ request = message.table_stats_request()
+ response, pkt = self.controller.transact(request, timeout=2)
+ self.assertTrue(response is not None, "Did not get response")
+ basic_logger.debug(response.show())
+
class FlowMod(SimpleProtocol):
"""
Insert a flow
diff --git a/tests/caps.py b/tests/caps.py
new file mode 100644
index 0000000..1146cf1
--- /dev/null
+++ b/tests/caps.py
@@ -0,0 +1,158 @@
+"""
+Basic capabilities and capacities tests
+
+"""
+
+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 caps_port_map Local copy of the configuration map from OF port
+# numbers to OS interfaces
+caps_port_map = None
+#@var caps_logger Local logger object
+caps_logger = None
+#@var caps_config Local copy of global configuration data
+caps_config = None
+
+def test_set_init(config):
+ """
+ Set up function for caps test classes
+
+ @param config The configuration dictionary; see oft
+ """
+
+ global caps_port_map
+ global caps_logger
+ global caps_config
+
+ caps_logger = logging.getLogger("caps")
+ caps_logger.info("Initializing caps test set")
+ caps_port_map = config["port_map"]
+ caps_config = config
+
+
+def flow_caps_common(obj, is_exact=True):
+ """
+ The common function for
+
+ @param obj The calling object
+ @param is_exact If True, checking exact match; else wildcard
+ """
+
+ global caps_port_map
+ of_ports = caps_port_map.keys()
+ of_ports.sort()
+
+ rv = delete_all_flows(obj.controller, caps_logger)
+ obj.assertEqual(rv, 0, "Failed to delete all flows")
+
+ pkt = simple_tcp_packet()
+ match = parse.packet_to_flow_match(pkt)
+ obj.assertTrue(match is not None, "Could not generate flow match from pkt")
+ for port in of_ports:
+ break;
+ match.in_port = port
+ match.nw_src = 1
+ request = message.flow_mod()
+ count_check = 101 # fixme: better way to determine this.
+ if is_exact:
+ match.wildcards = 0
+ else:
+ match.wildcards |= ofp.OFPFW_DL_SRC
+
+ request.match = match
+ caps_logger.info(request.show())
+
+ tstats = message.table_stats_request()
+ try: # Determine the table index to check (or "all")
+ table_idx = caps_config["caps_table_idx"]
+ except:
+ table_idx = -1 # Accumulate all table counts
+
+ # Make sure we can install at least one flow
+ caps_logger.info("Inserting initial flow")
+ rv = obj.controller.message_send(request)
+ obj.assertTrue(rv != -1, "Error installing flow mod")
+ do_barrier(obj.controller)
+ flow_count = 1
+
+ caps_logger.info("Table idx: " + str(table_idx))
+ caps_logger.info("Check every " + str(count_check) + " inserts")
+
+ while True:
+ request.match.nw_src += 1
+ rv = obj.controller.message_send(request)
+ do_barrier(obj.controller)
+ flow_count += 1
+ if flow_count % count_check == 0:
+ response, pkt = obj.controller.transact(tstats, timeout=2)
+ obj.assertTrue(response is not None, "Get tab stats failed")
+ caps_logger.info(response.show())
+ if table_idx == -1: # Accumulate for all tables
+ active_flows = 0
+ for stats in response.stats:
+ active_flows += stats.active_count
+ else: # Table index to use specified in config
+ active_flows = response.stats[table_idx].active_count
+ if active_flows != flow_count:
+ break
+
+ caps_logger.error("RESULT: " + str(flow_count) + " flows inserted")
+ caps_logger.error("RESULT: " + str(active_flows) + " flows reported")
+
+
+class FillTableExact(basic.SimpleProtocol):
+ """
+ Fill the flow table with exact matches
+
+ Fill table until no more flows can be added. Report result.
+ Increment the source IP address. Assume the flow table will
+ fill in less than 4 billion inserts
+
+ To check the number of flows in the tables is expensive, so
+ it's only done periodically. This is controlled by the
+ count_check variable.
+
+ A switch may have multiple tables. The default behaviour
+ is to count all the flows in all the tables. By setting
+ the parameter "caps_table_idx" in the configuration array,
+ you can control which table to check.
+ """
+ def runTest(self):
+ caps_logger.info("Running " + str(self))
+ flow_caps_common(self)
+
+
+class FillTableWC(basic.SimpleProtocol):
+ """
+ Fill the flow table with wildcard matches
+
+ Fill table using wildcard entries until no more flows can be
+ added. Report result.
+ Increment the source IP address. Assume the flow table will
+ fill in less than 4 billion inserts
+
+ To check the number of flows in the tables is expensive, so
+ it's only done periodically. This is controlled by the
+ count_check variable.
+
+ A switch may have multiple tables. The default behaviour
+ is to count all the flows in all the tables. By setting
+ the parameter "caps_table_idx" in the configuration array,
+ you can control which table to check.
+
+ """
+ def runTest(self):
+ caps_logger.info("Running " + str(self))
+ flow_caps_common(self, is_exact=False)