blob: e1cece459ce1ac595a41eea20e36ff729672ffc1 [file] [log] [blame]
Rich Lane89e12652013-10-10 17:26:25 -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# Copyright (c) 2012, 2013 CPqD
5# Copyright (c) 2012, 2013 Ericsson
6"""
7Group table test cases.
8"""
9
10import logging
Rich Lane7b1b1b82013-10-18 13:44:59 -070011import random
Rich Lane89e12652013-10-10 17:26:25 -070012
13from oftest import config
14import oftest
15import oftest.base_tests as base_tests
16import ofp
17
18from oftest.testutils import *
19
20class GroupTest(base_tests.SimpleDataPlane):
21 def setUp(self):
22 base_tests.SimpleDataPlane.setUp(self)
23 delete_all_flows(self.controller)
24 delete_all_groups(self.controller)
25
26
27class GroupAdd(GroupTest):
28 """
29 A regular group should be added successfully
30 """
31
32 def runTest(self):
33 port1, = openflow_ports(1)
34
Rich Lane8be7a282013-11-22 14:21:00 -080035 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -070036 group_type=ofp.OFPGT_ALL,
37 group_id=0,
38 buckets=[
39 ofp.bucket(actions=[ofp.action.output(port1)])])
40
41 self.controller.message_send(msg)
42 do_barrier(self.controller)
43
44 stats = get_stats(self, ofp.message.group_desc_stats_request())
45 self.assertEquals(stats, [
46 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -070047 group_type=msg.group_type,
Rich Lane89e12652013-10-10 17:26:25 -070048 group_id=msg.group_id,
49 buckets=msg.buckets)])
50
51
Rich Laned9ea8ac2013-10-15 10:43:55 -070052class GroupAddMaxID(GroupTest):
53 """
54 A group with ID OFPG_MAX should be added successfully
55 """
56
57 def runTest(self):
58 port1, = openflow_ports(1)
59
Rich Lane8be7a282013-11-22 14:21:00 -080060 msg = ofp.message.group_add(
Rich Laned9ea8ac2013-10-15 10:43:55 -070061 group_type=ofp.OFPGT_ALL,
62 group_id=ofp.OFPG_MAX,
63 buckets=[
64 ofp.bucket(actions=[ofp.action.output(port1)])])
65
66 self.controller.message_send(msg)
67 do_barrier(self.controller)
68
69 stats = get_stats(self, ofp.message.group_desc_stats_request())
70 self.assertEquals(stats, [
71 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -070072 group_type=msg.group_type,
Rich Laned9ea8ac2013-10-15 10:43:55 -070073 group_id=msg.group_id,
74 buckets=msg.buckets)])
75
76
Rich Lane89e12652013-10-10 17:26:25 -070077class GroupAddInvalidAction(GroupTest):
78 """
79 If any action in the buckets is invalid, OFPET_BAD_ACTION/<code> should be returned
80 """
81
82 def runTest(self):
Rich Lane8be7a282013-11-22 14:21:00 -080083 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -070084 group_type=ofp.OFPGT_ALL,
85 group_id=0,
86 buckets=[
87 ofp.bucket(actions=[ofp.action.output(ofp.OFPP_ANY)])])
88
89 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -070090 self.assertIsInstance(response, ofp.message.bad_action_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -070091 self.assertEquals(response.code, ofp.OFPBAC_BAD_OUT_PORT)
92
93
94class GroupAddExisting(GroupTest):
95 """
96 An addition with existing group id should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_GROUP_EXISTS
97 """
98
99 def runTest(self):
100 port1, port2, = openflow_ports(2)
101
Rich Lane8be7a282013-11-22 14:21:00 -0800102 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700103 group_type=ofp.OFPGT_ALL,
104 group_id=0,
105 buckets=[
106 ofp.bucket(actions=[ofp.action.output(port1)])])
107
108 self.controller.message_send(msg)
109 do_barrier(self.controller)
110
Rich Lane8be7a282013-11-22 14:21:00 -0800111 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700112 group_type=ofp.OFPGT_ALL,
113 group_id=0,
114 buckets=[
115 ofp.bucket(actions=[ofp.action.output(port2)])])
116
117 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700118 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700119 self.assertEquals(response.code, ofp.OFPGMFC_GROUP_EXISTS)
120
121
122class GroupAddInvalidID(GroupTest):
123 """
124 An addition with invalid group id (reserved) should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
125 """
126
127 def runTest(self):
128 port1, = openflow_ports(1)
129
Rich Lane8be7a282013-11-22 14:21:00 -0800130 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700131 group_type=ofp.OFPGT_ALL,
132 group_id=ofp.OFPG_ALL,
133 buckets=[
134 ofp.bucket(actions=[ofp.action.output(port1)])])
135
136 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700137 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700138 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
139
140
Rich Laned9ea8ac2013-10-15 10:43:55 -0700141class GroupAddMinimumInvalidID(GroupTest):
142 """
143 An addition with invalid group id (reserved) should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
144 """
145
146 def runTest(self):
147 port1, = openflow_ports(1)
148
Rich Lane8be7a282013-11-22 14:21:00 -0800149 msg = ofp.message.group_add(
Rich Laned9ea8ac2013-10-15 10:43:55 -0700150 group_type=ofp.OFPGT_ALL,
151 group_id=ofp.OFPG_MAX+1,
152 buckets=[
153 ofp.bucket(actions=[ofp.action.output(port1)])])
154
155 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700156 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Laned9ea8ac2013-10-15 10:43:55 -0700157 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
158
159
Rich Lane89e12652013-10-10 17:26:25 -0700160class GroupModify(GroupTest):
161 """
162 A regular group modification should be successful
163 """
164
165 def runTest(self):
166 port1, port2, = openflow_ports(2)
167
Rich Lane8be7a282013-11-22 14:21:00 -0800168 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700169 group_type=ofp.OFPGT_ALL,
170 group_id=0,
171 buckets=[
172 ofp.bucket(actions=[ofp.action.output(port1)])])
173
174 self.controller.message_send(msg)
175 do_barrier(self.controller)
176
Rich Lane8be7a282013-11-22 14:21:00 -0800177 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700178 group_type=ofp.OFPGT_ALL,
179 group_id=0,
180 buckets=[
181 ofp.bucket(actions=[ofp.action.output(port2)])])
182
183 self.controller.message_send(msg)
184 do_barrier(self.controller)
185
186 stats = get_stats(self, ofp.message.group_desc_stats_request())
187 self.assertEquals(stats, [
188 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -0700189 group_type=msg.group_type,
Rich Lane89e12652013-10-10 17:26:25 -0700190 group_id=msg.group_id,
191 buckets=msg.buckets)])
192
193
194class GroupModifyNonexisting(GroupTest):
195 """
196 A modification for a non-existing group should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_UNKNOWN_GROUP
197 """
198
199 def runTest(self):
200 port1, = openflow_ports(1)
201
Rich Lane8be7a282013-11-22 14:21:00 -0800202 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700203 group_type=ofp.OFPGT_ALL,
204 group_id=0,
205 buckets=[
206 ofp.bucket(actions=[ofp.action.output(port1)])])
207
208 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700209 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700210 self.assertEquals(response.code, ofp.OFPGMFC_UNKNOWN_GROUP)
211
212
213class GroupModifyLoop(GroupTest):
214 """
215 A modification causing loop should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_LOOP
216 """
217
218 def runTest(self):
219 port1, = openflow_ports(1)
220
Rich Lane8be7a282013-11-22 14:21:00 -0800221 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700222 group_type=ofp.OFPGT_ALL,
223 group_id=0,
224 buckets=[
225 ofp.bucket(actions=[ofp.action.output(port1)])])
226
227 self.controller.message_send(msg)
228 do_barrier(self.controller)
229
Rich Lane8be7a282013-11-22 14:21:00 -0800230 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700231 group_type=ofp.OFPGT_ALL,
232 group_id=1,
233 buckets=[
234 ofp.bucket(actions=[ofp.action.group(0)])])
235
236 self.controller.message_send(msg)
237 do_barrier(self.controller)
238
Rich Lane8be7a282013-11-22 14:21:00 -0800239 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700240 group_type=ofp.OFPGT_ALL,
241 group_id=2,
242 buckets=[
243 ofp.bucket(actions=[ofp.action.group(1)])])
244
245 self.controller.message_send(msg)
246 do_barrier(self.controller)
247
Rich Lane8be7a282013-11-22 14:21:00 -0800248 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700249 group_type=ofp.OFPGT_ALL,
250 group_id=0,
251 buckets=[
252 ofp.bucket(actions=[ofp.action.group(2)])])
253
254 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700255 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700256 self.assertEquals(response.code, ofp.OFPGMFC_LOOP)
257
258
259class GroupModifyInvalidID(GroupTest):
260 """
261 A modification for a reserved group should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
262 """
263
264 def runTest(self):
265 port1, = openflow_ports(1)
266
Rich Lane8be7a282013-11-22 14:21:00 -0800267 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700268 group_type=ofp.OFPGT_ALL,
269 group_id=ofp.OFPG_ALL,
270 buckets=[
271 ofp.bucket(actions=[ofp.action.output(port1)])])
272
273 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700274 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700275 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
276
277
278class GroupModifyEmpty(GroupTest):
279 """
280 A modification for an existing group with no buckets should be accepted
281 """
282
283 def runTest(self):
284 port1, = openflow_ports(1)
285
Rich Lane8be7a282013-11-22 14:21:00 -0800286 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700287 group_type=ofp.OFPGT_ALL,
288 group_id=0,
289 buckets=[
290 ofp.bucket(actions=[ofp.action.output(port1)])])
291
292 self.controller.message_send(msg)
293 do_barrier(self.controller)
294
Rich Lane8be7a282013-11-22 14:21:00 -0800295 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700296 group_type=ofp.OFPGT_ALL,
297 group_id=0,
298 buckets=[])
299
300 self.controller.message_send(msg)
301 do_barrier(self.controller)
302
303 stats = get_stats(self, ofp.message.group_desc_stats_request())
304 self.assertEquals(stats, [
305 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -0700306 group_type=msg.group_type,
Rich Lane89e12652013-10-10 17:26:25 -0700307 group_id=msg.group_id,
308 buckets=msg.buckets)])
309
310
311class GroupDeleteExisting(GroupTest):
312 """
313 A deletion for an existing group should remove the group
314 """
315
316 def runTest(self):
317 port1, = openflow_ports(1)
318
Rich Lane8be7a282013-11-22 14:21:00 -0800319 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700320 group_type=ofp.OFPGT_ALL,
321 group_id=0,
322 buckets=[
323 ofp.bucket(actions=[ofp.action.output(port1)])])
324
325 self.controller.message_send(msg)
326 do_barrier(self.controller)
327
Rich Lane8be7a282013-11-22 14:21:00 -0800328 msg = ofp.message.group_delete(group_id=0)
Rich Lane89e12652013-10-10 17:26:25 -0700329
330 self.controller.message_send(msg)
331 do_barrier(self.controller)
332
333 stats = get_stats(self, ofp.message.group_desc_stats_request())
334 self.assertEquals(stats, [])
335
336
337class GroupDeleteNonexisting(GroupTest):
338 """
339 A deletion for nonexisting group should result in no error
340 """
341
342 def runTest(self):
Rich Lane8be7a282013-11-22 14:21:00 -0800343 msg = ofp.message.group_delete(group_id=0)
Rich Lane89e12652013-10-10 17:26:25 -0700344
345 self.controller.message_send(msg)
346 do_barrier(self.controller)
347 verify_no_errors(self.controller)
348
349
350class GroupDeleteAll(GroupTest):
351 """
352 A deletion for OFPG_ALL should remove all groups
353 """
354
355 def runTest(self):
356 port1, = openflow_ports(1)
357
Rich Lane8be7a282013-11-22 14:21:00 -0800358 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700359 group_type=ofp.OFPGT_ALL,
360 group_id=0,
361 buckets=[
362 ofp.bucket(actions=[ofp.action.output(port1)])])
363
364 self.controller.message_send(msg)
365 do_barrier(self.controller)
366
Rich Lane8be7a282013-11-22 14:21:00 -0800367 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700368 group_type=ofp.OFPGT_ALL,
369 group_id=1,
370 buckets=[
371 ofp.bucket(actions=[ofp.action.output(port1)])])
372
373 self.controller.message_send(msg)
374 do_barrier(self.controller)
375
Rich Lane8be7a282013-11-22 14:21:00 -0800376 msg = ofp.message.group_delete(group_id=ofp.OFPG_ALL)
Rich Lane89e12652013-10-10 17:26:25 -0700377
378 self.controller.message_send(msg)
379 do_barrier(self.controller)
380
381 stats = get_stats(self, ofp.message.group_desc_stats_request())
382 self.assertEquals(stats, [])
383
384
385class GroupAddAllWeight(GroupTest):
386 """
387 An ALL group with weights for buckets should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
388 """
389
390 def runTest(self):
391 port1, port2, = openflow_ports(2)
392
Rich Lane8be7a282013-11-22 14:21:00 -0800393 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700394 group_type=ofp.OFPGT_ALL,
395 group_id=0,
396 buckets=[
397 ofp.bucket(weight=1, actions=[ofp.action.output(port1)]),
398 ofp.bucket(weight=2, actions=[ofp.action.output(port2)])])
399
400 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700401 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700402 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
403
404
405class GroupAddIndirectWeight(GroupTest):
406 """
407 An INDIRECT group with weights for buckets should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
408 """
409
410 def runTest(self):
411 port1, = openflow_ports(1)
412
Rich Lane8be7a282013-11-22 14:21:00 -0800413 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700414 group_type=ofp.OFPGT_INDIRECT,
415 group_id=0,
416 buckets=[
417 ofp.bucket(weight=1, actions=[ofp.action.output(port1)])])
418
419 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700420 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700421 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
422
423
424class GroupAddIndirectBuckets(GroupTest):
425 """
426 An INDIRECT group with <>1 bucket should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
427 """
428
429 def runTest(self):
430 port1, port2, = openflow_ports(2)
431
Rich Lane8be7a282013-11-22 14:21:00 -0800432 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700433 group_type=ofp.OFPGT_INDIRECT,
434 group_id=0,
435 buckets=[
436 ofp.bucket(actions=[ofp.action.output(port1)]),
437 ofp.bucket(actions=[ofp.action.output(port2)])])
438
439 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700440 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700441 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
442
443
444class GroupAddSelectNoWeight(GroupTest):
445 """
446 A SELECT group with ==0 weights should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
447 """
448
449 def runTest(self):
450 port1, port2, = openflow_ports(2)
451
Rich Lane8be7a282013-11-22 14:21:00 -0800452 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700453 group_type=ofp.OFPGT_SELECT,
454 group_id=0,
455 buckets=[
456 ofp.bucket(actions=[ofp.action.output(port1)]),
457 ofp.bucket(actions=[ofp.action.output(port2)])])
458
459 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700460 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700461 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
462
463
464class GroupStats(GroupTest):
465 """
466 A group stats request should return an entry for the specified group
467 """
468
469 def runTest(self):
470 port1, port2, = openflow_ports(2)
471
Rich Lane8be7a282013-11-22 14:21:00 -0800472 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700473 group_type=ofp.OFPGT_ALL,
474 group_id=10,
475 buckets=[
476 ofp.bucket(actions=[
477 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
478 ofp.action.output(port1)]),
479 ofp.bucket(actions=[
480 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
481 ofp.action.output(port2)])])
482
483 self.controller.message_send(msg)
484 do_barrier(self.controller)
485
486 request = ofp.message.group_stats_request(group_id=10)
487 stats = get_stats(self, request)
488
489 self.assertEquals(len(stats), 1)
490 self.assertEquals(stats[0].group_id, 10)
491 self.assertEquals(stats[0].ref_count, 0)
492 self.assertEquals(stats[0].packet_count, 0)
493 self.assertEquals(stats[0].byte_count, 0)
494 self.assertEquals(len(stats[0].bucket_stats), 2)
495
496
497class GroupStatsNonexistent(GroupTest):
498 """
499 A group stats request for a nonexistent group should return an empty list
500 """
501
502 def runTest(self):
503 request = ofp.message.group_stats_request(group_id=10)
504 stats = get_stats(self, request)
505 self.assertEquals(len(stats), 0)
506
507
508class GroupStatsAll(GroupTest):
509 """
510 A group stats request with OFPG_ALL should return an entry for each group
511 """
512
513 def runTest(self):
514 port1, port2, = openflow_ports(2)
515
Rich Lane8be7a282013-11-22 14:21:00 -0800516 msg0 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700517 group_type=ofp.OFPGT_ALL,
518 group_id=0,
519 buckets=[
520 ofp.bucket(actions=[
521 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
522 ofp.action.output(port1)]),
523 ofp.bucket(actions=[
524 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
525 ofp.action.output(port2)])])
526
527 self.controller.message_send(msg0)
528 do_barrier(self.controller)
529
Rich Lane8be7a282013-11-22 14:21:00 -0800530 msg1 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700531 group_type=ofp.OFPGT_ALL,
532 group_id=1,
533 buckets=[
534 ofp.bucket(actions=[
535 ofp.action.set_field(ofp.oxm.tcp_src(2001)),
536 ofp.action.output(port1)]),
537 ofp.bucket(actions=[
538 ofp.action.set_field(ofp.oxm.tcp_src(3001)),
539 ofp.action.output(port2)])])
540
541 self.controller.message_send(msg1)
542 do_barrier(self.controller)
543
544 request = ofp.message.group_stats_request(group_id=ofp.OFPG_ALL)
545 stats = sorted(get_stats(self, request), key=lambda x: x.group_id)
546
547 self.assertEquals(len(stats), 2)
548
549 self.assertEquals(stats[0].group_id, 0)
550 self.assertEquals(stats[0].ref_count, 0)
551 self.assertEquals(stats[0].packet_count, 0)
552 self.assertEquals(stats[0].byte_count, 0)
553 self.assertEquals(len(stats[0].bucket_stats), 2)
554
555 self.assertEquals(stats[1].group_id, 1)
556 self.assertEquals(stats[1].ref_count, 0)
557 self.assertEquals(stats[1].packet_count, 0)
558 self.assertEquals(stats[1].byte_count, 0)
559 self.assertEquals(len(stats[1].bucket_stats), 2)
560
561
562class GroupDescStats(GroupTest):
563 """
564 A group desc stats request should return the type, id, and buckets for each group
565 """
566
567 def runTest(self):
568 port1, port2, port3, = openflow_ports(3)
569
Rich Lane8be7a282013-11-22 14:21:00 -0800570 msg0 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700571 group_type=ofp.OFPGT_ALL,
572 group_id=0,
573 buckets=[
574 ofp.bucket(actions=[
575 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
576 ofp.action.output(port1)]),
577 ofp.bucket(actions=[
578 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
579 ofp.action.output(port2)]),
580 ofp.bucket(actions=[
581 ofp.action.set_field(ofp.oxm.tcp_src(4000)),
582 ofp.action.output(port3)])])
583
584 self.controller.message_send(msg0)
585 do_barrier(self.controller)
586
Rich Lane8be7a282013-11-22 14:21:00 -0800587 msg1 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700588 group_type=ofp.OFPGT_SELECT,
589 group_id=1,
590 buckets=[
591 ofp.bucket(
592 weight=1,
593 actions=[
594 ofp.action.set_field(ofp.oxm.tcp_src(2001)),
595 ofp.action.output(port1)]),
596 ofp.bucket(
597 weight=2,
598 actions=[
599 ofp.action.set_field(ofp.oxm.tcp_src(3001)),
600 ofp.action.output(port2)]),
601 ofp.bucket(
602 weight=3,
603 actions=[
604 ofp.action.set_field(ofp.oxm.tcp_src(4001)),
605 ofp.action.output(port3)])])
606
607 self.controller.message_send(msg1)
608 do_barrier(self.controller)
609
Rich Lane8be7a282013-11-22 14:21:00 -0800610 msg2 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700611 group_type=ofp.OFPGT_FF,
612 group_id=2,
613 buckets=[
614 ofp.bucket(
615 watch_port=port1,
616 actions=[
617 ofp.action.set_field(ofp.oxm.tcp_src(2002)),
618 ofp.action.output(port1)]),
619 ofp.bucket(
620 watch_port=port2,
621 actions=[
622 ofp.action.set_field(ofp.oxm.tcp_src(3002)),
623 ofp.action.output(port2,)]),
624 ofp.bucket(
625 watch_port=port3,
626 actions=[
627 ofp.action.set_field(ofp.oxm.tcp_src(4002)),
628 ofp.action.output(port3,)])])
629
630 self.controller.message_send(msg2)
631 do_barrier(self.controller)
632
633 request = ofp.message.group_desc_stats_request()
634 stats = sorted(get_stats(self, request), key=lambda x: x.group_id)
635
636 self.assertEquals(len(stats), 3)
637
638 self.assertEquals(stats[0].group_id, msg0.group_id)
Rich Lane165332d2014-07-30 14:27:44 -0700639 self.assertEquals(stats[0].group_type, msg0.group_type)
Rich Lane89e12652013-10-10 17:26:25 -0700640 self.assertEquals(stats[0].buckets, msg0.buckets)
641
642 self.assertEquals(stats[1].group_id, msg1.group_id)
Rich Lane165332d2014-07-30 14:27:44 -0700643 self.assertEquals(stats[1].group_type, msg1.group_type)
Rich Lane89e12652013-10-10 17:26:25 -0700644 self.assertEquals(stats[1].buckets, msg1.buckets)
645
646 self.assertEquals(stats[2].group_id, msg2.group_id)
Rich Lane165332d2014-07-30 14:27:44 -0700647 self.assertEquals(stats[2].group_type, msg2.group_type)
Rich Lane89e12652013-10-10 17:26:25 -0700648 self.assertEquals(stats[2].buckets, msg2.buckets)
649
650
651class GroupFlowSelect(GroupTest):
652 """
653 A flow stats request qualified on group id should select the correct flows
654 """
655
656 def runTest(self):
657 port1, = openflow_ports(1)
658
Rich Lane8be7a282013-11-22 14:21:00 -0800659 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700660 group_type=ofp.OFPGT_ALL,
661 group_id=1,
662 buckets=[])
663
664 self.controller.message_send(msg)
665 do_barrier(self.controller)
666
Rich Lane8be7a282013-11-22 14:21:00 -0800667 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700668 group_type=ofp.OFPGT_ALL,
669 group_id=2,
670 buckets=[])
671
672 self.controller.message_send(msg)
673 do_barrier(self.controller)
674
675 packet_in1 = simple_tcp_packet(tcp_sport=1000)
676
677 flow_add_msg1 = flow_msg_create(
678 self,
679 packet_in1,
680 ing_port=1,
681 action_list=[
682 ofp.action.group(1),
683 ofp.action.output(port1)])
684
685 self.controller.message_send(flow_add_msg1)
686 do_barrier(self.controller)
687
688 packet_in2 = simple_tcp_packet(tcp_sport=2000)
689
690 flow_add_msg2 = flow_msg_create(
691 self,
692 packet_in2,
693 ing_port=1,
694 action_list=[
695 ofp.action.group(2),
696 ofp.action.output(port1)])
697
698 self.controller.message_send(flow_add_msg2)
699 do_barrier(self.controller)
700
701 packet_in3 = simple_tcp_packet(tcp_sport=3000)
702
703 flow_add_msg3 = flow_msg_create(
704 self,
705 packet_in3,
706 ing_port=1,
707 action_list=[
708 ofp.action.group(2),
709 ofp.action.output(port1)])
710
711 self.controller.message_send(flow_add_msg3)
712 do_barrier(self.controller)
713
714 packet_in4 = simple_tcp_packet(tcp_sport=4000)
715
716 flow_add_msg4 = flow_msg_create(
717 self,
718 packet_in4,
719 ing_port=1,
720 action_list=[
721 ofp.action.output(port1)])
722
723 self.controller.message_send(flow_add_msg4)
724 do_barrier(self.controller)
725
726 request = ofp.message.aggregate_stats_request(
727 table_id=ofp.OFPTT_ALL,
728 out_port=ofp.OFPP_ANY,
729 out_group=2)
730
731 response, _ = self.controller.transact(request)
732
733 self.assertEqual(response.flow_count, 2,
734 'Did not match expected flow count')
Rich Lane7b1b1b82013-10-18 13:44:59 -0700735
736
737class SelectFwdEmpty(GroupTest):
738 """
739 A SELECT group with no buckets should not alter the action set of the packet
740 """
741
742 def runTest(self):
743 port1, port2 = openflow_ports(2)
744
Rich Lane8be7a282013-11-22 14:21:00 -0800745 msg = ofp.message.group_add(
Rich Lane7b1b1b82013-10-18 13:44:59 -0700746 group_type=ofp.OFPGT_SELECT,
747 group_id=1,
748 buckets=[])
749
750 self.controller.message_send(msg)
751 do_barrier(self.controller)
752
753 msg = ofp.message.flow_add(
754 buffer_id=ofp.OFP_NO_BUFFER,
755 instructions=[
756 ofp.instruction.apply_actions(
757 [ofp.action.output(2), ofp.action.group(1)])])
758
759 self.controller.message_send(msg)
760 do_barrier(self.controller)
761
762 verify_no_errors(self.controller)
763
764 pkt = simple_tcp_packet()
765 self.dataplane.send(port1, str(pkt))
766 verify_packets(self, pkt, [port2])
767
768
769class SelectFwdSingle(GroupTest):
770 """
771 A SELECT group with a single bucket should use that bucket's actions
772 """
773
774 def runTest(self):
775 port1, port2 = openflow_ports(2)
776
Rich Lane8be7a282013-11-22 14:21:00 -0800777 msg = ofp.message.group_add(
Rich Lane7b1b1b82013-10-18 13:44:59 -0700778 group_type=ofp.OFPGT_SELECT,
779 group_id=1,
780 buckets=[
781 ofp.bucket(weight=1, actions=[ofp.action.output(port2)])])
782
783 self.controller.message_send(msg)
784 do_barrier(self.controller)
785
786 msg = ofp.message.flow_add(
787 buffer_id=ofp.OFP_NO_BUFFER,
788 instructions=[ofp.instruction.apply_actions([ofp.action.group(1)])])
789
790 self.controller.message_send(msg)
791 do_barrier(self.controller)
792
793 verify_no_errors(self.controller)
794
795 pkt = simple_tcp_packet()
796 self.dataplane.send(port1, str(pkt))
797 verify_packets(self, pkt, [port2])
798
799
800class SelectFwdSpread(GroupTest):
801 """
802 A SELECT group with several buckets should spead different flows between them
803 """
804
805 def runTest(self):
806 num_out_ports = 3
807 num_pkts = 1000
808
809 port1, port2, port3, port4 = openflow_ports(num_out_ports + 1)
810 out_ports = [port2, port3, port4]
811
Rich Lane8be7a282013-11-22 14:21:00 -0800812 msg = ofp.message.group_add(
Rich Lane7b1b1b82013-10-18 13:44:59 -0700813 group_type=ofp.OFPGT_SELECT,
814 group_id=1,
815 buckets=[
816 ofp.bucket(weight=1, actions=[ofp.action.output(port)])
817 for port in out_ports])
818
819 self.controller.message_send(msg)
820 do_barrier(self.controller)
821
822 msg = ofp.message.flow_add(
823 buffer_id=ofp.OFP_NO_BUFFER,
824 instructions=[ofp.instruction.apply_actions([ofp.action.group(1)])])
825
826 self.controller.message_send(msg)
827 do_barrier(self.controller)
828
829 verify_no_errors(self.controller)
830
831 counters = { x: 0 for x in out_ports }
832
833 for i in xrange(0, num_pkts):
834 pkt = simple_tcp_packet(tcp_sport=i, tcp_dport=random.randint(0, 65535))
835 self.dataplane.send(port1, str(pkt))
836 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=str(pkt))
837 self.assertIsNotNone(rcv_pkt)
838 if rcv_port not in counters:
839 raise AssertionError("unexpected packet on port %d" % rcv_port)
840 counters[rcv_port] += 1
841
842 # Verify the same flow is mapped to the same output port
843 self.dataplane.send(port1, str(pkt))
844 (rcv_port2, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=str(pkt))
845 self.assertIsNotNone(rcv_pkt)
846 self.assertEquals(rcv_port, rcv_port2)
847
848 logging.debug("Distribution: %r" ,counters)
849
850 self.assertEquals(sum(counters.values()), num_pkts)
851 expected = num_pkts/num_out_ports
852 for port, count in counters.iteritems():
853 # Check that count is within 20% of expected
854 self.assertTrue(expected * 0.8 < count < expected * 1.2,
855 "port %d count was %d, expected %d" % (port, count, expected))