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