blob: d1bc83afd72bd6aa97cd02cfab851e9cfe50afc7 [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
35 msg = ofp.message.group_mod(
36 command=ofp.OFPGC_ADD,
37 group_type=ofp.OFPGT_ALL,
38 group_id=0,
39 buckets=[
40 ofp.bucket(actions=[ofp.action.output(port1)])])
41
42 self.controller.message_send(msg)
43 do_barrier(self.controller)
44
45 stats = get_stats(self, ofp.message.group_desc_stats_request())
46 self.assertEquals(stats, [
47 ofp.group_desc_stats_entry(
48 type=msg.group_type,
49 group_id=msg.group_id,
50 buckets=msg.buckets)])
51
52
Rich Laned9ea8ac2013-10-15 10:43:55 -070053class GroupAddMaxID(GroupTest):
54 """
55 A group with ID OFPG_MAX should be added successfully
56 """
57
58 def runTest(self):
59 port1, = openflow_ports(1)
60
61 msg = ofp.message.group_mod(
62 command=ofp.OFPGC_ADD,
63 group_type=ofp.OFPGT_ALL,
64 group_id=ofp.OFPG_MAX,
65 buckets=[
66 ofp.bucket(actions=[ofp.action.output(port1)])])
67
68 self.controller.message_send(msg)
69 do_barrier(self.controller)
70
71 stats = get_stats(self, ofp.message.group_desc_stats_request())
72 self.assertEquals(stats, [
73 ofp.group_desc_stats_entry(
74 type=msg.group_type,
75 group_id=msg.group_id,
76 buckets=msg.buckets)])
77
78
Rich Lane89e12652013-10-10 17:26:25 -070079class GroupAddInvalidAction(GroupTest):
80 """
81 If any action in the buckets is invalid, OFPET_BAD_ACTION/<code> should be returned
82 """
83
84 def runTest(self):
85 msg = ofp.message.group_mod(
86 command=ofp.OFPGC_ADD,
87 group_type=ofp.OFPGT_ALL,
88 group_id=0,
89 buckets=[
90 ofp.bucket(actions=[ofp.action.output(ofp.OFPP_ANY)])])
91
92 response, _ = self.controller.transact(msg)
93 self.assertIsInstance(response, ofp.message.error_msg)
94 self.assertEquals(response.err_type, ofp.OFPET_BAD_ACTION)
95 self.assertEquals(response.code, ofp.OFPBAC_BAD_OUT_PORT)
96
97
98class GroupAddExisting(GroupTest):
99 """
100 An addition with existing group id should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_GROUP_EXISTS
101 """
102
103 def runTest(self):
104 port1, port2, = openflow_ports(2)
105
106 msg = ofp.message.group_mod(
107 command=ofp.OFPGC_ADD,
108 group_type=ofp.OFPGT_ALL,
109 group_id=0,
110 buckets=[
111 ofp.bucket(actions=[ofp.action.output(port1)])])
112
113 self.controller.message_send(msg)
114 do_barrier(self.controller)
115
116 msg = ofp.message.group_mod(
117 command=ofp.OFPGC_ADD,
118 group_type=ofp.OFPGT_ALL,
119 group_id=0,
120 buckets=[
121 ofp.bucket(actions=[ofp.action.output(port2)])])
122
123 response, _ = self.controller.transact(msg)
124 self.assertIsInstance(response, ofp.message.error_msg)
125 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
126 self.assertEquals(response.code, ofp.OFPGMFC_GROUP_EXISTS)
127
128
129class GroupAddInvalidID(GroupTest):
130 """
131 An addition with invalid group id (reserved) should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
132 """
133
134 def runTest(self):
135 port1, = openflow_ports(1)
136
137 msg = ofp.message.group_mod(
138 command=ofp.OFPGC_ADD,
139 group_type=ofp.OFPGT_ALL,
140 group_id=ofp.OFPG_ALL,
141 buckets=[
142 ofp.bucket(actions=[ofp.action.output(port1)])])
143
144 response, _ = self.controller.transact(msg)
145 self.assertIsInstance(response, ofp.message.error_msg)
146 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
147 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
148
149
Rich Laned9ea8ac2013-10-15 10:43:55 -0700150class GroupAddMinimumInvalidID(GroupTest):
151 """
152 An addition with invalid group id (reserved) should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
153 """
154
155 def runTest(self):
156 port1, = openflow_ports(1)
157
158 msg = ofp.message.group_mod(
159 command=ofp.OFPGC_ADD,
160 group_type=ofp.OFPGT_ALL,
161 group_id=ofp.OFPG_MAX+1,
162 buckets=[
163 ofp.bucket(actions=[ofp.action.output(port1)])])
164
165 response, _ = self.controller.transact(msg)
166 self.assertIsInstance(response, ofp.message.error_msg)
167 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
168 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
169
170
Rich Lane89e12652013-10-10 17:26:25 -0700171class GroupModify(GroupTest):
172 """
173 A regular group modification should be successful
174 """
175
176 def runTest(self):
177 port1, port2, = openflow_ports(2)
178
179 msg = ofp.message.group_mod(
180 command=ofp.OFPGC_ADD,
181 group_type=ofp.OFPGT_ALL,
182 group_id=0,
183 buckets=[
184 ofp.bucket(actions=[ofp.action.output(port1)])])
185
186 self.controller.message_send(msg)
187 do_barrier(self.controller)
188
189 msg = ofp.message.group_mod(
190 command=ofp.OFPGC_MODIFY,
191 group_type=ofp.OFPGT_ALL,
192 group_id=0,
193 buckets=[
194 ofp.bucket(actions=[ofp.action.output(port2)])])
195
196 self.controller.message_send(msg)
197 do_barrier(self.controller)
198
199 stats = get_stats(self, ofp.message.group_desc_stats_request())
200 self.assertEquals(stats, [
201 ofp.group_desc_stats_entry(
202 type=msg.group_type,
203 group_id=msg.group_id,
204 buckets=msg.buckets)])
205
206
207class GroupModifyNonexisting(GroupTest):
208 """
209 A modification for a non-existing group should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_UNKNOWN_GROUP
210 """
211
212 def runTest(self):
213 port1, = openflow_ports(1)
214
215 msg = ofp.message.group_mod(
216 command=ofp.OFPGC_MODIFY,
217 group_type=ofp.OFPGT_ALL,
218 group_id=0,
219 buckets=[
220 ofp.bucket(actions=[ofp.action.output(port1)])])
221
222 response, _ = self.controller.transact(msg)
223 self.assertIsInstance(response, ofp.message.error_msg)
224 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
225 self.assertEquals(response.code, ofp.OFPGMFC_UNKNOWN_GROUP)
226
227
228class GroupModifyLoop(GroupTest):
229 """
230 A modification causing loop should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_LOOP
231 """
232
233 def runTest(self):
234 port1, = openflow_ports(1)
235
236 msg = ofp.message.group_mod(
237 command=ofp.OFPGC_ADD,
238 group_type=ofp.OFPGT_ALL,
239 group_id=0,
240 buckets=[
241 ofp.bucket(actions=[ofp.action.output(port1)])])
242
243 self.controller.message_send(msg)
244 do_barrier(self.controller)
245
246 msg = ofp.message.group_mod(
247 command=ofp.OFPGC_ADD,
248 group_type=ofp.OFPGT_ALL,
249 group_id=1,
250 buckets=[
251 ofp.bucket(actions=[ofp.action.group(0)])])
252
253 self.controller.message_send(msg)
254 do_barrier(self.controller)
255
256 msg = ofp.message.group_mod(
257 command=ofp.OFPGC_ADD,
258 group_type=ofp.OFPGT_ALL,
259 group_id=2,
260 buckets=[
261 ofp.bucket(actions=[ofp.action.group(1)])])
262
263 self.controller.message_send(msg)
264 do_barrier(self.controller)
265
266 msg = ofp.message.group_mod(
267 command=ofp.OFPGC_MODIFY,
268 group_type=ofp.OFPGT_ALL,
269 group_id=0,
270 buckets=[
271 ofp.bucket(actions=[ofp.action.group(2)])])
272
273 response, _ = self.controller.transact(msg)
274 self.assertIsInstance(response, ofp.message.error_msg)
275 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
276 self.assertEquals(response.code, ofp.OFPGMFC_LOOP)
277
278
279class GroupModifyInvalidID(GroupTest):
280 """
281 A modification for a reserved group should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
282 """
283
284 def runTest(self):
285 port1, = openflow_ports(1)
286
287 msg = ofp.message.group_mod(
288 command=ofp.OFPGC_ADD,
289 group_type=ofp.OFPGT_ALL,
290 group_id=ofp.OFPG_ALL,
291 buckets=[
292 ofp.bucket(actions=[ofp.action.output(port1)])])
293
294 response, _ = self.controller.transact(msg)
295 self.assertIsInstance(response, ofp.message.error_msg)
296 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
297 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
298
299
300class GroupModifyEmpty(GroupTest):
301 """
302 A modification for an existing group with no buckets should be accepted
303 """
304
305 def runTest(self):
306 port1, = openflow_ports(1)
307
308 msg = ofp.message.group_mod(
309 command=ofp.OFPGC_ADD,
310 group_type=ofp.OFPGT_ALL,
311 group_id=0,
312 buckets=[
313 ofp.bucket(actions=[ofp.action.output(port1)])])
314
315 self.controller.message_send(msg)
316 do_barrier(self.controller)
317
318 msg = ofp.message.group_mod(
319 command=ofp.OFPGC_MODIFY,
320 group_type=ofp.OFPGT_ALL,
321 group_id=0,
322 buckets=[])
323
324 self.controller.message_send(msg)
325 do_barrier(self.controller)
326
327 stats = get_stats(self, ofp.message.group_desc_stats_request())
328 self.assertEquals(stats, [
329 ofp.group_desc_stats_entry(
330 type=msg.group_type,
331 group_id=msg.group_id,
332 buckets=msg.buckets)])
333
334
335class GroupDeleteExisting(GroupTest):
336 """
337 A deletion for an existing group should remove the group
338 """
339
340 def runTest(self):
341 port1, = openflow_ports(1)
342
343 msg = ofp.message.group_mod(
344 command=ofp.OFPGC_ADD,
345 group_type=ofp.OFPGT_ALL,
346 group_id=0,
347 buckets=[
348 ofp.bucket(actions=[ofp.action.output(port1)])])
349
350 self.controller.message_send(msg)
351 do_barrier(self.controller)
352
353 msg = ofp.message.group_mod(
354 command=ofp.OFPGC_DELETE,
355 group_id=0)
356
357 self.controller.message_send(msg)
358 do_barrier(self.controller)
359
360 stats = get_stats(self, ofp.message.group_desc_stats_request())
361 self.assertEquals(stats, [])
362
363
364class GroupDeleteNonexisting(GroupTest):
365 """
366 A deletion for nonexisting group should result in no error
367 """
368
369 def runTest(self):
370 msg = ofp.message.group_mod(
371 command=ofp.OFPGC_DELETE,
372 group_id=0)
373
374 self.controller.message_send(msg)
375 do_barrier(self.controller)
376 verify_no_errors(self.controller)
377
378
379class GroupDeleteAll(GroupTest):
380 """
381 A deletion for OFPG_ALL should remove all groups
382 """
383
384 def runTest(self):
385 port1, = openflow_ports(1)
386
387 msg = ofp.message.group_mod(
388 command=ofp.OFPGC_ADD,
389 group_type=ofp.OFPGT_ALL,
390 group_id=0,
391 buckets=[
392 ofp.bucket(actions=[ofp.action.output(port1)])])
393
394 self.controller.message_send(msg)
395 do_barrier(self.controller)
396
397 msg = ofp.message.group_mod(
398 command=ofp.OFPGC_ADD,
399 group_type=ofp.OFPGT_ALL,
400 group_id=1,
401 buckets=[
402 ofp.bucket(actions=[ofp.action.output(port1)])])
403
404 self.controller.message_send(msg)
405 do_barrier(self.controller)
406
407 msg = ofp.message.group_mod(
408 command=ofp.OFPGC_DELETE,
409 group_id=ofp.OFPG_ALL)
410
411 self.controller.message_send(msg)
412 do_barrier(self.controller)
413
414 stats = get_stats(self, ofp.message.group_desc_stats_request())
415 self.assertEquals(stats, [])
416
417
418class GroupAddAllWeight(GroupTest):
419 """
420 An ALL group with weights for buckets should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
421 """
422
423 def runTest(self):
424 port1, port2, = openflow_ports(2)
425
426 msg = ofp.message.group_mod(
427 command=ofp.OFPGC_ADD,
428 group_type=ofp.OFPGT_ALL,
429 group_id=0,
430 buckets=[
431 ofp.bucket(weight=1, actions=[ofp.action.output(port1)]),
432 ofp.bucket(weight=2, actions=[ofp.action.output(port2)])])
433
434 response, _ = self.controller.transact(msg)
435 self.assertIsInstance(response, ofp.message.error_msg)
436 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
437 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
438
439
440class GroupAddIndirectWeight(GroupTest):
441 """
442 An INDIRECT group with weights for buckets should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
443 """
444
445 def runTest(self):
446 port1, = openflow_ports(1)
447
448 msg = ofp.message.group_mod(
449 command=ofp.OFPGC_ADD,
450 group_type=ofp.OFPGT_INDIRECT,
451 group_id=0,
452 buckets=[
453 ofp.bucket(weight=1, actions=[ofp.action.output(port1)])])
454
455 response, _ = self.controller.transact(msg)
456 self.assertIsInstance(response, ofp.message.error_msg)
457 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
458 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
459
460
461class GroupAddIndirectBuckets(GroupTest):
462 """
463 An INDIRECT group with <>1 bucket should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
464 """
465
466 def runTest(self):
467 port1, port2, = openflow_ports(2)
468
469 msg = ofp.message.group_mod(
470 command=ofp.OFPGC_ADD,
471 group_type=ofp.OFPGT_INDIRECT,
472 group_id=0,
473 buckets=[
474 ofp.bucket(actions=[ofp.action.output(port1)]),
475 ofp.bucket(actions=[ofp.action.output(port2)])])
476
477 response, _ = self.controller.transact(msg)
478 self.assertIsInstance(response, ofp.message.error_msg)
479 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
480 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
481
482
483class GroupAddSelectNoWeight(GroupTest):
484 """
485 A SELECT group with ==0 weights should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
486 """
487
488 def runTest(self):
489 port1, port2, = openflow_ports(2)
490
491 msg = ofp.message.group_mod(
492 command=ofp.OFPGC_ADD,
493 group_type=ofp.OFPGT_SELECT,
494 group_id=0,
495 buckets=[
496 ofp.bucket(actions=[ofp.action.output(port1)]),
497 ofp.bucket(actions=[ofp.action.output(port2)])])
498
499 response, _ = self.controller.transact(msg)
500 self.assertIsInstance(response, ofp.message.error_msg)
501 self.assertEquals(response.err_type, ofp.OFPET_GROUP_MOD_FAILED)
502 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
503
504
505class GroupStats(GroupTest):
506 """
507 A group stats request should return an entry for the specified group
508 """
509
510 def runTest(self):
511 port1, port2, = openflow_ports(2)
512
513 msg = ofp.message.group_mod(
514 command=ofp.OFPGC_ADD,
515 group_type=ofp.OFPGT_ALL,
516 group_id=10,
517 buckets=[
518 ofp.bucket(actions=[
519 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
520 ofp.action.output(port1)]),
521 ofp.bucket(actions=[
522 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
523 ofp.action.output(port2)])])
524
525 self.controller.message_send(msg)
526 do_barrier(self.controller)
527
528 request = ofp.message.group_stats_request(group_id=10)
529 stats = get_stats(self, request)
530
531 self.assertEquals(len(stats), 1)
532 self.assertEquals(stats[0].group_id, 10)
533 self.assertEquals(stats[0].ref_count, 0)
534 self.assertEquals(stats[0].packet_count, 0)
535 self.assertEquals(stats[0].byte_count, 0)
536 self.assertEquals(len(stats[0].bucket_stats), 2)
537
538
539class GroupStatsNonexistent(GroupTest):
540 """
541 A group stats request for a nonexistent group should return an empty list
542 """
543
544 def runTest(self):
545 request = ofp.message.group_stats_request(group_id=10)
546 stats = get_stats(self, request)
547 self.assertEquals(len(stats), 0)
548
549
550class GroupStatsAll(GroupTest):
551 """
552 A group stats request with OFPG_ALL should return an entry for each group
553 """
554
555 def runTest(self):
556 port1, port2, = openflow_ports(2)
557
558 msg0 = ofp.message.group_mod(
559 command=ofp.OFPGC_ADD,
560 group_type=ofp.OFPGT_ALL,
561 group_id=0,
562 buckets=[
563 ofp.bucket(actions=[
564 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
565 ofp.action.output(port1)]),
566 ofp.bucket(actions=[
567 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
568 ofp.action.output(port2)])])
569
570 self.controller.message_send(msg0)
571 do_barrier(self.controller)
572
573 msg1 = ofp.message.group_mod(
574 command=ofp.OFPGC_ADD,
575 group_type=ofp.OFPGT_ALL,
576 group_id=1,
577 buckets=[
578 ofp.bucket(actions=[
579 ofp.action.set_field(ofp.oxm.tcp_src(2001)),
580 ofp.action.output(port1)]),
581 ofp.bucket(actions=[
582 ofp.action.set_field(ofp.oxm.tcp_src(3001)),
583 ofp.action.output(port2)])])
584
585 self.controller.message_send(msg1)
586 do_barrier(self.controller)
587
588 request = ofp.message.group_stats_request(group_id=ofp.OFPG_ALL)
589 stats = sorted(get_stats(self, request), key=lambda x: x.group_id)
590
591 self.assertEquals(len(stats), 2)
592
593 self.assertEquals(stats[0].group_id, 0)
594 self.assertEquals(stats[0].ref_count, 0)
595 self.assertEquals(stats[0].packet_count, 0)
596 self.assertEquals(stats[0].byte_count, 0)
597 self.assertEquals(len(stats[0].bucket_stats), 2)
598
599 self.assertEquals(stats[1].group_id, 1)
600 self.assertEquals(stats[1].ref_count, 0)
601 self.assertEquals(stats[1].packet_count, 0)
602 self.assertEquals(stats[1].byte_count, 0)
603 self.assertEquals(len(stats[1].bucket_stats), 2)
604
605
606class GroupDescStats(GroupTest):
607 """
608 A group desc stats request should return the type, id, and buckets for each group
609 """
610
611 def runTest(self):
612 port1, port2, port3, = openflow_ports(3)
613
614 msg0 = ofp.message.group_mod(
615 command=ofp.OFPGC_ADD,
616 group_type=ofp.OFPGT_ALL,
617 group_id=0,
618 buckets=[
619 ofp.bucket(actions=[
620 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
621 ofp.action.output(port1)]),
622 ofp.bucket(actions=[
623 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
624 ofp.action.output(port2)]),
625 ofp.bucket(actions=[
626 ofp.action.set_field(ofp.oxm.tcp_src(4000)),
627 ofp.action.output(port3)])])
628
629 self.controller.message_send(msg0)
630 do_barrier(self.controller)
631
632 msg1 = ofp.message.group_mod(
633 command=ofp.OFPGC_ADD,
634 group_type=ofp.OFPGT_SELECT,
635 group_id=1,
636 buckets=[
637 ofp.bucket(
638 weight=1,
639 actions=[
640 ofp.action.set_field(ofp.oxm.tcp_src(2001)),
641 ofp.action.output(port1)]),
642 ofp.bucket(
643 weight=2,
644 actions=[
645 ofp.action.set_field(ofp.oxm.tcp_src(3001)),
646 ofp.action.output(port2)]),
647 ofp.bucket(
648 weight=3,
649 actions=[
650 ofp.action.set_field(ofp.oxm.tcp_src(4001)),
651 ofp.action.output(port3)])])
652
653 self.controller.message_send(msg1)
654 do_barrier(self.controller)
655
656 msg2 = ofp.message.group_mod(
657 command=ofp.OFPGC_ADD,
658 group_type=ofp.OFPGT_FF,
659 group_id=2,
660 buckets=[
661 ofp.bucket(
662 watch_port=port1,
663 actions=[
664 ofp.action.set_field(ofp.oxm.tcp_src(2002)),
665 ofp.action.output(port1)]),
666 ofp.bucket(
667 watch_port=port2,
668 actions=[
669 ofp.action.set_field(ofp.oxm.tcp_src(3002)),
670 ofp.action.output(port2,)]),
671 ofp.bucket(
672 watch_port=port3,
673 actions=[
674 ofp.action.set_field(ofp.oxm.tcp_src(4002)),
675 ofp.action.output(port3,)])])
676
677 self.controller.message_send(msg2)
678 do_barrier(self.controller)
679
680 request = ofp.message.group_desc_stats_request()
681 stats = sorted(get_stats(self, request), key=lambda x: x.group_id)
682
683 self.assertEquals(len(stats), 3)
684
685 self.assertEquals(stats[0].group_id, msg0.group_id)
686 self.assertEquals(stats[0].type, msg0.group_type)
687 self.assertEquals(stats[0].buckets, msg0.buckets)
688
689 self.assertEquals(stats[1].group_id, msg1.group_id)
690 self.assertEquals(stats[1].type, msg1.group_type)
691 self.assertEquals(stats[1].buckets, msg1.buckets)
692
693 self.assertEquals(stats[2].group_id, msg2.group_id)
694 self.assertEquals(stats[2].type, msg2.group_type)
695 self.assertEquals(stats[2].buckets, msg2.buckets)
696
697
698class GroupFlowSelect(GroupTest):
699 """
700 A flow stats request qualified on group id should select the correct flows
701 """
702
703 def runTest(self):
704 port1, = openflow_ports(1)
705
706 msg = ofp.message.group_mod(
707 command=ofp.OFPGC_ADD,
708 group_type=ofp.OFPGT_ALL,
709 group_id=1,
710 buckets=[])
711
712 self.controller.message_send(msg)
713 do_barrier(self.controller)
714
715 msg = ofp.message.group_mod(
716 command=ofp.OFPGC_ADD,
717 group_type=ofp.OFPGT_ALL,
718 group_id=2,
719 buckets=[])
720
721 self.controller.message_send(msg)
722 do_barrier(self.controller)
723
724 packet_in1 = simple_tcp_packet(tcp_sport=1000)
725
726 flow_add_msg1 = flow_msg_create(
727 self,
728 packet_in1,
729 ing_port=1,
730 action_list=[
731 ofp.action.group(1),
732 ofp.action.output(port1)])
733
734 self.controller.message_send(flow_add_msg1)
735 do_barrier(self.controller)
736
737 packet_in2 = simple_tcp_packet(tcp_sport=2000)
738
739 flow_add_msg2 = flow_msg_create(
740 self,
741 packet_in2,
742 ing_port=1,
743 action_list=[
744 ofp.action.group(2),
745 ofp.action.output(port1)])
746
747 self.controller.message_send(flow_add_msg2)
748 do_barrier(self.controller)
749
750 packet_in3 = simple_tcp_packet(tcp_sport=3000)
751
752 flow_add_msg3 = flow_msg_create(
753 self,
754 packet_in3,
755 ing_port=1,
756 action_list=[
757 ofp.action.group(2),
758 ofp.action.output(port1)])
759
760 self.controller.message_send(flow_add_msg3)
761 do_barrier(self.controller)
762
763 packet_in4 = simple_tcp_packet(tcp_sport=4000)
764
765 flow_add_msg4 = flow_msg_create(
766 self,
767 packet_in4,
768 ing_port=1,
769 action_list=[
770 ofp.action.output(port1)])
771
772 self.controller.message_send(flow_add_msg4)
773 do_barrier(self.controller)
774
775 request = ofp.message.aggregate_stats_request(
776 table_id=ofp.OFPTT_ALL,
777 out_port=ofp.OFPP_ANY,
778 out_group=2)
779
780 response, _ = self.controller.transact(request)
781
782 self.assertEqual(response.flow_count, 2,
783 'Did not match expected flow count')
Rich Lane7b1b1b82013-10-18 13:44:59 -0700784
785
786class SelectFwdEmpty(GroupTest):
787 """
788 A SELECT group with no buckets should not alter the action set of the packet
789 """
790
791 def runTest(self):
792 port1, port2 = openflow_ports(2)
793
794 msg = ofp.message.group_mod(
795 command=ofp.OFPGC_ADD,
796 group_type=ofp.OFPGT_SELECT,
797 group_id=1,
798 buckets=[])
799
800 self.controller.message_send(msg)
801 do_barrier(self.controller)
802
803 msg = ofp.message.flow_add(
804 buffer_id=ofp.OFP_NO_BUFFER,
805 instructions=[
806 ofp.instruction.apply_actions(
807 [ofp.action.output(2), ofp.action.group(1)])])
808
809 self.controller.message_send(msg)
810 do_barrier(self.controller)
811
812 verify_no_errors(self.controller)
813
814 pkt = simple_tcp_packet()
815 self.dataplane.send(port1, str(pkt))
816 verify_packets(self, pkt, [port2])
817
818
819class SelectFwdSingle(GroupTest):
820 """
821 A SELECT group with a single bucket should use that bucket's actions
822 """
823
824 def runTest(self):
825 port1, port2 = openflow_ports(2)
826
827 msg = ofp.message.group_mod(
828 command=ofp.OFPGC_ADD,
829 group_type=ofp.OFPGT_SELECT,
830 group_id=1,
831 buckets=[
832 ofp.bucket(weight=1, actions=[ofp.action.output(port2)])])
833
834 self.controller.message_send(msg)
835 do_barrier(self.controller)
836
837 msg = ofp.message.flow_add(
838 buffer_id=ofp.OFP_NO_BUFFER,
839 instructions=[ofp.instruction.apply_actions([ofp.action.group(1)])])
840
841 self.controller.message_send(msg)
842 do_barrier(self.controller)
843
844 verify_no_errors(self.controller)
845
846 pkt = simple_tcp_packet()
847 self.dataplane.send(port1, str(pkt))
848 verify_packets(self, pkt, [port2])
849
850
851class SelectFwdSpread(GroupTest):
852 """
853 A SELECT group with several buckets should spead different flows between them
854 """
855
856 def runTest(self):
857 num_out_ports = 3
858 num_pkts = 1000
859
860 port1, port2, port3, port4 = openflow_ports(num_out_ports + 1)
861 out_ports = [port2, port3, port4]
862
863 msg = ofp.message.group_mod(
864 command=ofp.OFPGC_ADD,
865 group_type=ofp.OFPGT_SELECT,
866 group_id=1,
867 buckets=[
868 ofp.bucket(weight=1, actions=[ofp.action.output(port)])
869 for port in out_ports])
870
871 self.controller.message_send(msg)
872 do_barrier(self.controller)
873
874 msg = ofp.message.flow_add(
875 buffer_id=ofp.OFP_NO_BUFFER,
876 instructions=[ofp.instruction.apply_actions([ofp.action.group(1)])])
877
878 self.controller.message_send(msg)
879 do_barrier(self.controller)
880
881 verify_no_errors(self.controller)
882
883 counters = { x: 0 for x in out_ports }
884
885 for i in xrange(0, num_pkts):
886 pkt = simple_tcp_packet(tcp_sport=i, tcp_dport=random.randint(0, 65535))
887 self.dataplane.send(port1, str(pkt))
888 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=str(pkt))
889 self.assertIsNotNone(rcv_pkt)
890 if rcv_port not in counters:
891 raise AssertionError("unexpected packet on port %d" % rcv_port)
892 counters[rcv_port] += 1
893
894 # Verify the same flow is mapped to the same output port
895 self.dataplane.send(port1, str(pkt))
896 (rcv_port2, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=str(pkt))
897 self.assertIsNotNone(rcv_pkt)
898 self.assertEquals(rcv_port, rcv_port2)
899
900 logging.debug("Distribution: %r" ,counters)
901
902 self.assertEquals(sum(counters.values()), num_pkts)
903 expected = num_pkts/num_out_ports
904 for port, count in counters.iteritems():
905 # Check that count is within 20% of expected
906 self.assertTrue(expected * 0.8 < count < expected * 1.2,
907 "port %d count was %d, expected %d" % (port, count, expected))