blob: 3853888ce6c6c6d6edc0775f07a3063225aff598 [file] [log] [blame]
Rich Lane102d71d2013-10-04 14:09:34 -07001# Distributed under the OpenFlow Software License (see LICENSE)
2# Copyright (c) 2010 The Board of Trustees of The Leland Stanford Junior University
3# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
4"""
5Flow stats test cases
6
7These tests check the behavior of the flow stats request.
8"""
9
10import logging
Rich Lane43ffb102013-10-07 10:24:05 -070011import random
Rich Lane102d71d2013-10-04 14:09:34 -070012
13from oftest import config
14import oftest.base_tests as base_tests
15import ofp
16import oftest.packet as scapy
17
18from oftest.testutils import *
19from oftest.parse import parse_ipv6
20
21class AllFlowStats(base_tests.SimpleDataPlane):
22 """
23 Retrieve all flows and verify the stats entries match the flow-mods sent
24 """
25 def runTest(self):
26 port1, port2, port3 = openflow_ports(3)
Wilson Ng42df57a2013-10-28 17:54:57 -070027 table_id = test_param_get_table()
Rich Lane102d71d2013-10-04 14:09:34 -070028 delete_all_flows(self.controller)
29
30 flow1 = ofp.message.flow_add(
Wilson Ng42df57a2013-10-28 17:54:57 -070031 table_id=table_id,
Rich Lane102d71d2013-10-04 14:09:34 -070032 priority=0x11,
33 idle_timeout=0x21,
34 hard_timeout=0x31,
35 flags=ofp.OFPFF_NO_PKT_COUNTS,
36 cookie=1,
37 match=ofp.match([
38 ofp.oxm.in_port(port1),
39 ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|1)]),
40 instructions=[
41 ofp.instruction.write_actions(
42 actions=[
43 ofp.action.output(
44 port=port1,
45 max_len=ofp.OFPCML_NO_BUFFER)])],
46 buffer_id=ofp.OFP_NO_BUFFER)
47
48 flow2 = ofp.message.flow_add(
Wilson Ng42df57a2013-10-28 17:54:57 -070049 table_id=table_id,
Rich Lane102d71d2013-10-04 14:09:34 -070050 priority=0x12,
51 idle_timeout=0x22,
52 hard_timeout=0x32,
53 flags=ofp.OFPFF_NO_BYT_COUNTS,
54 cookie=2,
55 match=ofp.match([
56 ofp.oxm.in_port(port2),
57 ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|2)]),
58 instructions=[
59 ofp.instruction.write_actions(
60 actions=[
61 ofp.action.output(
62 port=port2,
63 max_len=ofp.OFPCML_NO_BUFFER)])],
64 buffer_id=ofp.OFP_NO_BUFFER)
65
66 flow3 = ofp.message.flow_add(
Wilson Ng42df57a2013-10-28 17:54:57 -070067 table_id=table_id,
Rich Lane102d71d2013-10-04 14:09:34 -070068 priority=0x13,
69 idle_timeout=0x23,
70 hard_timeout=0x33,
71 flags=ofp.OFPFF_CHECK_OVERLAP,
72 cookie=3,
73 match=ofp.match([
74 ofp.oxm.in_port(port3),
75 ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|3)]),
76 instructions=[
77 ofp.instruction.write_actions(
78 actions=[
79 ofp.action.output(
80 port=port3,
81 max_len=ofp.OFPCML_NO_BUFFER)])],
82 buffer_id=ofp.OFP_NO_BUFFER)
83
84 flows = [flow1, flow2, flow3]
85 for flow in flows:
86 logging.debug(flow.show())
87 self.controller.message_send(flow)
88
89 flows_by_cookie = { flow.cookie: flow for flow in flows }
90
91 do_barrier(self.controller)
92
93 logging.info("Sending flow stats request")
94 stats = get_flow_stats(self, ofp.match())
95 logging.info("Received %d flow stats entries", len(stats))
96
97 seen_cookies = set()
98 for entry in stats:
99 logging.debug(entry.show())
100 self.assertTrue(entry.cookie in flows_by_cookie, "Unexpected cookie")
101 self.assertTrue(entry.cookie not in seen_cookies, "Duplicate cookie")
102 flow = flows_by_cookie[entry.cookie]
103 seen_cookies.add(entry.cookie)
104
105 self.assertEqual(entry.table_id, flow.table_id)
106 self.assertEqual(entry.priority, flow.priority)
107 self.assertEqual(entry.idle_timeout, flow.idle_timeout)
108 self.assertEqual(entry.hard_timeout, flow.hard_timeout)
109 self.assertEqual(entry.flags, flow.flags)
110 self.assertEqual(entry.cookie, flow.cookie)
111 self.assertEqual(sorted(entry.match.oxm_list), sorted(flow.match.oxm_list))
112 self.assertEqual(sorted(entry.instructions), sorted(flow.instructions))
113
114 self.assertEqual(seen_cookies, set([1,2,3]))
Rich Laned15c6652013-10-04 14:42:26 -0700115
116class CookieFlowStats(base_tests.SimpleDataPlane):
117 """
118 Retrieve flows using various masks on the cookie
119 """
120 def runTest(self):
121 delete_all_flows(self.controller)
122
123 # Also used as masks
124 cookies = [
125 0x0000000000000000,
126 0xDDDDDDDD00000000,
127 0x00000000DDDDDDDD,
128 0xDDDDDDDDDDDDDDDD,
129 0xDDDD0000DDDD0000,
130 0x0000DDDD0000DDDD,
131 0xDD00DD00DD00DD00,
132 0xD0D0D0D0D0D0D0D0,
133 0xF000000000000000,
134 0xFF00000000000000,
135 0xFFF0000000000000,
136 0xFFFF000000000000,
137 ]
138
Rich Lane43ffb102013-10-07 10:24:05 -0700139 for i in range(0, 10):
140 cookies.append(random.getrandbits(64))
141
Rich Laned15c6652013-10-04 14:42:26 -0700142 # Generate the matching cookies for each combination of cookie and mask
143 matches = {}
Rich Lanef58cae22013-10-07 11:10:04 -0700144 for mask in cookies:
145 for cookie in cookies:
Rich Laned15c6652013-10-04 14:42:26 -0700146 matching = []
147 for cookie2 in cookies:
148 if cookie & mask == cookie2 & mask:
149 matching.append(cookie2)
150 matches[(cookie, mask)] = sorted(matching)
151
152 # Generate a flow for each cookie
153 flows = {}
154 for idx, cookie in enumerate(cookies):
155 flows[cookie] = ofp.message.flow_add(
Wilson Ng42df57a2013-10-28 17:54:57 -0700156 table_id=test_param_get_table(),
Rich Laned15c6652013-10-04 14:42:26 -0700157 cookie=cookie,
158 match=ofp.match([ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|idx)]),
159 buffer_id=ofp.OFP_NO_BUFFER)
160
161 # Install flows
162 for flow in flows.values():
163 self.controller.message_send(flow)
164 do_barrier(self.controller)
165
166 # For each combination of cookie and match, verify the correct flows
167 # are retrieved
Rich Lane316204b2013-10-07 11:08:03 -0700168 for (cookie, mask), expected_cookies in matches.iteritems():
Rich Laned15c6652013-10-04 14:42:26 -0700169 stats = get_flow_stats(self, ofp.match(), cookie=cookie, cookie_mask=mask)
170 received_cookies = sorted([entry.cookie for entry in stats])
171 logging.debug("expected 0x%016x/0x%016x: %s", cookie, mask,
172 ' '.join(["0x%016x" % x for x in expected_cookies]))
173 logging.debug("received 0x%016x/0x%016x: %s", cookie, mask,
174 ' '.join(["0x%016x" % x for x in received_cookies]))
175 self.assertEqual(expected_cookies, received_cookies)