blob: 41673a5c10a2c97c0b9cf30f0ed345a5934d0152 [file] [log] [blame]
Matteo Scandoloa229eca2017-08-08 13:05:28 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Rich Lane89e12652013-10-10 17:26:25 -070017# Distributed under the OpenFlow Software License (see LICENSE)
18# Copyright (c) 2010 The Board of Trustees of The Leland Stanford Junior University
19# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
20# Copyright (c) 2012, 2013 CPqD
21# Copyright (c) 2012, 2013 Ericsson
22"""
23Group table test cases.
24"""
25
26import logging
Rich Lane7b1b1b82013-10-18 13:44:59 -070027import random
Rich Lane89e12652013-10-10 17:26:25 -070028
29from oftest import config
30import oftest
31import oftest.base_tests as base_tests
32import ofp
33
34from oftest.testutils import *
35
36class GroupTest(base_tests.SimpleDataPlane):
37 def setUp(self):
38 base_tests.SimpleDataPlane.setUp(self)
39 delete_all_flows(self.controller)
40 delete_all_groups(self.controller)
41
42
43class GroupAdd(GroupTest):
44 """
45 A regular group should be added successfully
46 """
47
48 def runTest(self):
49 port1, = openflow_ports(1)
50
Rich Lane8be7a282013-11-22 14:21:00 -080051 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -070052 group_type=ofp.OFPGT_ALL,
53 group_id=0,
54 buckets=[
55 ofp.bucket(actions=[ofp.action.output(port1)])])
56
57 self.controller.message_send(msg)
58 do_barrier(self.controller)
59
60 stats = get_stats(self, ofp.message.group_desc_stats_request())
61 self.assertEquals(stats, [
62 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -070063 group_type=msg.group_type,
Rich Lane89e12652013-10-10 17:26:25 -070064 group_id=msg.group_id,
65 buckets=msg.buckets)])
66
67
Rich Laned9ea8ac2013-10-15 10:43:55 -070068class GroupAddMaxID(GroupTest):
69 """
70 A group with ID OFPG_MAX should be added successfully
71 """
72
73 def runTest(self):
74 port1, = openflow_ports(1)
75
Rich Lane8be7a282013-11-22 14:21:00 -080076 msg = ofp.message.group_add(
Rich Laned9ea8ac2013-10-15 10:43:55 -070077 group_type=ofp.OFPGT_ALL,
78 group_id=ofp.OFPG_MAX,
79 buckets=[
80 ofp.bucket(actions=[ofp.action.output(port1)])])
81
82 self.controller.message_send(msg)
83 do_barrier(self.controller)
84
85 stats = get_stats(self, ofp.message.group_desc_stats_request())
86 self.assertEquals(stats, [
87 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -070088 group_type=msg.group_type,
Rich Laned9ea8ac2013-10-15 10:43:55 -070089 group_id=msg.group_id,
90 buckets=msg.buckets)])
91
92
Rich Lane89e12652013-10-10 17:26:25 -070093class GroupAddInvalidAction(GroupTest):
94 """
95 If any action in the buckets is invalid, OFPET_BAD_ACTION/<code> should be returned
96 """
97
98 def runTest(self):
Rich Lane8be7a282013-11-22 14:21:00 -080099 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700100 group_type=ofp.OFPGT_ALL,
101 group_id=0,
102 buckets=[
103 ofp.bucket(actions=[ofp.action.output(ofp.OFPP_ANY)])])
104
105 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700106 self.assertIsInstance(response, ofp.message.bad_action_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700107 self.assertEquals(response.code, ofp.OFPBAC_BAD_OUT_PORT)
108
109
110class GroupAddExisting(GroupTest):
111 """
112 An addition with existing group id should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_GROUP_EXISTS
113 """
114
115 def runTest(self):
116 port1, port2, = openflow_ports(2)
117
Rich Lane8be7a282013-11-22 14:21:00 -0800118 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700119 group_type=ofp.OFPGT_ALL,
120 group_id=0,
121 buckets=[
122 ofp.bucket(actions=[ofp.action.output(port1)])])
123
124 self.controller.message_send(msg)
125 do_barrier(self.controller)
126
Rich Lane8be7a282013-11-22 14:21:00 -0800127 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700128 group_type=ofp.OFPGT_ALL,
129 group_id=0,
130 buckets=[
131 ofp.bucket(actions=[ofp.action.output(port2)])])
132
133 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700134 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700135 self.assertEquals(response.code, ofp.OFPGMFC_GROUP_EXISTS)
136
137
138class GroupAddInvalidID(GroupTest):
139 """
140 An addition with invalid group id (reserved) should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
141 """
142
143 def runTest(self):
144 port1, = openflow_ports(1)
145
Rich Lane8be7a282013-11-22 14:21:00 -0800146 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700147 group_type=ofp.OFPGT_ALL,
148 group_id=ofp.OFPG_ALL,
149 buckets=[
150 ofp.bucket(actions=[ofp.action.output(port1)])])
151
152 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700153 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700154 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
155
156
Rich Laned9ea8ac2013-10-15 10:43:55 -0700157class GroupAddMinimumInvalidID(GroupTest):
158 """
159 An addition with invalid group id (reserved) should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
160 """
161
162 def runTest(self):
163 port1, = openflow_ports(1)
164
Rich Lane8be7a282013-11-22 14:21:00 -0800165 msg = ofp.message.group_add(
Rich Laned9ea8ac2013-10-15 10:43:55 -0700166 group_type=ofp.OFPGT_ALL,
167 group_id=ofp.OFPG_MAX+1,
168 buckets=[
169 ofp.bucket(actions=[ofp.action.output(port1)])])
170
171 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700172 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Laned9ea8ac2013-10-15 10:43:55 -0700173 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
174
175
Rich Lane89e12652013-10-10 17:26:25 -0700176class GroupModify(GroupTest):
177 """
178 A regular group modification should be successful
179 """
180
181 def runTest(self):
182 port1, port2, = openflow_ports(2)
183
Rich Lane8be7a282013-11-22 14:21:00 -0800184 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700185 group_type=ofp.OFPGT_ALL,
186 group_id=0,
187 buckets=[
188 ofp.bucket(actions=[ofp.action.output(port1)])])
189
190 self.controller.message_send(msg)
191 do_barrier(self.controller)
192
Rich Lane8be7a282013-11-22 14:21:00 -0800193 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700194 group_type=ofp.OFPGT_ALL,
195 group_id=0,
196 buckets=[
197 ofp.bucket(actions=[ofp.action.output(port2)])])
198
199 self.controller.message_send(msg)
200 do_barrier(self.controller)
201
202 stats = get_stats(self, ofp.message.group_desc_stats_request())
203 self.assertEquals(stats, [
204 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -0700205 group_type=msg.group_type,
Rich Lane89e12652013-10-10 17:26:25 -0700206 group_id=msg.group_id,
207 buckets=msg.buckets)])
208
209
210class GroupModifyNonexisting(GroupTest):
211 """
212 A modification for a non-existing group should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_UNKNOWN_GROUP
213 """
214
215 def runTest(self):
216 port1, = openflow_ports(1)
217
Rich Lane8be7a282013-11-22 14:21:00 -0800218 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700219 group_type=ofp.OFPGT_ALL,
220 group_id=0,
221 buckets=[
222 ofp.bucket(actions=[ofp.action.output(port1)])])
223
224 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700225 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700226 self.assertEquals(response.code, ofp.OFPGMFC_UNKNOWN_GROUP)
227
228
229class GroupModifyLoop(GroupTest):
230 """
231 A modification causing loop should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_LOOP
232 """
233
234 def runTest(self):
235 port1, = openflow_ports(1)
236
Rich Lane8be7a282013-11-22 14:21:00 -0800237 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700238 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
Rich Lane8be7a282013-11-22 14:21:00 -0800246 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700247 group_type=ofp.OFPGT_ALL,
248 group_id=1,
249 buckets=[
250 ofp.bucket(actions=[ofp.action.group(0)])])
251
252 self.controller.message_send(msg)
253 do_barrier(self.controller)
254
Rich Lane8be7a282013-11-22 14:21:00 -0800255 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700256 group_type=ofp.OFPGT_ALL,
257 group_id=2,
258 buckets=[
259 ofp.bucket(actions=[ofp.action.group(1)])])
260
261 self.controller.message_send(msg)
262 do_barrier(self.controller)
263
Rich Lane8be7a282013-11-22 14:21:00 -0800264 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700265 group_type=ofp.OFPGT_ALL,
266 group_id=0,
267 buckets=[
268 ofp.bucket(actions=[ofp.action.group(2)])])
269
270 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700271 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700272 self.assertEquals(response.code, ofp.OFPGMFC_LOOP)
273
274
275class GroupModifyInvalidID(GroupTest):
276 """
277 A modification for a reserved group should result in OFPET_GROUP_MOD_FAILED/OFPGMFC_INVALID_GROUP
278 """
279
280 def runTest(self):
281 port1, = openflow_ports(1)
282
Rich Lane8be7a282013-11-22 14:21:00 -0800283 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700284 group_type=ofp.OFPGT_ALL,
285 group_id=ofp.OFPG_ALL,
286 buckets=[
287 ofp.bucket(actions=[ofp.action.output(port1)])])
288
289 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700290 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700291 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
292
293
294class GroupModifyEmpty(GroupTest):
295 """
296 A modification for an existing group with no buckets should be accepted
297 """
298
299 def runTest(self):
300 port1, = openflow_ports(1)
301
Rich Lane8be7a282013-11-22 14:21:00 -0800302 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700303 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
Rich Lane8be7a282013-11-22 14:21:00 -0800311 msg = ofp.message.group_modify(
Rich Lane89e12652013-10-10 17:26:25 -0700312 group_type=ofp.OFPGT_ALL,
313 group_id=0,
314 buckets=[])
315
316 self.controller.message_send(msg)
317 do_barrier(self.controller)
318
319 stats = get_stats(self, ofp.message.group_desc_stats_request())
320 self.assertEquals(stats, [
321 ofp.group_desc_stats_entry(
Rich Lane3f71b812013-10-21 06:18:37 -0700322 group_type=msg.group_type,
Rich Lane89e12652013-10-10 17:26:25 -0700323 group_id=msg.group_id,
324 buckets=msg.buckets)])
325
326
327class GroupDeleteExisting(GroupTest):
328 """
329 A deletion for an existing group should remove the group
330 """
331
332 def runTest(self):
333 port1, = openflow_ports(1)
334
Rich Lane8be7a282013-11-22 14:21:00 -0800335 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700336 group_type=ofp.OFPGT_ALL,
337 group_id=0,
338 buckets=[
339 ofp.bucket(actions=[ofp.action.output(port1)])])
340
341 self.controller.message_send(msg)
342 do_barrier(self.controller)
343
Rich Lane8be7a282013-11-22 14:21:00 -0800344 msg = ofp.message.group_delete(group_id=0)
Rich Lane89e12652013-10-10 17:26:25 -0700345
346 self.controller.message_send(msg)
347 do_barrier(self.controller)
348
349 stats = get_stats(self, ofp.message.group_desc_stats_request())
350 self.assertEquals(stats, [])
351
352
353class GroupDeleteNonexisting(GroupTest):
354 """
355 A deletion for nonexisting group should result in no error
356 """
357
358 def runTest(self):
Rich Lane8be7a282013-11-22 14:21:00 -0800359 msg = ofp.message.group_delete(group_id=0)
Rich Lane89e12652013-10-10 17:26:25 -0700360
361 self.controller.message_send(msg)
362 do_barrier(self.controller)
363 verify_no_errors(self.controller)
364
365
366class GroupDeleteAll(GroupTest):
367 """
368 A deletion for OFPG_ALL should remove all groups
369 """
370
371 def runTest(self):
372 port1, = openflow_ports(1)
373
Rich Lane8be7a282013-11-22 14:21:00 -0800374 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700375 group_type=ofp.OFPGT_ALL,
376 group_id=0,
377 buckets=[
378 ofp.bucket(actions=[ofp.action.output(port1)])])
379
380 self.controller.message_send(msg)
381 do_barrier(self.controller)
382
Rich Lane8be7a282013-11-22 14:21:00 -0800383 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700384 group_type=ofp.OFPGT_ALL,
385 group_id=1,
386 buckets=[
387 ofp.bucket(actions=[ofp.action.output(port1)])])
388
389 self.controller.message_send(msg)
390 do_barrier(self.controller)
391
Rich Lane8be7a282013-11-22 14:21:00 -0800392 msg = ofp.message.group_delete(group_id=ofp.OFPG_ALL)
Rich Lane89e12652013-10-10 17:26:25 -0700393
394 self.controller.message_send(msg)
395 do_barrier(self.controller)
396
397 stats = get_stats(self, ofp.message.group_desc_stats_request())
398 self.assertEquals(stats, [])
399
400
401class GroupAddAllWeight(GroupTest):
402 """
403 An ALL group with weights for buckets should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
404 """
405
406 def runTest(self):
407 port1, port2, = openflow_ports(2)
408
Rich Lane8be7a282013-11-22 14:21:00 -0800409 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700410 group_type=ofp.OFPGT_ALL,
411 group_id=0,
412 buckets=[
413 ofp.bucket(weight=1, actions=[ofp.action.output(port1)]),
414 ofp.bucket(weight=2, actions=[ofp.action.output(port2)])])
415
416 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700417 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700418 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
419
420
421class GroupAddIndirectWeight(GroupTest):
422 """
423 An INDIRECT group with weights for buckets should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
424 """
425
426 def runTest(self):
427 port1, = openflow_ports(1)
428
Rich Lane8be7a282013-11-22 14:21:00 -0800429 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700430 group_type=ofp.OFPGT_INDIRECT,
431 group_id=0,
432 buckets=[
433 ofp.bucket(weight=1, actions=[ofp.action.output(port1)])])
434
435 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700436 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700437 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
438
439
440class GroupAddIndirectBuckets(GroupTest):
441 """
442 An INDIRECT group with <>1 bucket should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
443 """
444
445 def runTest(self):
446 port1, port2, = openflow_ports(2)
447
Rich Lane8be7a282013-11-22 14:21:00 -0800448 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700449 group_type=ofp.OFPGT_INDIRECT,
450 group_id=0,
451 buckets=[
452 ofp.bucket(actions=[ofp.action.output(port1)]),
453 ofp.bucket(actions=[ofp.action.output(port2)])])
454
455 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700456 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700457 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
458
459
460class GroupAddSelectNoWeight(GroupTest):
461 """
462 A SELECT group with ==0 weights should result in OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP
463 """
464
465 def runTest(self):
466 port1, port2, = openflow_ports(2)
467
Rich Lane8be7a282013-11-22 14:21:00 -0800468 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700469 group_type=ofp.OFPGT_SELECT,
470 group_id=0,
471 buckets=[
472 ofp.bucket(actions=[ofp.action.output(port1)]),
473 ofp.bucket(actions=[ofp.action.output(port2)])])
474
475 response, _ = self.controller.transact(msg)
Rich Lanee226f042013-10-21 06:22:03 -0700476 self.assertIsInstance(response, ofp.message.group_mod_failed_error_msg)
Rich Lane89e12652013-10-10 17:26:25 -0700477 self.assertEquals(response.code, ofp.OFPGMFC_INVALID_GROUP)
478
479
480class GroupStats(GroupTest):
481 """
482 A group stats request should return an entry for the specified group
483 """
484
485 def runTest(self):
486 port1, port2, = openflow_ports(2)
487
Rich Lane8be7a282013-11-22 14:21:00 -0800488 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700489 group_type=ofp.OFPGT_ALL,
490 group_id=10,
491 buckets=[
492 ofp.bucket(actions=[
493 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
494 ofp.action.output(port1)]),
495 ofp.bucket(actions=[
496 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
497 ofp.action.output(port2)])])
498
499 self.controller.message_send(msg)
500 do_barrier(self.controller)
501
502 request = ofp.message.group_stats_request(group_id=10)
503 stats = get_stats(self, request)
504
505 self.assertEquals(len(stats), 1)
506 self.assertEquals(stats[0].group_id, 10)
507 self.assertEquals(stats[0].ref_count, 0)
508 self.assertEquals(stats[0].packet_count, 0)
509 self.assertEquals(stats[0].byte_count, 0)
510 self.assertEquals(len(stats[0].bucket_stats), 2)
511
512
513class GroupStatsNonexistent(GroupTest):
514 """
515 A group stats request for a nonexistent group should return an empty list
516 """
517
518 def runTest(self):
519 request = ofp.message.group_stats_request(group_id=10)
520 stats = get_stats(self, request)
521 self.assertEquals(len(stats), 0)
522
523
524class GroupStatsAll(GroupTest):
525 """
526 A group stats request with OFPG_ALL should return an entry for each group
527 """
528
529 def runTest(self):
530 port1, port2, = openflow_ports(2)
531
Rich Lane8be7a282013-11-22 14:21:00 -0800532 msg0 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700533 group_type=ofp.OFPGT_ALL,
534 group_id=0,
535 buckets=[
536 ofp.bucket(actions=[
537 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
538 ofp.action.output(port1)]),
539 ofp.bucket(actions=[
540 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
541 ofp.action.output(port2)])])
542
543 self.controller.message_send(msg0)
544 do_barrier(self.controller)
545
Rich Lane8be7a282013-11-22 14:21:00 -0800546 msg1 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700547 group_type=ofp.OFPGT_ALL,
548 group_id=1,
549 buckets=[
550 ofp.bucket(actions=[
551 ofp.action.set_field(ofp.oxm.tcp_src(2001)),
552 ofp.action.output(port1)]),
553 ofp.bucket(actions=[
554 ofp.action.set_field(ofp.oxm.tcp_src(3001)),
555 ofp.action.output(port2)])])
556
557 self.controller.message_send(msg1)
558 do_barrier(self.controller)
559
560 request = ofp.message.group_stats_request(group_id=ofp.OFPG_ALL)
561 stats = sorted(get_stats(self, request), key=lambda x: x.group_id)
562
563 self.assertEquals(len(stats), 2)
564
565 self.assertEquals(stats[0].group_id, 0)
566 self.assertEquals(stats[0].ref_count, 0)
567 self.assertEquals(stats[0].packet_count, 0)
568 self.assertEquals(stats[0].byte_count, 0)
569 self.assertEquals(len(stats[0].bucket_stats), 2)
570
571 self.assertEquals(stats[1].group_id, 1)
572 self.assertEquals(stats[1].ref_count, 0)
573 self.assertEquals(stats[1].packet_count, 0)
574 self.assertEquals(stats[1].byte_count, 0)
575 self.assertEquals(len(stats[1].bucket_stats), 2)
576
577
578class GroupDescStats(GroupTest):
579 """
580 A group desc stats request should return the type, id, and buckets for each group
581 """
582
583 def runTest(self):
584 port1, port2, port3, = openflow_ports(3)
585
Rich Lane8be7a282013-11-22 14:21:00 -0800586 msg0 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700587 group_type=ofp.OFPGT_ALL,
588 group_id=0,
589 buckets=[
590 ofp.bucket(actions=[
591 ofp.action.set_field(ofp.oxm.tcp_src(2000)),
592 ofp.action.output(port1)]),
593 ofp.bucket(actions=[
594 ofp.action.set_field(ofp.oxm.tcp_src(3000)),
595 ofp.action.output(port2)]),
596 ofp.bucket(actions=[
597 ofp.action.set_field(ofp.oxm.tcp_src(4000)),
598 ofp.action.output(port3)])])
599
600 self.controller.message_send(msg0)
601 do_barrier(self.controller)
602
Rich Lane8be7a282013-11-22 14:21:00 -0800603 msg1 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700604 group_type=ofp.OFPGT_SELECT,
605 group_id=1,
606 buckets=[
607 ofp.bucket(
608 weight=1,
609 actions=[
610 ofp.action.set_field(ofp.oxm.tcp_src(2001)),
611 ofp.action.output(port1)]),
612 ofp.bucket(
613 weight=2,
614 actions=[
615 ofp.action.set_field(ofp.oxm.tcp_src(3001)),
616 ofp.action.output(port2)]),
617 ofp.bucket(
618 weight=3,
619 actions=[
620 ofp.action.set_field(ofp.oxm.tcp_src(4001)),
621 ofp.action.output(port3)])])
622
623 self.controller.message_send(msg1)
624 do_barrier(self.controller)
625
Rich Lane8be7a282013-11-22 14:21:00 -0800626 msg2 = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700627 group_type=ofp.OFPGT_FF,
628 group_id=2,
629 buckets=[
630 ofp.bucket(
631 watch_port=port1,
632 actions=[
633 ofp.action.set_field(ofp.oxm.tcp_src(2002)),
634 ofp.action.output(port1)]),
635 ofp.bucket(
636 watch_port=port2,
637 actions=[
638 ofp.action.set_field(ofp.oxm.tcp_src(3002)),
639 ofp.action.output(port2,)]),
640 ofp.bucket(
641 watch_port=port3,
642 actions=[
643 ofp.action.set_field(ofp.oxm.tcp_src(4002)),
644 ofp.action.output(port3,)])])
645
646 self.controller.message_send(msg2)
647 do_barrier(self.controller)
648
649 request = ofp.message.group_desc_stats_request()
650 stats = sorted(get_stats(self, request), key=lambda x: x.group_id)
651
652 self.assertEquals(len(stats), 3)
653
654 self.assertEquals(stats[0].group_id, msg0.group_id)
Rich Lane165332d2014-07-30 14:27:44 -0700655 self.assertEquals(stats[0].group_type, msg0.group_type)
Rich Lane89e12652013-10-10 17:26:25 -0700656 self.assertEquals(stats[0].buckets, msg0.buckets)
657
658 self.assertEquals(stats[1].group_id, msg1.group_id)
Rich Lane165332d2014-07-30 14:27:44 -0700659 self.assertEquals(stats[1].group_type, msg1.group_type)
Rich Lane89e12652013-10-10 17:26:25 -0700660 self.assertEquals(stats[1].buckets, msg1.buckets)
661
662 self.assertEquals(stats[2].group_id, msg2.group_id)
Rich Lane165332d2014-07-30 14:27:44 -0700663 self.assertEquals(stats[2].group_type, msg2.group_type)
Rich Lane89e12652013-10-10 17:26:25 -0700664 self.assertEquals(stats[2].buckets, msg2.buckets)
665
666
667class GroupFlowSelect(GroupTest):
668 """
669 A flow stats request qualified on group id should select the correct flows
670 """
671
672 def runTest(self):
673 port1, = openflow_ports(1)
674
Rich Lane8be7a282013-11-22 14:21:00 -0800675 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700676 group_type=ofp.OFPGT_ALL,
677 group_id=1,
678 buckets=[])
679
680 self.controller.message_send(msg)
681 do_barrier(self.controller)
682
Rich Lane8be7a282013-11-22 14:21:00 -0800683 msg = ofp.message.group_add(
Rich Lane89e12652013-10-10 17:26:25 -0700684 group_type=ofp.OFPGT_ALL,
685 group_id=2,
686 buckets=[])
687
688 self.controller.message_send(msg)
689 do_barrier(self.controller)
690
691 packet_in1 = simple_tcp_packet(tcp_sport=1000)
692
693 flow_add_msg1 = flow_msg_create(
694 self,
695 packet_in1,
696 ing_port=1,
697 action_list=[
698 ofp.action.group(1),
699 ofp.action.output(port1)])
700
701 self.controller.message_send(flow_add_msg1)
702 do_barrier(self.controller)
703
704 packet_in2 = simple_tcp_packet(tcp_sport=2000)
705
706 flow_add_msg2 = flow_msg_create(
707 self,
708 packet_in2,
709 ing_port=1,
710 action_list=[
711 ofp.action.group(2),
712 ofp.action.output(port1)])
713
714 self.controller.message_send(flow_add_msg2)
715 do_barrier(self.controller)
716
717 packet_in3 = simple_tcp_packet(tcp_sport=3000)
718
719 flow_add_msg3 = flow_msg_create(
720 self,
721 packet_in3,
722 ing_port=1,
723 action_list=[
724 ofp.action.group(2),
725 ofp.action.output(port1)])
726
727 self.controller.message_send(flow_add_msg3)
728 do_barrier(self.controller)
729
730 packet_in4 = simple_tcp_packet(tcp_sport=4000)
731
732 flow_add_msg4 = flow_msg_create(
733 self,
734 packet_in4,
735 ing_port=1,
736 action_list=[
737 ofp.action.output(port1)])
738
739 self.controller.message_send(flow_add_msg4)
740 do_barrier(self.controller)
741
742 request = ofp.message.aggregate_stats_request(
743 table_id=ofp.OFPTT_ALL,
744 out_port=ofp.OFPP_ANY,
745 out_group=2)
746
747 response, _ = self.controller.transact(request)
748
749 self.assertEqual(response.flow_count, 2,
750 'Did not match expected flow count')
Rich Lane7b1b1b82013-10-18 13:44:59 -0700751
752
753class SelectFwdEmpty(GroupTest):
754 """
755 A SELECT group with no buckets should not alter the action set of the packet
756 """
757
758 def runTest(self):
759 port1, port2 = openflow_ports(2)
760
Rich Lane8be7a282013-11-22 14:21:00 -0800761 msg = ofp.message.group_add(
Rich Lane7b1b1b82013-10-18 13:44:59 -0700762 group_type=ofp.OFPGT_SELECT,
763 group_id=1,
764 buckets=[])
765
766 self.controller.message_send(msg)
767 do_barrier(self.controller)
768
769 msg = ofp.message.flow_add(
770 buffer_id=ofp.OFP_NO_BUFFER,
771 instructions=[
772 ofp.instruction.apply_actions(
773 [ofp.action.output(2), ofp.action.group(1)])])
774
775 self.controller.message_send(msg)
776 do_barrier(self.controller)
777
778 verify_no_errors(self.controller)
779
780 pkt = simple_tcp_packet()
781 self.dataplane.send(port1, str(pkt))
782 verify_packets(self, pkt, [port2])
783
784
785class SelectFwdSingle(GroupTest):
786 """
787 A SELECT group with a single bucket should use that bucket's actions
788 """
789
790 def runTest(self):
791 port1, port2 = openflow_ports(2)
792
Rich Lane8be7a282013-11-22 14:21:00 -0800793 msg = ofp.message.group_add(
Rich Lane7b1b1b82013-10-18 13:44:59 -0700794 group_type=ofp.OFPGT_SELECT,
795 group_id=1,
796 buckets=[
797 ofp.bucket(weight=1, actions=[ofp.action.output(port2)])])
798
799 self.controller.message_send(msg)
800 do_barrier(self.controller)
801
802 msg = ofp.message.flow_add(
803 buffer_id=ofp.OFP_NO_BUFFER,
804 instructions=[ofp.instruction.apply_actions([ofp.action.group(1)])])
805
806 self.controller.message_send(msg)
807 do_barrier(self.controller)
808
809 verify_no_errors(self.controller)
810
811 pkt = simple_tcp_packet()
812 self.dataplane.send(port1, str(pkt))
813 verify_packets(self, pkt, [port2])
814
815
816class SelectFwdSpread(GroupTest):
817 """
818 A SELECT group with several buckets should spead different flows between them
819 """
820
821 def runTest(self):
822 num_out_ports = 3
823 num_pkts = 1000
824
825 port1, port2, port3, port4 = openflow_ports(num_out_ports + 1)
826 out_ports = [port2, port3, port4]
827
Rich Lane8be7a282013-11-22 14:21:00 -0800828 msg = ofp.message.group_add(
Rich Lane7b1b1b82013-10-18 13:44:59 -0700829 group_type=ofp.OFPGT_SELECT,
830 group_id=1,
831 buckets=[
832 ofp.bucket(weight=1, actions=[ofp.action.output(port)])
833 for port in out_ports])
834
835 self.controller.message_send(msg)
836 do_barrier(self.controller)
837
838 msg = ofp.message.flow_add(
839 buffer_id=ofp.OFP_NO_BUFFER,
840 instructions=[ofp.instruction.apply_actions([ofp.action.group(1)])])
841
842 self.controller.message_send(msg)
843 do_barrier(self.controller)
844
845 verify_no_errors(self.controller)
846
847 counters = { x: 0 for x in out_ports }
848
849 for i in xrange(0, num_pkts):
850 pkt = simple_tcp_packet(tcp_sport=i, tcp_dport=random.randint(0, 65535))
851 self.dataplane.send(port1, str(pkt))
852 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=str(pkt))
853 self.assertIsNotNone(rcv_pkt)
854 if rcv_port not in counters:
855 raise AssertionError("unexpected packet on port %d" % rcv_port)
856 counters[rcv_port] += 1
857
858 # Verify the same flow is mapped to the same output port
859 self.dataplane.send(port1, str(pkt))
860 (rcv_port2, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=str(pkt))
861 self.assertIsNotNone(rcv_pkt)
862 self.assertEquals(rcv_port, rcv_port2)
863
864 logging.debug("Distribution: %r" ,counters)
865
866 self.assertEquals(sum(counters.values()), num_pkts)
867 expected = num_pkts/num_out_ports
868 for port, count in counters.iteritems():
869 # Check that count is within 20% of expected
870 self.assertTrue(expected * 0.8 < count < expected * 1.2,
871 "port %d count was %d, expected %d" % (port, count, expected))