blob: 11bbedcc7208b4721ec7bfb52fb50bd2279fac8f [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
Rich Lanea7331722014-03-11 13:28:25 -070027def shuffled(seq):
28 l = list(seq)[:]
29 random.shuffle(l)
30 return l
31
Rich Lane207599b2014-03-06 14:24:16 -080032class FlowChecksumBase(base_tests.SimpleProtocol):
33 """
34 Base class that maintains the expected table and bucket checksums
35 """
36 checksum_buckets = None
37 table_checksum = None
38 all_checksums = []
39
40 def get_table_checksum(self):
41 for entry in get_stats(self, ofp.message.bsn_table_checksum_stats_request()):
42 if entry.table_id == TABLE_ID:
43 return entry.checksum
44 return None
45
46 def get_checksum_buckets(self):
47 stats = get_stats(self,
48 ofp.message.bsn_flow_checksum_bucket_stats_request(table_id=TABLE_ID))
49 return [x.checksum for x in stats]
50
51 def verify_checksums(self):
52 self.assertEquals(self.get_table_checksum(), self.table_checksum)
53 self.assertEquals(self.get_checksum_buckets(), self.checksum_buckets)
54
55 def update_checksums(self, checksum):
56 self.table_checksum ^= checksum
57 checksum_shift = 64 - int(math.log(len(self.checksum_buckets), 2))
58 self.checksum_buckets[checksum >> checksum_shift] ^= checksum
59
60 def insert_checksum(self, checksum):
61 self.update_checksums(checksum)
62 self.all_checksums.append(checksum)
63
64 def remove_checksum(self, checksum):
65 self.update_checksums(checksum)
66 self.all_checksums.remove(checksum)
67
68 def set_buckets_size(self, buckets_size):
69 self.controller.message_send(
70 ofp.message.bsn_table_set_buckets_size(
71 table_id=TABLE_ID, buckets_size=buckets_size))
72 do_barrier(self.controller)
73 verify_no_errors(self.controller)
74
75 self.checksum_buckets = [0] * buckets_size
76 self.table_checksum = 0
77 for checksum in self.all_checksums:
78 self.update_checksums(checksum)
79
80class FlowChecksum(FlowChecksumBase):
81 """
82 Test flow checksum buckets and table checksums
83 """
84 def runTest(self):
85 delete_all_flows(self.controller)
86
87 # Deleted all flows, table checksum should be 0
88 self.assertEquals(self.get_table_checksum(), 0)
89
90 self.set_buckets_size(8)
91 self.verify_checksums()
92
93 # Interesting checksums
94 checksums = [
95 make_checksum(0, 1),
96 make_checksum(0, 2),
97 make_checksum(1, 0xab),
98 make_checksum(1, 0xab),
99 make_checksum(7, 0xff),
100 make_checksum(7, 0xaa),
101 ]
102
103 # Random checksums
104 for _ in xrange(0, 8):
105 checksums.append(random.randint(0, 2**64-1))
106
107 # Add flows in random order
Rich Lanea7331722014-03-11 13:28:25 -0700108 for i, checksum in shuffled(enumerate(checksums)):
Rich Lane207599b2014-03-06 14:24:16 -0800109 self.insert_checksum(checksum)
110 request = ofp.message.flow_add(
111 table_id=TABLE_ID,
112 cookie=checksum,
113 buffer_id=ofp.OFP_NO_BUFFER,
114 priority=i)
115 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700116 do_barrier(self.controller)
117 verify_no_errors(self.controller)
118 self.verify_checksums()
Rich Lane207599b2014-03-06 14:24:16 -0800119
120 # Delete flows in random order
Rich Lanea7331722014-03-11 13:28:25 -0700121 for i, checksum in shuffled(enumerate(checksums)):
Rich Lane207599b2014-03-06 14:24:16 -0800122 self.remove_checksum(checksum)
123 request = ofp.message.flow_delete_strict(
124 table_id=TABLE_ID,
125 priority=i,
126 out_port=ofp.OFPP_ANY,
127 out_group=ofp.OFPG_ANY)
128 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700129 do_barrier(self.controller)
130 verify_no_errors(self.controller)
131 self.verify_checksums()
Rich Lane207599b2014-03-06 14:24:16 -0800132
133 # Deleted all flows, table checksum should be 0
134 self.assertEquals(self.get_table_checksum(), 0)
135
136class Resize(FlowChecksumBase):
137 """
138 Resize the checksum buckets, checking limits and redistribution
139 """
140 def runTest(self):
141 delete_all_flows(self.controller)
142
143 self.assertEquals(self.get_table_checksum(), 0)
144
145 self.set_buckets_size(128)
146 self.verify_checksums()
147
148 checksums = [random.randint(0, 2**64-1) for _ in xrange(0, 128)]
149
150 # Add flows
151 for i, checksum in enumerate(checksums):
152 self.insert_checksum(checksum)
153 request = ofp.message.flow_add(
154 table_id=TABLE_ID,
155 cookie=checksum,
156 buffer_id=ofp.OFP_NO_BUFFER,
157 priority=i)
158 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700159 if i % 17 == 0:
160 do_barrier(self.controller)
161 verify_no_errors(self.controller)
162 self.verify_checksums()
163
Rich Lane207599b2014-03-06 14:24:16 -0800164 do_barrier(self.controller)
165 verify_no_errors(self.controller)
166 self.verify_checksums()
167
168 # Shrink checksum buckets
169 self.set_buckets_size(64)
170 self.verify_checksums()
171
172 # Shrink checksum buckets to minimum
173 self.set_buckets_size(1)
174 self.verify_checksums()
175
176 # Grow checksum buckets
177 self.set_buckets_size(2)
178 self.verify_checksums()
179
180 # Grow checksum buckets
181 self.set_buckets_size(256)
182 self.verify_checksums()
183
184 # Grow checksum buckets to maximum
185 self.set_buckets_size(65536)
186 self.verify_checksums()
187
188 # Delete flows
189 for i, checksum in enumerate(checksums):
190 self.remove_checksum(checksum)
191 request = ofp.message.flow_delete_strict(
192 table_id=TABLE_ID,
193 priority=i,
194 out_port=ofp.OFPP_ANY,
195 out_group=ofp.OFPG_ANY)
196 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700197 if i % 17 == 0:
198 do_barrier(self.controller)
199 verify_no_errors(self.controller)
200 self.verify_checksums()
201
Rich Lane207599b2014-03-06 14:24:16 -0800202 do_barrier(self.controller)
203 verify_no_errors(self.controller)
204 self.verify_checksums()
205
206 # Deleted all flows, table checksum should be 0
207 self.assertEquals(self.get_table_checksum(), 0)
208
209class ResizeError(FlowChecksumBase):
210 """
211 Check that the switch rejects invalid checksum buckets sizes
212 """
213 def runTest(self):
214 # buckets_size = 0
215 self.controller.message_send(
216 ofp.message.bsn_table_set_buckets_size(
217 table_id=TABLE_ID, buckets_size=0))
218 do_barrier(self.controller)
219 error, _ = self.controller.poll(ofp.OFPT_ERROR)
220 self.assertIsInstance(error, ofp.message.error_msg)
221
222 # buckets_size = 3
223 self.controller.message_send(
224 ofp.message.bsn_table_set_buckets_size(
225 table_id=TABLE_ID, buckets_size=3))
226 do_barrier(self.controller)
227 error, _ = self.controller.poll(ofp.OFPT_ERROR)
228 self.assertIsInstance(error, ofp.message.error_msg)
229
230 # buckets_size = 100
231 self.controller.message_send(
232 ofp.message.bsn_table_set_buckets_size(
233 table_id=TABLE_ID, buckets_size=100))
234 do_barrier(self.controller)
235 error, _ = self.controller.poll(ofp.OFPT_ERROR)
236 self.assertIsInstance(error, ofp.message.error_msg)
237
238 # buckets_size = 2**32 - 1
239 self.controller.message_send(
240 ofp.message.bsn_table_set_buckets_size(
241 table_id=TABLE_ID, buckets_size=2**32-1))
242 do_barrier(self.controller)
243 error, _ = self.controller.poll(ofp.OFPT_ERROR)
244 self.assertIsInstance(error, ofp.message.error_msg)
245
246 # buckets_size = 2**31
247 self.controller.message_send(
248 ofp.message.bsn_table_set_buckets_size(
249 table_id=TABLE_ID, buckets_size=2**31))
250 do_barrier(self.controller)
251 error, _ = self.controller.poll(ofp.OFPT_ERROR)
252 self.assertIsInstance(error, ofp.message.error_msg)