blob: dc44f79de7051316b3463633f7e61a90240f7149 [file] [log] [blame]
Rich Lane207599b2014-03-06 14:24:16 -08001# Distributed under the OpenFlow Software License (see LICENSE)
2# Copyright (c) 2014 Big Switch Networks, Inc.
3"""
4BSN flow checksum extension test cases
5"""
6
7import logging
8import math
9import random
10
11from oftest import config
12import oftest.base_tests as base_tests
13import ofp
14
15from oftest.testutils import *
16
17TABLE_ID = 0
18
19def make_checksum(hi, lo):
20 """
21 Place 'hi' in the upper 8 bits and 'lo' in the lower bits.
22 """
23 return ((hi & 0xff) << 56) | lo
24
25assert make_checksum(0xab, 0xcd) == 0xab000000000000cd
26
27class FlowChecksumBase(base_tests.SimpleProtocol):
28 """
29 Base class that maintains the expected table and bucket checksums
30 """
31 checksum_buckets = None
32 table_checksum = None
33 all_checksums = []
34
35 def get_table_checksum(self):
36 for entry in get_stats(self, ofp.message.bsn_table_checksum_stats_request()):
37 if entry.table_id == TABLE_ID:
38 return entry.checksum
39 return None
40
41 def get_checksum_buckets(self):
42 stats = get_stats(self,
43 ofp.message.bsn_flow_checksum_bucket_stats_request(table_id=TABLE_ID))
44 return [x.checksum for x in stats]
45
46 def verify_checksums(self):
47 self.assertEquals(self.get_table_checksum(), self.table_checksum)
48 self.assertEquals(self.get_checksum_buckets(), self.checksum_buckets)
49
50 def update_checksums(self, checksum):
51 self.table_checksum ^= checksum
52 checksum_shift = 64 - int(math.log(len(self.checksum_buckets), 2))
53 self.checksum_buckets[checksum >> checksum_shift] ^= checksum
54
55 def insert_checksum(self, checksum):
56 self.update_checksums(checksum)
57 self.all_checksums.append(checksum)
58
59 def remove_checksum(self, checksum):
60 self.update_checksums(checksum)
61 self.all_checksums.remove(checksum)
62
63 def set_buckets_size(self, buckets_size):
64 self.controller.message_send(
65 ofp.message.bsn_table_set_buckets_size(
66 table_id=TABLE_ID, buckets_size=buckets_size))
67 do_barrier(self.controller)
68 verify_no_errors(self.controller)
69
70 self.checksum_buckets = [0] * buckets_size
71 self.table_checksum = 0
72 for checksum in self.all_checksums:
73 self.update_checksums(checksum)
74
75class FlowChecksum(FlowChecksumBase):
76 """
77 Test flow checksum buckets and table checksums
78 """
79 def runTest(self):
80 delete_all_flows(self.controller)
81
82 # Deleted all flows, table checksum should be 0
83 self.assertEquals(self.get_table_checksum(), 0)
84
85 self.set_buckets_size(8)
86 self.verify_checksums()
87
88 # Interesting checksums
89 checksums = [
90 make_checksum(0, 1),
91 make_checksum(0, 2),
92 make_checksum(1, 0xab),
93 make_checksum(1, 0xab),
94 make_checksum(7, 0xff),
95 make_checksum(7, 0xaa),
96 ]
97
98 # Random checksums
99 for _ in xrange(0, 8):
100 checksums.append(random.randint(0, 2**64-1))
101
102 # Add flows in random order
103 random.shuffle(checksums)
104 for i, checksum in enumerate(checksums):
105 self.insert_checksum(checksum)
106 request = ofp.message.flow_add(
107 table_id=TABLE_ID,
108 cookie=checksum,
109 buffer_id=ofp.OFP_NO_BUFFER,
110 priority=i)
111 self.controller.message_send(request)
112 do_barrier(self.controller)
113 verify_no_errors(self.controller)
114 self.verify_checksums()
115
116 # Delete flows in random order
117 random.shuffle(checksums)
118 for i, checksum in enumerate(checksums):
119 self.remove_checksum(checksum)
120 request = ofp.message.flow_delete_strict(
121 table_id=TABLE_ID,
122 priority=i,
123 out_port=ofp.OFPP_ANY,
124 out_group=ofp.OFPG_ANY)
125 self.controller.message_send(request)
126 do_barrier(self.controller)
127 verify_no_errors(self.controller)
128 self.verify_checksums()
129
130 # Deleted all flows, table checksum should be 0
131 self.assertEquals(self.get_table_checksum(), 0)
132
133class Resize(FlowChecksumBase):
134 """
135 Resize the checksum buckets, checking limits and redistribution
136 """
137 def runTest(self):
138 delete_all_flows(self.controller)
139
140 self.assertEquals(self.get_table_checksum(), 0)
141
142 self.set_buckets_size(128)
143 self.verify_checksums()
144
145 checksums = [random.randint(0, 2**64-1) for _ in xrange(0, 128)]
146
147 # Add flows
148 for i, checksum in enumerate(checksums):
149 self.insert_checksum(checksum)
150 request = ofp.message.flow_add(
151 table_id=TABLE_ID,
152 cookie=checksum,
153 buffer_id=ofp.OFP_NO_BUFFER,
154 priority=i)
155 self.controller.message_send(request)
156 do_barrier(self.controller)
157 verify_no_errors(self.controller)
158 self.verify_checksums()
159
160 # Shrink checksum buckets
161 self.set_buckets_size(64)
162 self.verify_checksums()
163
164 # Shrink checksum buckets to minimum
165 self.set_buckets_size(1)
166 self.verify_checksums()
167
168 # Grow checksum buckets
169 self.set_buckets_size(2)
170 self.verify_checksums()
171
172 # Grow checksum buckets
173 self.set_buckets_size(256)
174 self.verify_checksums()
175
176 # Grow checksum buckets to maximum
177 self.set_buckets_size(65536)
178 self.verify_checksums()
179
180 # Delete flows
181 for i, checksum in enumerate(checksums):
182 self.remove_checksum(checksum)
183 request = ofp.message.flow_delete_strict(
184 table_id=TABLE_ID,
185 priority=i,
186 out_port=ofp.OFPP_ANY,
187 out_group=ofp.OFPG_ANY)
188 self.controller.message_send(request)
189 do_barrier(self.controller)
190 verify_no_errors(self.controller)
191 self.verify_checksums()
192
193 # Deleted all flows, table checksum should be 0
194 self.assertEquals(self.get_table_checksum(), 0)
195
196class ResizeError(FlowChecksumBase):
197 """
198 Check that the switch rejects invalid checksum buckets sizes
199 """
200 def runTest(self):
201 # buckets_size = 0
202 self.controller.message_send(
203 ofp.message.bsn_table_set_buckets_size(
204 table_id=TABLE_ID, buckets_size=0))
205 do_barrier(self.controller)
206 error, _ = self.controller.poll(ofp.OFPT_ERROR)
207 self.assertIsInstance(error, ofp.message.error_msg)
208
209 # buckets_size = 3
210 self.controller.message_send(
211 ofp.message.bsn_table_set_buckets_size(
212 table_id=TABLE_ID, buckets_size=3))
213 do_barrier(self.controller)
214 error, _ = self.controller.poll(ofp.OFPT_ERROR)
215 self.assertIsInstance(error, ofp.message.error_msg)
216
217 # buckets_size = 100
218 self.controller.message_send(
219 ofp.message.bsn_table_set_buckets_size(
220 table_id=TABLE_ID, buckets_size=100))
221 do_barrier(self.controller)
222 error, _ = self.controller.poll(ofp.OFPT_ERROR)
223 self.assertIsInstance(error, ofp.message.error_msg)
224
225 # buckets_size = 2**32 - 1
226 self.controller.message_send(
227 ofp.message.bsn_table_set_buckets_size(
228 table_id=TABLE_ID, buckets_size=2**32-1))
229 do_barrier(self.controller)
230 error, _ = self.controller.poll(ofp.OFPT_ERROR)
231 self.assertIsInstance(error, ofp.message.error_msg)
232
233 # buckets_size = 2**31
234 self.controller.message_send(
235 ofp.message.bsn_table_set_buckets_size(
236 table_id=TABLE_ID, buckets_size=2**31))
237 do_barrier(self.controller)
238 error, _ = self.controller.poll(ofp.OFPT_ERROR)
239 self.assertIsInstance(error, ofp.message.error_msg)