]> git.proxmox.com Git - ovs.git/blob - lib/ofp-group.c
Add OpenFlow extensions for group support in OpenFlow 1.0.
[ovs.git] / lib / ofp-group.c
1 /*
2 * Copyright (c) 2008-2017 Nicira, Inc.
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
17 #include <config.h>
18 #include "openvswitch/ofp-group.h"
19 #include <errno.h>
20 #include "byte-order.h"
21 #include "id-pool.h"
22 #include "nx-match.h"
23 #include "openvswitch/ofp-actions.h"
24 #include "openvswitch/dynamic-string.h"
25 #include "openvswitch/ofp-msgs.h"
26 #include "openvswitch/ofp-parse.h"
27 #include "openvswitch/ofp-port.h"
28 #include "openvswitch/ofp-prop.h"
29 #include "openvswitch/ofpbuf.h"
30 #include "openvswitch/vlog.h"
31 #include "util.h"
32
33 VLOG_DEFINE_THIS_MODULE(ofp_group);
34
35 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
36
37 /* Stores the group id represented by 's' into '*group_idp'. 's' may be an
38 * integer or, for reserved group IDs, the standard OpenFlow name for the group
39 * (either "ANY" or "ALL").
40 *
41 * Returns true if successful, false if 's' is not a valid OpenFlow group ID or
42 * name. */
43 bool
44 ofputil_group_from_string(const char *s, uint32_t *group_idp)
45 {
46 if (!strcasecmp(s, "any")) {
47 *group_idp = OFPG_ANY;
48 } else if (!strcasecmp(s, "all")) {
49 *group_idp = OFPG_ALL;
50 } else if (!str_to_uint(s, 10, group_idp)) {
51 VLOG_WARN("%s is not a valid group ID. (Valid group IDs are "
52 "32-bit nonnegative integers or the keywords ANY or "
53 "ALL.)", s);
54 return false;
55 }
56
57 return true;
58 }
59
60 /* Appends to 's' a string representation of the OpenFlow group ID 'group_id'.
61 * Most groups' string representation is just the number, but for special
62 * groups, e.g. OFPG_ALL, it is the name, e.g. "ALL". */
63 void
64 ofputil_format_group(uint32_t group_id, struct ds *s)
65 {
66 char name[MAX_GROUP_NAME_LEN];
67
68 ofputil_group_to_string(group_id, name, sizeof name);
69 ds_put_cstr(s, name);
70 }
71
72
73 /* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
74 * representation of OpenFlow group ID 'group_id'. Most group are represented
75 * as just their number, but special groups, e.g. OFPG_ALL, are represented
76 * by name, e.g. "ALL". */
77 void
78 ofputil_group_to_string(uint32_t group_id,
79 char namebuf[MAX_GROUP_NAME_LEN + 1], size_t bufsize)
80 {
81 switch (group_id) {
82 case OFPG_ALL:
83 ovs_strlcpy(namebuf, "ALL", bufsize);
84 break;
85
86 case OFPG_ANY:
87 ovs_strlcpy(namebuf, "ANY", bufsize);
88 break;
89
90 default:
91 snprintf(namebuf, bufsize, "%"PRIu32, group_id);
92 break;
93 }
94 }
95 \f
96 /* Frees all of the "struct ofputil_bucket"s in the 'buckets' list. */
97 void
98 ofputil_bucket_list_destroy(struct ovs_list *buckets)
99 {
100 struct ofputil_bucket *bucket;
101
102 LIST_FOR_EACH_POP (bucket, list_node, buckets) {
103 free(bucket->ofpacts);
104 free(bucket);
105 }
106 }
107
108 /* Clones 'bucket' and its ofpacts data */
109 static struct ofputil_bucket *
110 ofputil_bucket_clone_data(const struct ofputil_bucket *bucket)
111 {
112 struct ofputil_bucket *new;
113
114 new = xmemdup(bucket, sizeof *bucket);
115 new->ofpacts = xmemdup(bucket->ofpacts, bucket->ofpacts_len);
116
117 return new;
118 }
119
120 /* Clones each of the buckets in the list 'src' appending them
121 * in turn to 'dest' which should be an initialised list.
122 * An exception is that if the pointer value of a bucket in 'src'
123 * matches 'skip' then it is not cloned or appended to 'dest'.
124 * This allows all of 'src' or 'all of 'src' except 'skip' to
125 * be cloned and appended to 'dest'. */
126 void
127 ofputil_bucket_clone_list(struct ovs_list *dest, const struct ovs_list *src,
128 const struct ofputil_bucket *skip)
129 {
130 struct ofputil_bucket *bucket;
131
132 LIST_FOR_EACH (bucket, list_node, src) {
133 struct ofputil_bucket *new_bucket;
134
135 if (bucket == skip) {
136 continue;
137 }
138
139 new_bucket = ofputil_bucket_clone_data(bucket);
140 ovs_list_push_back(dest, &new_bucket->list_node);
141 }
142 }
143
144 /* Find a bucket in the list 'buckets' whose bucket id is 'bucket_id'
145 * Returns the first bucket found or NULL if no buckets are found. */
146 struct ofputil_bucket *
147 ofputil_bucket_find(const struct ovs_list *buckets, uint32_t bucket_id)
148 {
149 struct ofputil_bucket *bucket;
150
151 if (bucket_id > OFPG15_BUCKET_MAX) {
152 return NULL;
153 }
154
155 LIST_FOR_EACH (bucket, list_node, buckets) {
156 if (bucket->bucket_id == bucket_id) {
157 return bucket;
158 }
159 }
160
161 return NULL;
162 }
163
164 /* Returns true if more than one bucket in the list 'buckets'
165 * have the same bucket id. Returns false otherwise. */
166 bool
167 ofputil_bucket_check_duplicate_id(const struct ovs_list *buckets)
168 {
169 struct ofputil_bucket *i, *j;
170
171 LIST_FOR_EACH (i, list_node, buckets) {
172 LIST_FOR_EACH_REVERSE (j, list_node, buckets) {
173 if (i == j) {
174 break;
175 }
176 if (i->bucket_id == j->bucket_id) {
177 return true;
178 }
179 }
180 }
181
182 return false;
183 }
184
185 /* Returns the bucket at the front of the list 'buckets'.
186 * Undefined if 'buckets is empty. */
187 struct ofputil_bucket *
188 ofputil_bucket_list_front(const struct ovs_list *buckets)
189 {
190 static struct ofputil_bucket *bucket;
191
192 ASSIGN_CONTAINER(bucket, ovs_list_front(buckets), list_node);
193
194 return bucket;
195 }
196
197 /* Returns the bucket at the back of the list 'buckets'.
198 * Undefined if 'buckets is empty. */
199 struct ofputil_bucket *
200 ofputil_bucket_list_back(const struct ovs_list *buckets)
201 {
202 static struct ofputil_bucket *bucket;
203
204 ASSIGN_CONTAINER(bucket, ovs_list_back(buckets), list_node);
205
206 return bucket;
207 }
208
209 /* Returns an OpenFlow group stats request for OpenFlow version 'ofp_version',
210 * that requests stats for group 'group_id'. (Use OFPG_ALL to request stats
211 * for all groups.)
212 *
213 * Group statistics include packet and byte counts for each group. */
214 struct ofpbuf *
215 ofputil_encode_group_stats_request(enum ofp_version ofp_version,
216 uint32_t group_id)
217 {
218 struct ofpbuf *msg = ofpraw_alloc((ofp_version == OFP10_VERSION
219 ? OFPRAW_NXST_GROUP_REQUEST
220 : OFPRAW_OFPST11_GROUP_REQUEST),
221 ofp_version, 0);
222 struct ofp11_group_stats_request *req = ofpbuf_put_zeros(msg, sizeof *req);
223 req->group_id = htonl(group_id);
224
225 return msg;
226 }
227
228 void
229 ofputil_uninit_group_desc(struct ofputil_group_desc *gd)
230 {
231 ofputil_bucket_list_destroy(&gd->buckets);
232 ofputil_group_properties_destroy(&gd->props);
233 }
234
235 /* Decodes the OpenFlow group description request in 'oh', returning the group
236 * whose description is requested, or OFPG_ALL if stats for all groups was
237 * requested. */
238 uint32_t
239 ofputil_decode_group_desc_request(const struct ofp_header *oh)
240 {
241 struct ofpbuf request = ofpbuf_const_initializer(oh, ntohs(oh->length));
242 enum ofpraw raw = ofpraw_pull_assert(&request);
243 if (raw == OFPRAW_OFPST11_GROUP_DESC_REQUEST) {
244 return OFPG_ALL;
245 } else if (raw == OFPRAW_NXST_GROUP_DESC_REQUEST ||
246 raw == OFPRAW_OFPST15_GROUP_DESC_REQUEST) {
247 ovs_be32 *group_id = ofpbuf_pull(&request, sizeof *group_id);
248 return ntohl(*group_id);
249 } else {
250 OVS_NOT_REACHED();
251 }
252 }
253
254 /* Returns an OpenFlow group description request for OpenFlow version
255 * 'ofp_version', that requests stats for group 'group_id'. Use OFPG_ALL to
256 * request stats for all groups (OpenFlow 1.4 and earlier always request all
257 * groups).
258 *
259 * Group descriptions include the bucket and action configuration for each
260 * group. */
261 struct ofpbuf *
262 ofputil_encode_group_desc_request(enum ofp_version ofp_version,
263 uint32_t group_id)
264 {
265 struct ofpbuf *request;
266
267 switch (ofp_version) {
268 case OFP11_VERSION:
269 case OFP12_VERSION:
270 case OFP13_VERSION:
271 case OFP14_VERSION:
272 request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST,
273 ofp_version, 0);
274 break;
275 case OFP10_VERSION:
276 case OFP15_VERSION:
277 case OFP16_VERSION: {
278 struct ofp15_group_desc_request *req;
279 request = ofpraw_alloc((ofp_version == OFP10_VERSION
280 ? OFPRAW_NXST_GROUP_DESC_REQUEST
281 : OFPRAW_OFPST15_GROUP_DESC_REQUEST),
282 ofp_version, 0);
283 req = ofpbuf_put_zeros(request, sizeof *req);
284 req->group_id = htonl(group_id);
285 break;
286 }
287 default:
288 OVS_NOT_REACHED();
289 }
290
291 return request;
292 }
293
294 static void
295 ofputil_group_bucket_counters_to_ofp11(const struct ofputil_group_stats *gs,
296 struct ofp11_bucket_counter bucket_cnts[])
297 {
298 int i;
299
300 for (i = 0; i < gs->n_buckets; i++) {
301 bucket_cnts[i].packet_count = htonll(gs->bucket_stats[i].packet_count);
302 bucket_cnts[i].byte_count = htonll(gs->bucket_stats[i].byte_count);
303 }
304 }
305
306 static void
307 ofputil_group_stats_to_ofp11(const struct ofputil_group_stats *gs,
308 struct ofp11_group_stats *gs11, size_t length,
309 struct ofp11_bucket_counter bucket_cnts[])
310 {
311 memset(gs11, 0, sizeof *gs11);
312 gs11->length = htons(length);
313 gs11->group_id = htonl(gs->group_id);
314 gs11->ref_count = htonl(gs->ref_count);
315 gs11->packet_count = htonll(gs->packet_count);
316 gs11->byte_count = htonll(gs->byte_count);
317 ofputil_group_bucket_counters_to_ofp11(gs, bucket_cnts);
318 }
319
320 static void
321 ofputil_group_stats_to_ofp13(const struct ofputil_group_stats *gs,
322 struct ofp13_group_stats *gs13, size_t length,
323 struct ofp11_bucket_counter bucket_cnts[])
324 {
325 ofputil_group_stats_to_ofp11(gs, &gs13->gs, length, bucket_cnts);
326 gs13->duration_sec = htonl(gs->duration_sec);
327 gs13->duration_nsec = htonl(gs->duration_nsec);
328
329 }
330
331 /* Encodes 'gs' properly for the format of the list of group statistics
332 * replies already begun in 'replies' and appends it to the list. 'replies'
333 * must have originally been initialized with ofpmp_init(). */
334 void
335 ofputil_append_group_stats(struct ovs_list *replies,
336 const struct ofputil_group_stats *gs)
337 {
338 size_t bucket_counter_size;
339 struct ofp11_bucket_counter *bucket_counters;
340 size_t length;
341
342 bucket_counter_size = gs->n_buckets * sizeof(struct ofp11_bucket_counter);
343
344 switch (ofpmp_version(replies)) {
345 case OFP11_VERSION:
346 case OFP12_VERSION:{
347 struct ofp11_group_stats *gs11;
348
349 length = sizeof *gs11 + bucket_counter_size;
350 gs11 = ofpmp_append(replies, length);
351 bucket_counters = (struct ofp11_bucket_counter *)(gs11 + 1);
352 ofputil_group_stats_to_ofp11(gs, gs11, length, bucket_counters);
353 break;
354 }
355
356 case OFP10_VERSION:
357 case OFP13_VERSION:
358 case OFP14_VERSION:
359 case OFP15_VERSION:
360 case OFP16_VERSION: {
361 struct ofp13_group_stats *gs13;
362
363 length = sizeof *gs13 + bucket_counter_size;
364 gs13 = ofpmp_append(replies, length);
365 bucket_counters = (struct ofp11_bucket_counter *)(gs13 + 1);
366 ofputil_group_stats_to_ofp13(gs, gs13, length, bucket_counters);
367 break;
368 }
369
370 default:
371 OVS_NOT_REACHED();
372 }
373 }
374 /* Returns an OpenFlow group features request for OpenFlow version
375 * 'ofp_version'. */
376 struct ofpbuf *
377 ofputil_encode_group_features_request(enum ofp_version ofp_version)
378 {
379 return ofpraw_alloc((ofp_version < OFP12_VERSION
380 ? OFPRAW_NXST_GROUP_FEATURES_REQUEST
381 : OFPRAW_OFPST12_GROUP_FEATURES_REQUEST),
382 ofp_version, 0);
383 }
384
385 /* Returns a OpenFlow message that encodes 'features' properly as a reply to
386 * group features request 'request'. */
387 struct ofpbuf *
388 ofputil_encode_group_features_reply(
389 const struct ofputil_group_features *features,
390 const struct ofp_header *request)
391 {
392 struct ofpbuf *reply = ofpraw_alloc_stats_reply(request, 0);
393 struct ofp12_group_features_stats *ogf
394 = ofpbuf_put_zeros(reply, sizeof *ogf);
395 ogf->types = htonl(features->types);
396 ogf->capabilities = htonl(features->capabilities);
397 for (int i = 0; i < OFPGT12_N_TYPES; i++) {
398 ogf->max_groups[i] = htonl(features->max_groups[i]);
399 ogf->actions[i] = ofpact_bitmap_to_openflow(features->ofpacts[i],
400 request->version);
401 }
402
403 return reply;
404 }
405
406 /* Decodes group features reply 'oh' into 'features'. */
407 void
408 ofputil_decode_group_features_reply(const struct ofp_header *oh,
409 struct ofputil_group_features *features)
410 {
411 const struct ofp12_group_features_stats *ogf = ofpmsg_body(oh);
412 int i;
413
414 features->types = ntohl(ogf->types);
415 features->capabilities = ntohl(ogf->capabilities);
416 for (i = 0; i < OFPGT12_N_TYPES; i++) {
417 features->max_groups[i] = ntohl(ogf->max_groups[i]);
418 features->ofpacts[i] = ofpact_bitmap_from_openflow(
419 ogf->actions[i], oh->version);
420 }
421 }
422
423 /* Parse a group status request message into a 32 bit OpenFlow 1.1
424 * group ID and stores the latter in '*group_id'.
425 * Returns 0 if successful, otherwise an OFPERR_* number. */
426 enum ofperr
427 ofputil_decode_group_stats_request(const struct ofp_header *request,
428 uint32_t *group_id)
429 {
430 const struct ofp11_group_stats_request *gsr11 = ofpmsg_body(request);
431 *group_id = ntohl(gsr11->group_id);
432 return 0;
433 }
434
435 /* Converts a group stats reply in 'msg' into an abstract ofputil_group_stats
436 * in 'gs'. Assigns freshly allocated memory to gs->bucket_stats for the
437 * caller to eventually free.
438 *
439 * Multiple group stats replies can be packed into a single OpenFlow message.
440 * Calling this function multiple times for a single 'msg' iterates through the
441 * replies. The caller must initially leave 'msg''s layer pointers null and
442 * not modify them between calls.
443 *
444 * Returns 0 if successful, EOF if no replies were left in this 'msg',
445 * otherwise a positive errno value. */
446 int
447 ofputil_decode_group_stats_reply(struct ofpbuf *msg,
448 struct ofputil_group_stats *gs)
449 {
450 struct ofp11_bucket_counter *obc;
451 struct ofp11_group_stats *ogs11;
452 enum ofpraw raw;
453 enum ofperr error;
454 size_t base_len;
455 size_t length;
456 size_t i;
457
458 gs->bucket_stats = NULL;
459 error = (msg->header ? ofpraw_decode(&raw, msg->header)
460 : ofpraw_pull(&raw, msg));
461 if (error) {
462 return error;
463 }
464
465 if (!msg->size) {
466 return EOF;
467 }
468
469 if (raw == OFPRAW_OFPST11_GROUP_REPLY) {
470 base_len = sizeof *ogs11;
471 ogs11 = ofpbuf_try_pull(msg, sizeof *ogs11);
472 gs->duration_sec = gs->duration_nsec = UINT32_MAX;
473 } else if (raw == OFPRAW_NXST_GROUP_REPLY ||
474 raw == OFPRAW_OFPST13_GROUP_REPLY) {
475 struct ofp13_group_stats *ogs13;
476
477 base_len = sizeof *ogs13;
478 ogs13 = ofpbuf_try_pull(msg, sizeof *ogs13);
479 if (ogs13) {
480 ogs11 = &ogs13->gs;
481 gs->duration_sec = ntohl(ogs13->duration_sec);
482 gs->duration_nsec = ntohl(ogs13->duration_nsec);
483 } else {
484 ogs11 = NULL;
485 }
486 } else {
487 OVS_NOT_REACHED();
488 }
489
490 if (!ogs11) {
491 VLOG_WARN_RL(&rl, "%s reply has %"PRIu32" leftover bytes at end",
492 ofpraw_get_name(raw), msg->size);
493 return OFPERR_OFPBRC_BAD_LEN;
494 }
495 length = ntohs(ogs11->length);
496 if (length < sizeof base_len) {
497 VLOG_WARN_RL(&rl, "%s reply claims invalid length %"PRIuSIZE,
498 ofpraw_get_name(raw), length);
499 return OFPERR_OFPBRC_BAD_LEN;
500 }
501
502 gs->group_id = ntohl(ogs11->group_id);
503 gs->ref_count = ntohl(ogs11->ref_count);
504 gs->packet_count = ntohll(ogs11->packet_count);
505 gs->byte_count = ntohll(ogs11->byte_count);
506
507 gs->n_buckets = (length - base_len) / sizeof *obc;
508 obc = ofpbuf_try_pull(msg, gs->n_buckets * sizeof *obc);
509 if (!obc) {
510 VLOG_WARN_RL(&rl, "%s reply has %"PRIu32" leftover bytes at end",
511 ofpraw_get_name(raw), msg->size);
512 return OFPERR_OFPBRC_BAD_LEN;
513 }
514
515 gs->bucket_stats = xmalloc(gs->n_buckets * sizeof *gs->bucket_stats);
516 for (i = 0; i < gs->n_buckets; i++) {
517 gs->bucket_stats[i].packet_count = ntohll(obc[i].packet_count);
518 gs->bucket_stats[i].byte_count = ntohll(obc[i].byte_count);
519 }
520
521 return 0;
522 }
523
524 static char * OVS_WARN_UNUSED_RESULT
525 parse_bucket_str(struct ofputil_bucket *bucket, char *str_,
526 const struct ofputil_port_map *port_map,
527 const struct ofputil_table_map *table_map,
528 uint8_t group_type, enum ofputil_protocol *usable_protocols)
529 {
530 char *pos, *key, *value;
531 struct ofpbuf ofpacts;
532 struct ds actions;
533 char *error;
534
535 bucket->weight = group_type == OFPGT11_SELECT ? 1 : 0;
536 bucket->bucket_id = OFPG15_BUCKET_ALL;
537 bucket->watch_port = OFPP_ANY;
538 bucket->watch_group = OFPG_ANY;
539
540 ds_init(&actions);
541
542 pos = str_;
543 error = NULL;
544 while (ofputil_parse_key_value(&pos, &key, &value)) {
545 if (!strcasecmp(key, "weight")) {
546 error = str_to_u16(value, "weight", &bucket->weight);
547 } else if (!strcasecmp(key, "watch_port")) {
548 if (!ofputil_port_from_string(value, port_map, &bucket->watch_port)
549 || (ofp_to_u16(bucket->watch_port) >= ofp_to_u16(OFPP_MAX)
550 && bucket->watch_port != OFPP_ANY)) {
551 error = xasprintf("%s: invalid watch_port", value);
552 }
553 } else if (!strcasecmp(key, "watch_group")) {
554 error = str_to_u32(value, &bucket->watch_group);
555 if (!error && bucket->watch_group > OFPG_MAX) {
556 error = xasprintf("invalid watch_group id %"PRIu32,
557 bucket->watch_group);
558 }
559 } else if (!strcasecmp(key, "bucket_id")) {
560 error = str_to_u32(value, &bucket->bucket_id);
561 if (!error && bucket->bucket_id > OFPG15_BUCKET_MAX) {
562 error = xasprintf("invalid bucket_id id %"PRIu32,
563 bucket->bucket_id);
564 }
565 *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP;
566 } else if (!strcasecmp(key, "action") || !strcasecmp(key, "actions")) {
567 ds_put_format(&actions, "%s,", value);
568 } else {
569 ds_put_format(&actions, "%s(%s),", key, value);
570 }
571
572 if (error) {
573 ds_destroy(&actions);
574 return error;
575 }
576 }
577
578 if (!actions.length) {
579 return xstrdup("bucket must specify actions");
580 }
581 if (group_type == OFPGT11_FF && !ofputil_bucket_has_liveness(bucket)) {
582 return xstrdup("fast failover bucket requires watch_port or "
583 "watch_group");
584 }
585 ds_chomp(&actions, ',');
586
587 ofpbuf_init(&ofpacts, 0);
588 struct ofpact_parse_params pp = {
589 .port_map = port_map,
590 .table_map = table_map,
591 .ofpacts = &ofpacts,
592 .usable_protocols = usable_protocols,
593 };
594 error = ofpacts_parse_actions(ds_cstr(&actions), &pp);
595 ds_destroy(&actions);
596 if (error) {
597 ofpbuf_uninit(&ofpacts);
598 return error;
599 }
600 bucket->ofpacts = ofpacts.data;
601 bucket->ofpacts_len = ofpacts.size;
602
603 return NULL;
604 }
605
606 static char * OVS_WARN_UNUSED_RESULT
607 parse_select_group_field(char *s, const struct ofputil_port_map *port_map,
608 struct field_array *fa,
609 enum ofputil_protocol *usable_protocols)
610 {
611 char *name, *value_str;
612
613 while (ofputil_parse_key_value(&s, &name, &value_str)) {
614 const struct mf_field *mf = mf_from_name(name);
615
616 if (mf) {
617 char *error;
618 union mf_value value;
619
620 if (bitmap_is_set(fa->used.bm, mf->id)) {
621 return xasprintf("%s: duplicate field", name);
622 }
623
624 if (*value_str) {
625 error = mf_parse_value(mf, value_str, port_map, &value);
626 if (error) {
627 return error;
628 }
629
630 /* The mask cannot be all-zeros */
631 if (!mf_is_tun_metadata(mf) &&
632 is_all_zeros(&value, mf->n_bytes)) {
633 return xasprintf("%s: values are wildcards here "
634 "and must not be all-zeros", s);
635 }
636
637 /* The values parsed are masks for fields used
638 * by the selection method */
639 if (!mf_is_mask_valid(mf, &value)) {
640 return xasprintf("%s: invalid mask for field %s",
641 value_str, mf->name);
642 }
643 } else {
644 memset(&value, 0xff, mf->n_bytes);
645 }
646
647 field_array_set(mf->id, &value, fa);
648
649 if (is_all_ones(&value, mf->n_bytes)) {
650 *usable_protocols &= mf->usable_protocols_exact;
651 } else if (mf->usable_protocols_bitwise == mf->usable_protocols_cidr
652 || ip_is_cidr(value.be32)) {
653 *usable_protocols &= mf->usable_protocols_cidr;
654 } else {
655 *usable_protocols &= mf->usable_protocols_bitwise;
656 }
657 } else {
658 return xasprintf("%s: unknown field %s", s, name);
659 }
660 }
661
662 return NULL;
663 }
664
665 static char * OVS_WARN_UNUSED_RESULT
666 parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command,
667 char *string,
668 const struct ofputil_port_map *port_map,
669 const struct ofputil_table_map *table_map,
670 enum ofputil_protocol *usable_protocols)
671 {
672 enum {
673 F_GROUP_TYPE = 1 << 0,
674 F_BUCKETS = 1 << 1,
675 F_COMMAND_BUCKET_ID = 1 << 2,
676 F_COMMAND_BUCKET_ID_ALL = 1 << 3,
677 } fields;
678 bool had_type = false;
679 bool had_command_bucket_id = false;
680 struct ofputil_bucket *bucket;
681 char *error = NULL;
682
683 *usable_protocols = OFPUTIL_P_ANY;
684
685 if (command == -2) {
686 size_t len;
687
688 string += strspn(string, " \t\r\n"); /* Skip white space. */
689 len = strcspn(string, ", \t\r\n"); /* Get length of the first token. */
690
691 if (!strncmp(string, "add", len)) {
692 command = OFPGC11_ADD;
693 } else if (!strncmp(string, "delete", len)) {
694 command = OFPGC11_DELETE;
695 } else if (!strncmp(string, "modify", len)) {
696 command = OFPGC11_MODIFY;
697 } else if (!strncmp(string, "add_or_mod", len)) {
698 command = OFPGC11_ADD_OR_MOD;
699 } else if (!strncmp(string, "insert_bucket", len)) {
700 command = OFPGC15_INSERT_BUCKET;
701 } else if (!strncmp(string, "remove_bucket", len)) {
702 command = OFPGC15_REMOVE_BUCKET;
703 } else {
704 len = 0;
705 command = OFPGC11_ADD;
706 }
707 string += len;
708 }
709
710 switch (command) {
711 case OFPGC11_ADD:
712 fields = F_GROUP_TYPE | F_BUCKETS;
713 break;
714
715 case OFPGC11_DELETE:
716 fields = 0;
717 break;
718
719 case OFPGC11_MODIFY:
720 fields = F_GROUP_TYPE | F_BUCKETS;
721 break;
722
723 case OFPGC11_ADD_OR_MOD:
724 fields = F_GROUP_TYPE | F_BUCKETS;
725 break;
726
727 case OFPGC15_INSERT_BUCKET:
728 fields = F_BUCKETS | F_COMMAND_BUCKET_ID;
729 *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP;
730 break;
731
732 case OFPGC15_REMOVE_BUCKET:
733 fields = F_COMMAND_BUCKET_ID | F_COMMAND_BUCKET_ID_ALL;
734 *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP;
735 break;
736
737 default:
738 OVS_NOT_REACHED();
739 }
740
741 memset(gm, 0, sizeof *gm);
742 gm->command = command;
743 gm->group_id = OFPG_ANY;
744 gm->command_bucket_id = OFPG15_BUCKET_ALL;
745 ovs_list_init(&gm->buckets);
746 if (command == OFPGC11_DELETE && string[0] == '\0') {
747 gm->group_id = OFPG_ALL;
748 return NULL;
749 }
750
751 /* Strip the buckets off the end of 'string', if there are any, saving a
752 * pointer for later. We want to parse the buckets last because the bucket
753 * type influences bucket defaults. */
754 char *bkt_str = strstr(string, "bucket=");
755 if (bkt_str) {
756 if (!(fields & F_BUCKETS)) {
757 error = xstrdup("bucket is not needed");
758 goto out;
759 }
760 *bkt_str = '\0';
761 }
762
763 /* Parse everything before the buckets. */
764 char *pos = string;
765 char *name, *value;
766 while (ofputil_parse_key_value(&pos, &name, &value)) {
767 if (!strcmp(name, "command_bucket_id")) {
768 if (!(fields & F_COMMAND_BUCKET_ID)) {
769 error = xstrdup("command bucket id is not needed");
770 goto out;
771 }
772 if (!strcmp(value, "all")) {
773 gm->command_bucket_id = OFPG15_BUCKET_ALL;
774 } else if (!strcmp(value, "first")) {
775 gm->command_bucket_id = OFPG15_BUCKET_FIRST;
776 } else if (!strcmp(value, "last")) {
777 gm->command_bucket_id = OFPG15_BUCKET_LAST;
778 } else {
779 error = str_to_u32(value, &gm->command_bucket_id);
780 if (error) {
781 goto out;
782 }
783 if (gm->command_bucket_id > OFPG15_BUCKET_MAX
784 && (gm->command_bucket_id != OFPG15_BUCKET_FIRST
785 && gm->command_bucket_id != OFPG15_BUCKET_LAST
786 && gm->command_bucket_id != OFPG15_BUCKET_ALL)) {
787 error = xasprintf("invalid command bucket id %"PRIu32,
788 gm->command_bucket_id);
789 goto out;
790 }
791 }
792 if (gm->command_bucket_id == OFPG15_BUCKET_ALL
793 && !(fields & F_COMMAND_BUCKET_ID_ALL)) {
794 error = xstrdup("command_bucket_id=all is not permitted");
795 goto out;
796 }
797 had_command_bucket_id = true;
798 } else if (!strcmp(name, "group_id")) {
799 if(!strcmp(value, "all")) {
800 gm->group_id = OFPG_ALL;
801 } else {
802 error = str_to_u32(value, &gm->group_id);
803 if (error) {
804 goto out;
805 }
806 if (gm->group_id != OFPG_ALL && gm->group_id > OFPG_MAX) {
807 error = xasprintf("invalid group id %"PRIu32,
808 gm->group_id);
809 goto out;
810 }
811 }
812 } else if (!strcmp(name, "type")){
813 if (!(fields & F_GROUP_TYPE)) {
814 error = xstrdup("type is not needed");
815 goto out;
816 }
817 if (!strcmp(value, "all")) {
818 gm->type = OFPGT11_ALL;
819 } else if (!strcmp(value, "select")) {
820 gm->type = OFPGT11_SELECT;
821 } else if (!strcmp(value, "indirect")) {
822 gm->type = OFPGT11_INDIRECT;
823 } else if (!strcmp(value, "ff") ||
824 !strcmp(value, "fast_failover")) {
825 gm->type = OFPGT11_FF;
826 } else {
827 error = xasprintf("invalid group type %s", value);
828 goto out;
829 }
830 had_type = true;
831 } else if (!strcmp(name, "selection_method")) {
832 if (!(fields & F_GROUP_TYPE)) {
833 error = xstrdup("selection method is not needed");
834 goto out;
835 }
836 if (strlen(value) >= NTR_MAX_SELECTION_METHOD_LEN) {
837 error = xasprintf("selection method is longer than %u"
838 " bytes long",
839 NTR_MAX_SELECTION_METHOD_LEN - 1);
840 goto out;
841 }
842 memset(gm->props.selection_method, '\0',
843 NTR_MAX_SELECTION_METHOD_LEN);
844 strcpy(gm->props.selection_method, value);
845 *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP;
846 } else if (!strcmp(name, "selection_method_param")) {
847 if (!(fields & F_GROUP_TYPE)) {
848 error = xstrdup("selection method param is not needed");
849 goto out;
850 }
851 error = str_to_u64(value, &gm->props.selection_method_param);
852 if (error) {
853 goto out;
854 }
855 *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP;
856 } else if (!strcmp(name, "fields")) {
857 if (!(fields & F_GROUP_TYPE)) {
858 error = xstrdup("fields are not needed");
859 goto out;
860 }
861 error = parse_select_group_field(value, port_map,
862 &gm->props.fields,
863 usable_protocols);
864 if (error) {
865 goto out;
866 }
867 *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP;
868 } else {
869 error = xasprintf("unknown keyword %s", name);
870 goto out;
871 }
872 }
873 if (gm->group_id == OFPG_ANY) {
874 error = xstrdup("must specify a group_id");
875 goto out;
876 }
877 if (fields & F_GROUP_TYPE && !had_type) {
878 error = xstrdup("must specify a type");
879 goto out;
880 }
881
882 /* Exclude fields for non "hash" selection method. */
883 if (strcmp(gm->props.selection_method, "hash") &&
884 gm->props.fields.values_size) {
885 error = xstrdup("fields may only be specified with "
886 "\"selection_method=hash\"");
887 goto out;
888 }
889 /* Exclude selection_method_param if no selection_method is given. */
890 if (gm->props.selection_method[0] == 0
891 && gm->props.selection_method_param != 0) {
892 error = xstrdup("selection_method_param is only allowed with "
893 "\"selection_method\"");
894 goto out;
895 }
896 if (fields & F_COMMAND_BUCKET_ID) {
897 if (!(fields & F_COMMAND_BUCKET_ID_ALL || had_command_bucket_id)) {
898 error = xstrdup("must specify a command bucket id");
899 goto out;
900 }
901 } else if (had_command_bucket_id) {
902 error = xstrdup("command bucket id is not needed");
903 goto out;
904 }
905
906 /* Now parse the buckets, if any. */
907 while (bkt_str) {
908 char *next_bkt_str;
909
910 bkt_str = strchr(bkt_str + 1, '=');
911 if (!bkt_str) {
912 error = xstrdup("must specify bucket content");
913 goto out;
914 }
915 bkt_str++;
916
917 next_bkt_str = strstr(bkt_str, "bucket=");
918 if (next_bkt_str) {
919 *next_bkt_str = '\0';
920 }
921
922 bucket = xzalloc(sizeof(struct ofputil_bucket));
923 error = parse_bucket_str(bucket, bkt_str, port_map, table_map,
924 gm->type, usable_protocols);
925 if (error) {
926 free(bucket);
927 goto out;
928 }
929 ovs_list_push_back(&gm->buckets, &bucket->list_node);
930
931 if (gm->type != OFPGT11_SELECT && bucket->weight) {
932 error = xstrdup("Only select groups can have bucket weights.");
933 goto out;
934 }
935
936 bkt_str = next_bkt_str;
937 }
938 if (gm->type == OFPGT11_INDIRECT && !ovs_list_is_short(&gm->buckets)) {
939 error = xstrdup("Indirect groups can have at most one bucket.");
940 goto out;
941 }
942
943 return NULL;
944 out:
945 ofputil_uninit_group_mod(gm);
946 return error;
947 }
948
949 /* If 'command' is given as -2, each line may start with a command name ("add",
950 * "modify", "add_or_mod", "delete", "insert_bucket", or "remove_bucket"). A
951 * missing command name is treated as "add".
952 */
953 char * OVS_WARN_UNUSED_RESULT
954 parse_ofp_group_mod_str(struct ofputil_group_mod *gm, int command,
955 const char *str_,
956 const struct ofputil_port_map *port_map,
957 const struct ofputil_table_map *table_map,
958 enum ofputil_protocol *usable_protocols)
959 {
960 char *string = xstrdup(str_);
961 char *error = parse_ofp_group_mod_str__(gm, command, string, port_map,
962 table_map, usable_protocols);
963 free(string);
964 return error;
965 }
966
967 /* If 'command' is given as -2, each line may start with a command name ("add",
968 * "modify", "add_or_mod", "delete", "insert_bucket", or "remove_bucket"). A
969 * missing command name is treated as "add".
970 */
971 char * OVS_WARN_UNUSED_RESULT
972 parse_ofp_group_mod_file(const char *file_name,
973 const struct ofputil_port_map *port_map,
974 const struct ofputil_table_map *table_map,
975 int command,
976 struct ofputil_group_mod **gms, size_t *n_gms,
977 enum ofputil_protocol *usable_protocols)
978 {
979 size_t allocated_gms;
980 int line_number;
981 FILE *stream;
982 struct ds s;
983
984 *gms = NULL;
985 *n_gms = 0;
986
987 stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
988 if (stream == NULL) {
989 return xasprintf("%s: open failed (%s)",
990 file_name, ovs_strerror(errno));
991 }
992
993 allocated_gms = *n_gms;
994 ds_init(&s);
995 line_number = 0;
996 *usable_protocols = OFPUTIL_P_ANY;
997 while (!ds_get_preprocessed_line(&s, stream, &line_number)) {
998 enum ofputil_protocol usable;
999 char *error;
1000
1001 if (*n_gms >= allocated_gms) {
1002 struct ofputil_group_mod *new_gms;
1003 size_t i;
1004
1005 new_gms = x2nrealloc(*gms, &allocated_gms, sizeof **gms);
1006 for (i = 0; i < *n_gms; i++) {
1007 ovs_list_moved(&new_gms[i].buckets, &(*gms)[i].buckets);
1008 }
1009 *gms = new_gms;
1010 }
1011 error = parse_ofp_group_mod_str(&(*gms)[*n_gms], command, ds_cstr(&s),
1012 port_map, table_map, &usable);
1013 if (error) {
1014 size_t i;
1015
1016 for (i = 0; i < *n_gms; i++) {
1017 ofputil_uninit_group_mod(&(*gms)[i]);
1018 }
1019 free(*gms);
1020 *gms = NULL;
1021 *n_gms = 0;
1022
1023 ds_destroy(&s);
1024 if (stream != stdin) {
1025 fclose(stream);
1026 }
1027
1028 char *ret = xasprintf("%s:%d: %s", file_name, line_number, error);
1029 free(error);
1030 return ret;
1031 }
1032 *usable_protocols &= usable;
1033 *n_gms += 1;
1034 }
1035
1036 ds_destroy(&s);
1037 if (stream != stdin) {
1038 fclose(stream);
1039 }
1040 return NULL;
1041 }
1042 \f
1043 static void
1044 ofputil_put_ofp11_bucket(const struct ofputil_bucket *bucket,
1045 struct ofpbuf *openflow, enum ofp_version ofp_version)
1046 {
1047 struct ofp11_bucket *ob;
1048 size_t start;
1049
1050 start = openflow->size;
1051 ofpbuf_put_zeros(openflow, sizeof *ob);
1052 ofpacts_put_openflow_actions(bucket->ofpacts, bucket->ofpacts_len,
1053 openflow, ofp_version);
1054 ob = ofpbuf_at_assert(openflow, start, sizeof *ob);
1055 ob->len = htons(openflow->size - start);
1056 ob->weight = htons(bucket->weight);
1057 ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
1058 ob->watch_group = htonl(bucket->watch_group);
1059 }
1060
1061 static void
1062 ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket,
1063 uint32_t bucket_id, enum ofp11_group_type group_type,
1064 struct ofpbuf *openflow, enum ofp_version ofp_version)
1065 {
1066 struct ofp15_bucket *ob;
1067 size_t start, actions_start, actions_len;
1068
1069 start = openflow->size;
1070 ofpbuf_put_zeros(openflow, sizeof *ob);
1071
1072 actions_start = openflow->size;
1073 ofpacts_put_openflow_actions(bucket->ofpacts, bucket->ofpacts_len,
1074 openflow, ofp_version);
1075 actions_len = openflow->size - actions_start;
1076
1077 if (group_type == OFPGT11_SELECT) {
1078 ofpprop_put_u16(openflow, OFPGBPT15_WEIGHT, bucket->weight);
1079 }
1080 if (bucket->watch_port != OFPP_ANY) {
1081 ofpprop_put_be32(openflow, OFPGBPT15_WATCH_PORT,
1082 ofputil_port_to_ofp11(bucket->watch_port));
1083 }
1084 if (bucket->watch_group != OFPG_ANY) {
1085 ofpprop_put_u32(openflow, OFPGBPT15_WATCH_GROUP, bucket->watch_group);
1086 }
1087
1088 ob = ofpbuf_at_assert(openflow, start, sizeof *ob);
1089 ob->len = htons(openflow->size - start);
1090 ob->action_array_len = htons(actions_len);
1091 ob->bucket_id = htonl(bucket_id);
1092 }
1093
1094 static void
1095 ofputil_put_group_prop_ntr_selection_method(enum ofp_version ofp_version,
1096 const struct ofputil_group_props *gp,
1097 struct ofpbuf *openflow)
1098 {
1099 struct ntr_group_prop_selection_method *prop;
1100 size_t start;
1101
1102 start = openflow->size;
1103 ofpbuf_put_zeros(openflow, sizeof *prop);
1104 oxm_put_field_array(openflow, &gp->fields, ofp_version);
1105 prop = ofpbuf_at_assert(openflow, start, sizeof *prop);
1106 prop->type = htons(OFPGPT15_EXPERIMENTER);
1107 prop->experimenter = htonl(NTR_VENDOR_ID);
1108 prop->exp_type = htonl(NTRT_SELECTION_METHOD);
1109 strcpy(prop->selection_method, gp->selection_method);
1110 prop->selection_method_param = htonll(gp->selection_method_param);
1111 ofpprop_end(openflow, start);
1112 }
1113
1114 static void
1115 ofputil_append_ofp11_group_desc_reply(const struct ofputil_group_desc *gds,
1116 const struct ovs_list *buckets,
1117 struct ovs_list *replies,
1118 enum ofp_version version)
1119 {
1120 struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
1121 struct ofp11_group_desc_stats *ogds;
1122 struct ofputil_bucket *bucket;
1123 size_t start_ogds;
1124
1125 start_ogds = reply->size;
1126 ofpbuf_put_zeros(reply, sizeof *ogds);
1127 LIST_FOR_EACH (bucket, list_node, buckets) {
1128 ofputil_put_ofp11_bucket(bucket, reply, version);
1129 }
1130 ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
1131 ogds->length = htons(reply->size - start_ogds);
1132 ogds->type = gds->type;
1133 ogds->group_id = htonl(gds->group_id);
1134
1135 ofpmp_postappend(replies, start_ogds);
1136 }
1137
1138 static void
1139 ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds,
1140 const struct ovs_list *buckets,
1141 struct ovs_list *replies,
1142 enum ofp_version version)
1143 {
1144 struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
1145 struct ofp15_group_desc_stats *ogds;
1146 struct ofputil_bucket *bucket;
1147 size_t start_ogds, start_buckets;
1148
1149 start_ogds = reply->size;
1150 ofpbuf_put_zeros(reply, sizeof *ogds);
1151 start_buckets = reply->size;
1152 LIST_FOR_EACH (bucket, list_node, buckets) {
1153 ofputil_put_ofp15_bucket(bucket, bucket->bucket_id,
1154 gds->type, reply, version);
1155 }
1156 ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
1157 ogds->type = gds->type;
1158 ogds->group_id = htonl(gds->group_id);
1159 ogds->bucket_list_len = htons(reply->size - start_buckets);
1160
1161 /* Add group properties */
1162 if (gds->props.selection_method[0]) {
1163 ofputil_put_group_prop_ntr_selection_method(version, &gds->props,
1164 reply);
1165 }
1166 ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
1167 ogds->length = htons(reply->size - start_ogds);
1168
1169 ofpmp_postappend(replies, start_ogds);
1170 }
1171
1172 /* Appends a group stats reply that contains the data in 'gds' to those already
1173 * present in the list of ofpbufs in 'replies'. 'replies' should have been
1174 * initialized with ofpmp_init(). */
1175 void
1176 ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds,
1177 const struct ovs_list *buckets,
1178 struct ovs_list *replies)
1179 {
1180 enum ofp_version version = ofpmp_version(replies);
1181
1182 switch (version)
1183 {
1184 case OFP11_VERSION:
1185 case OFP12_VERSION:
1186 case OFP13_VERSION:
1187 case OFP14_VERSION:
1188 ofputil_append_ofp11_group_desc_reply(gds, buckets, replies, version);
1189 break;
1190
1191 case OFP10_VERSION:
1192 case OFP15_VERSION:
1193 case OFP16_VERSION:
1194 ofputil_append_ofp15_group_desc_reply(gds, buckets, replies, version);
1195 break;
1196
1197 default:
1198 OVS_NOT_REACHED();
1199 }
1200 }
1201
1202 static enum ofperr
1203 ofputil_pull_ofp11_buckets(struct ofpbuf *msg, size_t buckets_length,
1204 enum ofp_version version, struct ovs_list *buckets)
1205 {
1206 struct ofp11_bucket *ob;
1207 uint32_t bucket_id = 0;
1208
1209 ovs_list_init(buckets);
1210 while (buckets_length > 0) {
1211 struct ofputil_bucket *bucket;
1212 struct ofpbuf ofpacts;
1213 enum ofperr error;
1214 size_t ob_len;
1215
1216 ob = (buckets_length >= sizeof *ob
1217 ? ofpbuf_try_pull(msg, sizeof *ob)
1218 : NULL);
1219 if (!ob) {
1220 VLOG_WARN_RL(&rl, "buckets end with %"PRIuSIZE" leftover bytes",
1221 buckets_length);
1222 ofputil_bucket_list_destroy(buckets);
1223 return OFPERR_OFPGMFC_BAD_BUCKET;
1224 }
1225
1226 ob_len = ntohs(ob->len);
1227 if (ob_len < sizeof *ob) {
1228 VLOG_WARN_RL(&rl, "OpenFlow message bucket length "
1229 "%"PRIuSIZE" is not valid", ob_len);
1230 ofputil_bucket_list_destroy(buckets);
1231 return OFPERR_OFPGMFC_BAD_BUCKET;
1232 } else if (ob_len > buckets_length) {
1233 VLOG_WARN_RL(&rl, "OpenFlow message bucket length %"PRIuSIZE" "
1234 "exceeds remaining buckets data size %"PRIuSIZE,
1235 ob_len, buckets_length);
1236 ofputil_bucket_list_destroy(buckets);
1237 return OFPERR_OFPGMFC_BAD_BUCKET;
1238 }
1239 buckets_length -= ob_len;
1240
1241 ofpbuf_init(&ofpacts, 0);
1242 error = ofpacts_pull_openflow_actions(msg, ob_len - sizeof *ob,
1243 version, NULL, NULL, &ofpacts);
1244 if (error) {
1245 ofpbuf_uninit(&ofpacts);
1246 ofputil_bucket_list_destroy(buckets);
1247 return error;
1248 }
1249
1250 bucket = xzalloc(sizeof *bucket);
1251 bucket->weight = ntohs(ob->weight);
1252 error = ofputil_port_from_ofp11(ob->watch_port, &bucket->watch_port);
1253 if (error) {
1254 ofpbuf_uninit(&ofpacts);
1255 ofputil_bucket_list_destroy(buckets);
1256 free(bucket);
1257 return OFPERR_OFPGMFC_BAD_WATCH;
1258 }
1259 bucket->watch_group = ntohl(ob->watch_group);
1260 bucket->bucket_id = bucket_id++;
1261
1262 bucket->ofpacts = ofpbuf_steal_data(&ofpacts);
1263 bucket->ofpacts_len = ofpacts.size;
1264 ovs_list_push_back(buckets, &bucket->list_node);
1265 }
1266
1267 return 0;
1268 }
1269
1270 static enum ofperr
1271 ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length,
1272 enum ofp_version version, uint8_t group_type,
1273 struct ovs_list *buckets)
1274 {
1275 ovs_list_init(buckets);
1276 while (buckets_length > 0) {
1277 struct ofputil_bucket *bucket = NULL;
1278 struct ofpbuf ofpacts;
1279 enum ofperr err = OFPERR_OFPGMFC_BAD_BUCKET;
1280 size_t ob_len, actions_len, properties_len;
1281 ovs_be32 watch_port = ofputil_port_to_ofp11(OFPP_ANY);
1282 ovs_be32 watch_group = htonl(OFPG_ANY);
1283 ovs_be16 weight = htons(group_type == OFPGT11_SELECT ? 1 : 0);
1284
1285 ofpbuf_init(&ofpacts, 0);
1286
1287 struct ofp15_bucket *ob = ofpbuf_try_pull(msg, sizeof *ob);
1288 if (!ob) {
1289 VLOG_WARN_RL(&rl, "buckets end with %"PRIuSIZE
1290 " leftover bytes", buckets_length);
1291 goto err;
1292 }
1293
1294 ob_len = ntohs(ob->len);
1295 actions_len = ntohs(ob->action_array_len);
1296
1297 if (ob_len < sizeof *ob) {
1298 VLOG_WARN_RL(&rl, "OpenFlow message bucket length "
1299 "%"PRIuSIZE" is not valid", ob_len);
1300 goto err;
1301 } else if (ob_len > buckets_length) {
1302 VLOG_WARN_RL(&rl, "OpenFlow message bucket length "
1303 "%"PRIuSIZE" exceeds remaining buckets data size %"
1304 PRIuSIZE, ob_len, buckets_length);
1305 goto err;
1306 } else if (actions_len > ob_len - sizeof *ob) {
1307 VLOG_WARN_RL(&rl, "OpenFlow message bucket actions "
1308 "length %"PRIuSIZE" exceeds remaining bucket "
1309 "data size %"PRIuSIZE, actions_len,
1310 ob_len - sizeof *ob);
1311 goto err;
1312 }
1313 buckets_length -= ob_len;
1314
1315 err = ofpacts_pull_openflow_actions(msg, actions_len, version,
1316 NULL, NULL, &ofpacts);
1317 if (err) {
1318 goto err;
1319 }
1320
1321 properties_len = ob_len - sizeof *ob - actions_len;
1322 struct ofpbuf properties = ofpbuf_const_initializer(
1323 ofpbuf_pull(msg, properties_len), properties_len);
1324 while (properties.size > 0) {
1325 struct ofpbuf payload;
1326 uint64_t type;
1327
1328 err = ofpprop_pull(&properties, &payload, &type);
1329 if (err) {
1330 goto err;
1331 }
1332
1333 switch (type) {
1334 case OFPGBPT15_WEIGHT:
1335 err = ofpprop_parse_be16(&payload, &weight);
1336 break;
1337
1338 case OFPGBPT15_WATCH_PORT:
1339 err = ofpprop_parse_be32(&payload, &watch_port);
1340 break;
1341
1342 case OFPGBPT15_WATCH_GROUP:
1343 err = ofpprop_parse_be32(&payload, &watch_group);
1344 break;
1345
1346 default:
1347 err = OFPPROP_UNKNOWN(false, "group bucket", type);
1348 break;
1349 }
1350
1351 if (err) {
1352 goto err;
1353 }
1354 }
1355
1356 bucket = xzalloc(sizeof *bucket);
1357
1358 bucket->weight = ntohs(weight);
1359 err = ofputil_port_from_ofp11(watch_port, &bucket->watch_port);
1360 if (err) {
1361 err = OFPERR_OFPGMFC_BAD_WATCH;
1362 goto err;
1363 }
1364 bucket->watch_group = ntohl(watch_group);
1365 bucket->bucket_id = ntohl(ob->bucket_id);
1366 if (bucket->bucket_id > OFPG15_BUCKET_MAX) {
1367 VLOG_WARN_RL(&rl, "bucket id (%u) is out of range",
1368 bucket->bucket_id);
1369 err = OFPERR_OFPGMFC_BAD_BUCKET;
1370 goto err;
1371 }
1372
1373 bucket->ofpacts = ofpbuf_steal_data(&ofpacts);
1374 bucket->ofpacts_len = ofpacts.size;
1375 ovs_list_push_back(buckets, &bucket->list_node);
1376
1377 continue;
1378
1379 err:
1380 free(bucket);
1381 ofpbuf_uninit(&ofpacts);
1382 ofputil_bucket_list_destroy(buckets);
1383 return err;
1384 }
1385
1386 if (ofputil_bucket_check_duplicate_id(buckets)) {
1387 VLOG_WARN_RL(&rl, "Duplicate bucket id");
1388 ofputil_bucket_list_destroy(buckets);
1389 return OFPERR_OFPGMFC_BAD_BUCKET;
1390 }
1391
1392 return 0;
1393 }
1394
1395 static void
1396 ofputil_init_group_properties(struct ofputil_group_props *gp)
1397 {
1398 memset(gp, 0, sizeof *gp);
1399 }
1400
1401 void
1402 ofputil_group_properties_copy(struct ofputil_group_props *to,
1403 const struct ofputil_group_props *from)
1404 {
1405 *to = *from;
1406 to->fields.values = xmemdup(from->fields.values, from->fields.values_size);
1407 }
1408
1409 void
1410 ofputil_group_properties_destroy(struct ofputil_group_props *gp)
1411 {
1412 free(gp->fields.values);
1413 }
1414
1415 static enum ofperr
1416 parse_group_prop_ntr_selection_method(struct ofpbuf *payload,
1417 enum ofp11_group_type group_type,
1418 enum ofp15_group_mod_command group_cmd,
1419 struct ofputil_group_props *gp)
1420 {
1421 struct ntr_group_prop_selection_method *prop = payload->data;
1422 size_t fields_len, method_len;
1423 enum ofperr error;
1424
1425 switch (group_type) {
1426 case OFPGT11_SELECT:
1427 break;
1428 case OFPGT11_ALL:
1429 case OFPGT11_INDIRECT:
1430 case OFPGT11_FF:
1431 OFPPROP_LOG(&rl, false, "ntr selection method property is "
1432 "only allowed for select groups");
1433 return OFPERR_OFPBPC_BAD_VALUE;
1434 default:
1435 OVS_NOT_REACHED();
1436 }
1437
1438 switch (group_cmd) {
1439 case OFPGC15_ADD:
1440 case OFPGC15_MODIFY:
1441 case OFPGC15_ADD_OR_MOD:
1442 break;
1443 case OFPGC15_DELETE:
1444 case OFPGC15_INSERT_BUCKET:
1445 case OFPGC15_REMOVE_BUCKET:
1446 OFPPROP_LOG(&rl, false, "ntr selection method property is "
1447 "only allowed for add and delete group modifications");
1448 return OFPERR_OFPBPC_BAD_VALUE;
1449 default:
1450 OVS_NOT_REACHED();
1451 }
1452
1453 if (payload->size < sizeof *prop) {
1454 OFPPROP_LOG(&rl, false, "ntr selection method property "
1455 "length %u is not valid", payload->size);
1456 return OFPERR_OFPBPC_BAD_LEN;
1457 }
1458
1459 method_len = strnlen(prop->selection_method, NTR_MAX_SELECTION_METHOD_LEN);
1460
1461 if (method_len == NTR_MAX_SELECTION_METHOD_LEN) {
1462 OFPPROP_LOG(&rl, false,
1463 "ntr selection method is not null terminated");
1464 return OFPERR_OFPBPC_BAD_VALUE;
1465 }
1466
1467 if (strcmp("hash", prop->selection_method)
1468 && strcmp("dp_hash", prop->selection_method)) {
1469 OFPPROP_LOG(&rl, false,
1470 "ntr selection method '%s' is not supported",
1471 prop->selection_method);
1472 return OFPERR_OFPBPC_BAD_VALUE;
1473 }
1474 /* 'method_len' is now non-zero. */
1475
1476 strcpy(gp->selection_method, prop->selection_method);
1477 gp->selection_method_param = ntohll(prop->selection_method_param);
1478
1479 ofpbuf_pull(payload, sizeof *prop);
1480
1481 fields_len = ntohs(prop->length) - sizeof *prop;
1482 if (fields_len && strcmp("hash", gp->selection_method)) {
1483 OFPPROP_LOG(&rl, false, "ntr selection method %s "
1484 "does not support fields", gp->selection_method);
1485 return OFPERR_OFPBPC_BAD_VALUE;
1486 }
1487
1488 error = oxm_pull_field_array(payload->data, fields_len,
1489 &gp->fields);
1490 if (error) {
1491 OFPPROP_LOG(&rl, false,
1492 "ntr selection method fields are invalid");
1493 return error;
1494 }
1495
1496 return 0;
1497 }
1498
1499 static enum ofperr
1500 parse_ofp15_group_properties(struct ofpbuf *msg,
1501 enum ofp11_group_type group_type,
1502 enum ofp15_group_mod_command group_cmd,
1503 struct ofputil_group_props *gp,
1504 size_t properties_len)
1505 {
1506 struct ofpbuf properties = ofpbuf_const_initializer(
1507 ofpbuf_pull(msg, properties_len), properties_len);
1508 while (properties.size > 0) {
1509 struct ofpbuf payload;
1510 enum ofperr error;
1511 uint64_t type;
1512
1513 error = ofpprop_pull(&properties, &payload, &type);
1514 if (error) {
1515 return error;
1516 }
1517
1518 switch (type) {
1519 case OFPPROP_EXP(NTR_VENDOR_ID, NTRT_SELECTION_METHOD):
1520 case OFPPROP_EXP(NTR_COMPAT_VENDOR_ID, NTRT_SELECTION_METHOD):
1521 error = parse_group_prop_ntr_selection_method(&payload, group_type,
1522 group_cmd, gp);
1523 break;
1524
1525 default:
1526 error = OFPPROP_UNKNOWN(false, "group", type);
1527 break;
1528 }
1529
1530 if (error) {
1531 return error;
1532 }
1533 }
1534
1535 return 0;
1536 }
1537
1538 static int
1539 ofputil_decode_ofp11_group_desc_reply(struct ofputil_group_desc *gd,
1540 struct ofpbuf *msg,
1541 enum ofp_version version)
1542 {
1543 struct ofp11_group_desc_stats *ogds;
1544 size_t length;
1545
1546 if (!msg->header) {
1547 ofpraw_pull_assert(msg);
1548 }
1549
1550 if (!msg->size) {
1551 return EOF;
1552 }
1553
1554 ogds = ofpbuf_try_pull(msg, sizeof *ogds);
1555 if (!ogds) {
1556 VLOG_WARN_RL(&rl, "OFPST11_GROUP_DESC reply has %"PRIu32" "
1557 "leftover bytes at end", msg->size);
1558 return OFPERR_OFPBRC_BAD_LEN;
1559 }
1560 gd->type = ogds->type;
1561 gd->group_id = ntohl(ogds->group_id);
1562
1563 length = ntohs(ogds->length);
1564 if (length < sizeof *ogds || length - sizeof *ogds > msg->size) {
1565 VLOG_WARN_RL(&rl, "OFPST11_GROUP_DESC reply claims invalid "
1566 "length %"PRIuSIZE, length);
1567 return OFPERR_OFPBRC_BAD_LEN;
1568 }
1569
1570 return ofputil_pull_ofp11_buckets(msg, length - sizeof *ogds, version,
1571 &gd->buckets);
1572 }
1573
1574 static int
1575 ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd,
1576 struct ofpbuf *msg,
1577 enum ofp_version version)
1578 {
1579 struct ofp15_group_desc_stats *ogds;
1580 uint16_t length, bucket_list_len;
1581 int error;
1582
1583 if (!msg->header) {
1584 ofpraw_pull_assert(msg);
1585 }
1586
1587 if (!msg->size) {
1588 return EOF;
1589 }
1590
1591 ogds = ofpbuf_try_pull(msg, sizeof *ogds);
1592 if (!ogds) {
1593 VLOG_WARN_RL(&rl, "OFPST11_GROUP_DESC reply has %"PRIu32" "
1594 "leftover bytes at end", msg->size);
1595 return OFPERR_OFPBRC_BAD_LEN;
1596 }
1597 gd->type = ogds->type;
1598 gd->group_id = ntohl(ogds->group_id);
1599
1600 length = ntohs(ogds->length);
1601 if (length < sizeof *ogds || length - sizeof *ogds > msg->size) {
1602 VLOG_WARN_RL(&rl, "OFPST11_GROUP_DESC reply claims invalid "
1603 "length %u", length);
1604 return OFPERR_OFPBRC_BAD_LEN;
1605 }
1606
1607 bucket_list_len = ntohs(ogds->bucket_list_len);
1608 if (length < bucket_list_len + sizeof *ogds) {
1609 VLOG_WARN_RL(&rl, "OFPST11_GROUP_DESC reply claims invalid "
1610 "bucket list length %u", bucket_list_len);
1611 return OFPERR_OFPBRC_BAD_LEN;
1612 }
1613 error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, version, gd->type,
1614 &gd->buckets);
1615 if (error) {
1616 return error;
1617 }
1618
1619 /* By definition group desc messages don't have a group mod command.
1620 * However, parse_group_prop_ntr_selection_method() checks to make sure
1621 * that the command is OFPGC15_ADD or OFPGC15_DELETE to guard
1622 * against group mod messages with other commands supplying
1623 * a NTR selection method group experimenter property.
1624 * Such properties are valid for group desc replies so
1625 * claim that the group mod command is OFPGC15_ADD to
1626 * satisfy the check in parse_group_prop_ntr_selection_method() */
1627 error = parse_ofp15_group_properties(
1628 msg, gd->type, OFPGC15_ADD, &gd->props,
1629 length - sizeof *ogds - bucket_list_len);
1630 if (error) {
1631 ofputil_bucket_list_destroy(&gd->buckets);
1632 }
1633 return error;
1634 }
1635
1636 /* Converts a group description reply in 'msg' into an abstract
1637 * ofputil_group_desc in 'gd'.
1638 *
1639 * Multiple group description replies can be packed into a single OpenFlow
1640 * message. Calling this function multiple times for a single 'msg' iterates
1641 * through the replies. The caller must initially leave 'msg''s layer pointers
1642 * null and not modify them between calls.
1643 *
1644 * Returns 0 if successful, EOF if no replies were left in this 'msg',
1645 * otherwise a positive errno value. */
1646 int
1647 ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
1648 struct ofpbuf *msg, enum ofp_version version)
1649 {
1650 ofputil_init_group_properties(&gd->props);
1651
1652 switch (version)
1653 {
1654 case OFP11_VERSION:
1655 case OFP12_VERSION:
1656 case OFP13_VERSION:
1657 case OFP14_VERSION:
1658 return ofputil_decode_ofp11_group_desc_reply(gd, msg, version);
1659
1660 case OFP10_VERSION:
1661 case OFP15_VERSION:
1662 case OFP16_VERSION:
1663 return ofputil_decode_ofp15_group_desc_reply(gd, msg, version);
1664
1665 default:
1666 OVS_NOT_REACHED();
1667 }
1668 }
1669
1670 void
1671 ofputil_uninit_group_mod(struct ofputil_group_mod *gm)
1672 {
1673 ofputil_bucket_list_destroy(&gm->buckets);
1674 ofputil_group_properties_destroy(&gm->props);
1675 }
1676
1677 static struct ofpbuf *
1678 ofputil_encode_ofp11_group_mod(enum ofp_version ofp_version,
1679 const struct ofputil_group_mod *gm)
1680 {
1681 struct ofpbuf *b;
1682 struct ofp11_group_mod *ogm;
1683 size_t start_ogm;
1684 struct ofputil_bucket *bucket;
1685
1686 b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
1687 start_ogm = b->size;
1688 ofpbuf_put_zeros(b, sizeof *ogm);
1689
1690 LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
1691 ofputil_put_ofp11_bucket(bucket, b, ofp_version);
1692 }
1693 ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm);
1694 ogm->command = htons(gm->command);
1695 ogm->type = gm->type;
1696 ogm->group_id = htonl(gm->group_id);
1697
1698 return b;
1699 }
1700
1701 static struct ofpbuf *
1702 ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version,
1703 const struct ofputil_group_mod *gm)
1704 {
1705 struct ofpbuf *b;
1706 struct ofp15_group_mod *ogm;
1707 size_t start_ogm;
1708 struct ofputil_bucket *bucket;
1709 struct id_pool *bucket_ids = NULL;
1710
1711 b = ofpraw_alloc((ofp_version == OFP10_VERSION
1712 ? OFPRAW_NXT_GROUP_MOD
1713 : OFPRAW_OFPT15_GROUP_MOD), ofp_version, 0);
1714 start_ogm = b->size;
1715 ofpbuf_put_zeros(b, sizeof *ogm);
1716
1717 LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
1718 uint32_t bucket_id;
1719
1720 /* Generate a bucket id if none was supplied */
1721 if (bucket->bucket_id > OFPG15_BUCKET_MAX) {
1722 if (!bucket_ids) {
1723 const struct ofputil_bucket *bkt;
1724
1725 bucket_ids = id_pool_create(0, OFPG15_BUCKET_MAX + 1);
1726
1727 /* Mark all bucket_ids that are present in gm
1728 * as used in the pool. */
1729 LIST_FOR_EACH_REVERSE (bkt, list_node, &gm->buckets) {
1730 if (bkt == bucket) {
1731 break;
1732 }
1733 if (bkt->bucket_id <= OFPG15_BUCKET_MAX) {
1734 id_pool_add(bucket_ids, bkt->bucket_id);
1735 }
1736 }
1737 }
1738
1739 if (!id_pool_alloc_id(bucket_ids, &bucket_id)) {
1740 OVS_NOT_REACHED();
1741 }
1742 } else {
1743 bucket_id = bucket->bucket_id;
1744 }
1745
1746 ofputil_put_ofp15_bucket(bucket, bucket_id, gm->type, b, ofp_version);
1747 }
1748 ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm);
1749 ogm->command = htons(gm->command);
1750 ogm->type = gm->type;
1751 ogm->group_id = htonl(gm->group_id);
1752 ogm->command_bucket_id = htonl(gm->command_bucket_id);
1753 ogm->bucket_array_len = htons(b->size - start_ogm - sizeof *ogm);
1754
1755 /* Add group properties */
1756 if (gm->props.selection_method[0]) {
1757 ofputil_put_group_prop_ntr_selection_method(ofp_version, &gm->props, b);
1758 }
1759
1760 id_pool_destroy(bucket_ids);
1761 return b;
1762 }
1763
1764 static void
1765 bad_group_cmd(enum ofp15_group_mod_command cmd)
1766 {
1767 const char *opt_version;
1768 const char *version;
1769 const char *cmd_str;
1770
1771 switch (cmd) {
1772 case OFPGC15_ADD:
1773 case OFPGC15_MODIFY:
1774 case OFPGC15_ADD_OR_MOD:
1775 case OFPGC15_DELETE:
1776 version = "1.1";
1777 opt_version = "11";
1778 break;
1779
1780 case OFPGC15_INSERT_BUCKET:
1781 case OFPGC15_REMOVE_BUCKET:
1782 version = "1.5";
1783 opt_version = "15";
1784 break;
1785
1786 default:
1787 OVS_NOT_REACHED();
1788 }
1789
1790 switch (cmd) {
1791 case OFPGC15_ADD:
1792 cmd_str = "add-group";
1793 break;
1794
1795 case OFPGC15_MODIFY:
1796 case OFPGC15_ADD_OR_MOD:
1797 cmd_str = "mod-group";
1798 break;
1799
1800 case OFPGC15_DELETE:
1801 cmd_str = "del-group";
1802 break;
1803
1804 case OFPGC15_INSERT_BUCKET:
1805 cmd_str = "insert-bucket";
1806 break;
1807
1808 case OFPGC15_REMOVE_BUCKET:
1809 cmd_str = "remove-bucket";
1810 break;
1811
1812 default:
1813 OVS_NOT_REACHED();
1814 }
1815
1816 ovs_fatal(0, "%s needs OpenFlow %s or later (\'-O OpenFlow%s\')",
1817 cmd_str, version, opt_version);
1818
1819 }
1820
1821 /* Converts abstract group mod 'gm' into a message for OpenFlow version
1822 * 'ofp_version' and returns the message. */
1823 struct ofpbuf *
1824 ofputil_encode_group_mod(enum ofp_version ofp_version,
1825 const struct ofputil_group_mod *gm)
1826 {
1827
1828 switch (ofp_version) {
1829 case OFP11_VERSION:
1830 case OFP12_VERSION:
1831 case OFP13_VERSION:
1832 case OFP14_VERSION:
1833 if (gm->command > OFPGC11_DELETE && gm->command != OFPGC11_ADD_OR_MOD) {
1834 bad_group_cmd(gm->command);
1835 }
1836 return ofputil_encode_ofp11_group_mod(ofp_version, gm);
1837
1838 case OFP10_VERSION:
1839 case OFP15_VERSION:
1840 case OFP16_VERSION:
1841 return ofputil_encode_ofp15_group_mod(ofp_version, gm);
1842
1843 default:
1844 OVS_NOT_REACHED();
1845 }
1846 }
1847
1848 static enum ofperr
1849 ofputil_pull_ofp11_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,
1850 struct ofputil_group_mod *gm)
1851 {
1852 const struct ofp11_group_mod *ogm;
1853 enum ofperr error;
1854
1855 ogm = ofpbuf_pull(msg, sizeof *ogm);
1856 gm->command = ntohs(ogm->command);
1857 gm->type = ogm->type;
1858 gm->group_id = ntohl(ogm->group_id);
1859 gm->command_bucket_id = OFPG15_BUCKET_ALL;
1860
1861 error = ofputil_pull_ofp11_buckets(msg, msg->size, ofp_version,
1862 &gm->buckets);
1863
1864 /* OF1.3.5+ prescribes an error when an OFPGC_DELETE includes buckets. */
1865 if (!error
1866 && ofp_version >= OFP13_VERSION
1867 && gm->command == OFPGC11_DELETE
1868 && !ovs_list_is_empty(&gm->buckets)) {
1869 error = OFPERR_OFPGMFC_INVALID_GROUP;
1870 ofputil_bucket_list_destroy(&gm->buckets);
1871 }
1872
1873 return error;
1874 }
1875
1876 static enum ofperr
1877 ofputil_pull_ofp15_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,
1878 struct ofputil_group_mod *gm)
1879 {
1880 const struct ofp15_group_mod *ogm;
1881 uint16_t bucket_list_len;
1882 enum ofperr error = OFPERR_OFPGMFC_BAD_BUCKET;
1883
1884 ogm = ofpbuf_pull(msg, sizeof *ogm);
1885 gm->command = ntohs(ogm->command);
1886 gm->type = ogm->type;
1887 gm->group_id = ntohl(ogm->group_id);
1888
1889 gm->command_bucket_id = ntohl(ogm->command_bucket_id);
1890 switch (gm->command) {
1891 case OFPGC15_REMOVE_BUCKET:
1892 if (gm->command_bucket_id == OFPG15_BUCKET_ALL) {
1893 error = 0;
1894 }
1895 /* Fall through */
1896 case OFPGC15_INSERT_BUCKET:
1897 if (gm->command_bucket_id <= OFPG15_BUCKET_MAX ||
1898 gm->command_bucket_id == OFPG15_BUCKET_FIRST
1899 || gm->command_bucket_id == OFPG15_BUCKET_LAST) {
1900 error = 0;
1901 }
1902 break;
1903
1904 case OFPGC11_ADD:
1905 case OFPGC11_MODIFY:
1906 case OFPGC11_ADD_OR_MOD:
1907 case OFPGC11_DELETE:
1908 default:
1909 if (gm->command_bucket_id == OFPG15_BUCKET_ALL) {
1910 error = 0;
1911 }
1912 break;
1913 }
1914 if (error) {
1915 VLOG_WARN_RL(&rl,
1916 "group command bucket id (%u) is out of range",
1917 gm->command_bucket_id);
1918 return OFPERR_OFPGMFC_BAD_BUCKET;
1919 }
1920
1921 bucket_list_len = ntohs(ogm->bucket_array_len);
1922 if (bucket_list_len > msg->size) {
1923 return OFPERR_OFPBRC_BAD_LEN;
1924 }
1925 error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version,
1926 gm->type, &gm->buckets);
1927 if (error) {
1928 return error;
1929 }
1930
1931 error = parse_ofp15_group_properties(msg, gm->type, gm->command,
1932 &gm->props, msg->size);
1933 if (error) {
1934 ofputil_bucket_list_destroy(&gm->buckets);
1935 }
1936 return error;
1937 }
1938
1939 static enum ofperr
1940 ofputil_check_group_mod(const struct ofputil_group_mod *gm)
1941 {
1942 switch (gm->type) {
1943 case OFPGT11_INDIRECT:
1944 if (gm->command != OFPGC11_DELETE
1945 && !ovs_list_is_singleton(&gm->buckets) ) {
1946 return OFPERR_OFPGMFC_INVALID_GROUP;
1947 }
1948 break;
1949 case OFPGT11_ALL:
1950 case OFPGT11_SELECT:
1951 case OFPGT11_FF:
1952 break;
1953 default:
1954 return OFPERR_OFPGMFC_BAD_TYPE;
1955 }
1956
1957 switch (gm->command) {
1958 case OFPGC11_ADD:
1959 case OFPGC11_MODIFY:
1960 case OFPGC11_ADD_OR_MOD:
1961 case OFPGC11_DELETE:
1962 case OFPGC15_INSERT_BUCKET:
1963 break;
1964 case OFPGC15_REMOVE_BUCKET:
1965 if (!ovs_list_is_empty(&gm->buckets)) {
1966 return OFPERR_OFPGMFC_BAD_BUCKET;
1967 }
1968 break;
1969 default:
1970 return OFPERR_OFPGMFC_BAD_COMMAND;
1971 }
1972
1973 struct ofputil_bucket *bucket;
1974 LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
1975 if (bucket->weight && gm->type != OFPGT11_SELECT) {
1976 return OFPERR_OFPGMFC_INVALID_GROUP;
1977 }
1978
1979 switch (gm->type) {
1980 case OFPGT11_ALL:
1981 case OFPGT11_INDIRECT:
1982 if (ofputil_bucket_has_liveness(bucket)) {
1983 return OFPERR_OFPGMFC_WATCH_UNSUPPORTED;
1984 }
1985 break;
1986 case OFPGT11_SELECT:
1987 break;
1988 case OFPGT11_FF:
1989 if (!ofputil_bucket_has_liveness(bucket)) {
1990 return OFPERR_OFPGMFC_INVALID_GROUP;
1991 }
1992 break;
1993 default:
1994 /* Returning BAD TYPE to be consistent
1995 * though gm->type has been checked already. */
1996 return OFPERR_OFPGMFC_BAD_TYPE;
1997 }
1998 }
1999
2000 return 0;
2001 }
2002
2003 /* Converts OpenFlow group mod message 'oh' into an abstract group mod in
2004 * 'gm'. Returns 0 if successful, otherwise an OpenFlow error code. */
2005 enum ofperr
2006 ofputil_decode_group_mod(const struct ofp_header *oh,
2007 struct ofputil_group_mod *gm)
2008 {
2009 ofputil_init_group_properties(&gm->props);
2010
2011 enum ofp_version ofp_version = oh->version;
2012 struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length));
2013 ofpraw_pull_assert(&msg);
2014
2015 enum ofperr err;
2016 switch (ofp_version) {
2017 case OFP11_VERSION:
2018 case OFP12_VERSION:
2019 case OFP13_VERSION:
2020 case OFP14_VERSION:
2021 err = ofputil_pull_ofp11_group_mod(&msg, ofp_version, gm);
2022 break;
2023
2024 case OFP10_VERSION:
2025 case OFP15_VERSION:
2026 case OFP16_VERSION:
2027 err = ofputil_pull_ofp15_group_mod(&msg, ofp_version, gm);
2028 break;
2029
2030 default:
2031 OVS_NOT_REACHED();
2032 }
2033 if (err) {
2034 return err;
2035 }
2036
2037 err = ofputil_check_group_mod(gm);
2038 if (err) {
2039 ofputil_uninit_group_mod(gm);
2040 }
2041 return err;
2042 }