2 * Copyright (c) 2008-2017 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "openvswitch/ofp-group.h"
20 #include "byte-order.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"
33 VLOG_DEFINE_THIS_MODULE(ofp_group
);
35 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
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").
41 * Returns true if successful, false if 's' is not a valid OpenFlow group ID or
44 ofputil_group_from_string(const char *s
, uint32_t *group_idp
)
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 "
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". */
64 ofputil_format_group(uint32_t group_id
, struct ds
*s
)
66 char name
[MAX_GROUP_NAME_LEN
];
68 ofputil_group_to_string(group_id
, name
, sizeof name
);
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". */
78 ofputil_group_to_string(uint32_t group_id
,
79 char namebuf
[MAX_GROUP_NAME_LEN
+ 1], size_t bufsize
)
83 ovs_strlcpy(namebuf
, "ALL", bufsize
);
87 ovs_strlcpy(namebuf
, "ANY", bufsize
);
91 snprintf(namebuf
, bufsize
, "%"PRIu32
, group_id
);
96 /* Frees all of the "struct ofputil_bucket"s in the 'buckets' list. */
98 ofputil_bucket_list_destroy(struct ovs_list
*buckets
)
100 struct ofputil_bucket
*bucket
;
102 LIST_FOR_EACH_POP (bucket
, list_node
, buckets
) {
103 free(bucket
->ofpacts
);
108 /* Clones 'bucket' and its ofpacts data */
109 static struct ofputil_bucket
*
110 ofputil_bucket_clone_data(const struct ofputil_bucket
*bucket
)
112 struct ofputil_bucket
*new;
114 new = xmemdup(bucket
, sizeof *bucket
);
115 new->ofpacts
= xmemdup(bucket
->ofpacts
, bucket
->ofpacts_len
);
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'. */
127 ofputil_bucket_clone_list(struct ovs_list
*dest
, const struct ovs_list
*src
,
128 const struct ofputil_bucket
*skip
)
130 struct ofputil_bucket
*bucket
;
132 LIST_FOR_EACH (bucket
, list_node
, src
) {
133 struct ofputil_bucket
*new_bucket
;
135 if (bucket
== skip
) {
139 new_bucket
= ofputil_bucket_clone_data(bucket
);
140 ovs_list_push_back(dest
, &new_bucket
->list_node
);
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
)
149 struct ofputil_bucket
*bucket
;
151 if (bucket_id
> OFPG15_BUCKET_MAX
) {
155 LIST_FOR_EACH (bucket
, list_node
, buckets
) {
156 if (bucket
->bucket_id
== bucket_id
) {
164 /* Returns true if more than one bucket in the list 'buckets'
165 * have the same bucket id. Returns false otherwise. */
167 ofputil_bucket_check_duplicate_id(const struct ovs_list
*buckets
)
169 struct ofputil_bucket
*i
, *j
;
171 LIST_FOR_EACH (i
, list_node
, buckets
) {
172 LIST_FOR_EACH_REVERSE (j
, list_node
, buckets
) {
176 if (i
->bucket_id
== j
->bucket_id
) {
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
)
190 static struct ofputil_bucket
*bucket
;
192 ASSIGN_CONTAINER(bucket
, ovs_list_front(buckets
), list_node
);
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
)
202 static struct ofputil_bucket
*bucket
;
204 ASSIGN_CONTAINER(bucket
, ovs_list_back(buckets
), list_node
);
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
213 * Group statistics include packet and byte counts for each group. */
215 ofputil_encode_group_stats_request(enum ofp_version ofp_version
,
218 struct ofpbuf
*msg
= ofpraw_alloc((ofp_version
== OFP10_VERSION
219 ? OFPRAW_NXST_GROUP_REQUEST
220 : OFPRAW_OFPST11_GROUP_REQUEST
),
222 struct ofp11_group_stats_request
*req
= ofpbuf_put_zeros(msg
, sizeof *req
);
223 req
->group_id
= htonl(group_id
);
229 ofputil_uninit_group_desc(struct ofputil_group_desc
*gd
)
231 ofputil_bucket_list_destroy(&gd
->buckets
);
232 ofputil_group_properties_destroy(&gd
->props
);
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
239 ofputil_decode_group_desc_request(const struct ofp_header
*oh
)
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
) {
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
);
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
259 * Group descriptions include the bucket and action configuration for each
262 ofputil_encode_group_desc_request(enum ofp_version ofp_version
,
265 struct ofpbuf
*request
;
267 switch (ofp_version
) {
272 request
= ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST
,
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
),
283 req
= ofpbuf_put_zeros(request
, sizeof *req
);
284 req
->group_id
= htonl(group_id
);
295 ofputil_group_bucket_counters_to_ofp11(const struct ofputil_group_stats
*gs
,
296 struct ofp11_bucket_counter bucket_cnts
[])
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
);
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
[])
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
);
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
[])
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
);
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(). */
335 ofputil_append_group_stats(struct ovs_list
*replies
,
336 const struct ofputil_group_stats
*gs
)
338 size_t bucket_counter_size
;
339 struct ofp11_bucket_counter
*bucket_counters
;
342 bucket_counter_size
= gs
->n_buckets
* sizeof(struct ofp11_bucket_counter
);
344 switch (ofpmp_version(replies
)) {
347 struct ofp11_group_stats
*gs11
;
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
);
360 case OFP16_VERSION
: {
361 struct ofp13_group_stats
*gs13
;
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
);
374 /* Returns an OpenFlow group features request for OpenFlow version
377 ofputil_encode_group_features_request(enum ofp_version ofp_version
)
379 return ofpraw_alloc((ofp_version
< OFP12_VERSION
380 ? OFPRAW_NXST_GROUP_FEATURES_REQUEST
381 : OFPRAW_OFPST12_GROUP_FEATURES_REQUEST
),
385 /* Returns a OpenFlow message that encodes 'features' properly as a reply to
386 * group features request 'request'. */
388 ofputil_encode_group_features_reply(
389 const struct ofputil_group_features
*features
,
390 const struct ofp_header
*request
)
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
],
406 /* Decodes group features reply 'oh' into 'features'. */
408 ofputil_decode_group_features_reply(const struct ofp_header
*oh
,
409 struct ofputil_group_features
*features
)
411 const struct ofp12_group_features_stats
*ogf
= ofpmsg_body(oh
);
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
);
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. */
427 ofputil_decode_group_stats_request(const struct ofp_header
*request
,
430 const struct ofp11_group_stats_request
*gsr11
= ofpmsg_body(request
);
431 *group_id
= ntohl(gsr11
->group_id
);
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.
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.
444 * Returns 0 if successful, EOF if no replies were left in this 'msg',
445 * otherwise a positive errno value. */
447 ofputil_decode_group_stats_reply(struct ofpbuf
*msg
,
448 struct ofputil_group_stats
*gs
)
450 struct ofp11_bucket_counter
*obc
;
451 struct ofp11_group_stats
*ogs11
;
458 gs
->bucket_stats
= NULL
;
459 error
= (msg
->header
? ofpraw_decode(&raw
, msg
->header
)
460 : ofpraw_pull(&raw
, msg
));
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
;
477 base_len
= sizeof *ogs13
;
478 ogs13
= ofpbuf_try_pull(msg
, sizeof *ogs13
);
481 gs
->duration_sec
= ntohl(ogs13
->duration_sec
);
482 gs
->duration_nsec
= ntohl(ogs13
->duration_nsec
);
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
;
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
;
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
);
507 gs
->n_buckets
= (length
- base_len
) / sizeof *obc
;
508 obc
= ofpbuf_try_pull(msg
, gs
->n_buckets
* sizeof *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
;
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
);
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
)
530 char *pos
, *key
, *value
;
531 struct ofpbuf ofpacts
;
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
;
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
);
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
);
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
,
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
);
569 ds_put_format(&actions
, "%s(%s),", key
, value
);
573 ds_destroy(&actions
);
578 if (!actions
.length
) {
579 return xstrdup("bucket must specify actions");
581 if (group_type
== OFPGT11_FF
&& !ofputil_bucket_has_liveness(bucket
)) {
582 return xstrdup("fast failover bucket requires watch_port or "
585 ds_chomp(&actions
, ',');
587 ofpbuf_init(&ofpacts
, 0);
588 struct ofpact_parse_params pp
= {
589 .port_map
= port_map
,
590 .table_map
= table_map
,
592 .usable_protocols
= usable_protocols
,
594 error
= ofpacts_parse_actions(ds_cstr(&actions
), &pp
);
595 ds_destroy(&actions
);
597 ofpbuf_uninit(&ofpacts
);
600 bucket
->ofpacts
= ofpacts
.data
;
601 bucket
->ofpacts_len
= ofpacts
.size
;
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
)
611 char *name
, *value_str
;
613 while (ofputil_parse_key_value(&s
, &name
, &value_str
)) {
614 const struct mf_field
*mf
= mf_from_name(name
);
618 union mf_value value
;
620 if (bitmap_is_set(fa
->used
.bm
, mf
->id
)) {
621 return xasprintf("%s: duplicate field", name
);
625 error
= mf_parse_value(mf
, value_str
, port_map
, &value
);
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
);
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
);
644 memset(&value
, 0xff, mf
->n_bytes
);
647 field_array_set(mf
->id
, &value
, fa
);
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
;
655 *usable_protocols
&= mf
->usable_protocols_bitwise
;
658 return xasprintf("%s: unknown field %s", s
, name
);
665 static char * OVS_WARN_UNUSED_RESULT
666 parse_ofp_group_mod_str__(struct ofputil_group_mod
*gm
, int command
,
668 const struct ofputil_port_map
*port_map
,
669 const struct ofputil_table_map
*table_map
,
670 enum ofputil_protocol
*usable_protocols
)
673 F_GROUP_TYPE
= 1 << 0,
675 F_COMMAND_BUCKET_ID
= 1 << 2,
676 F_COMMAND_BUCKET_ID_ALL
= 1 << 3,
678 bool had_type
= false;
679 bool had_command_bucket_id
= false;
680 struct ofputil_bucket
*bucket
;
683 *usable_protocols
= OFPUTIL_P_ANY
;
688 string
+= strspn(string
, " \t\r\n"); /* Skip white space. */
689 len
= strcspn(string
, ", \t\r\n"); /* Get length of the first token. */
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
;
705 command
= OFPGC11_ADD
;
712 fields
= F_GROUP_TYPE
| F_BUCKETS
;
720 fields
= F_GROUP_TYPE
| F_BUCKETS
;
723 case OFPGC11_ADD_OR_MOD
:
724 fields
= F_GROUP_TYPE
| F_BUCKETS
;
727 case OFPGC15_INSERT_BUCKET
:
728 fields
= F_BUCKETS
| F_COMMAND_BUCKET_ID
;
729 *usable_protocols
&= OFPUTIL_P_OF10_ANY
| OFPUTIL_P_OF15_UP
;
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
;
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
;
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=");
756 if (!(fields
& F_BUCKETS
)) {
757 error
= xstrdup("bucket is not needed");
763 /* Parse everything before the buckets. */
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");
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
;
779 error
= str_to_u32(value
, &gm
->command_bucket_id
);
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
);
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");
797 had_command_bucket_id
= true;
798 } else if (!strcmp(name
, "group_id")) {
799 if(!strcmp(value
, "all")) {
800 gm
->group_id
= OFPG_ALL
;
802 error
= str_to_u32(value
, &gm
->group_id
);
806 if (gm
->group_id
!= OFPG_ALL
&& gm
->group_id
> OFPG_MAX
) {
807 error
= xasprintf("invalid group id %"PRIu32
,
812 } else if (!strcmp(name
, "type")){
813 if (!(fields
& F_GROUP_TYPE
)) {
814 error
= xstrdup("type is not needed");
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
;
827 error
= xasprintf("invalid group type %s", value
);
831 } else if (!strcmp(name
, "selection_method")) {
832 if (!(fields
& F_GROUP_TYPE
)) {
833 error
= xstrdup("selection method is not needed");
836 if (strlen(value
) >= NTR_MAX_SELECTION_METHOD_LEN
) {
837 error
= xasprintf("selection method is longer than %u"
839 NTR_MAX_SELECTION_METHOD_LEN
- 1);
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");
851 error
= str_to_u64(value
, &gm
->props
.selection_method_param
);
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");
861 error
= parse_select_group_field(value
, port_map
,
867 *usable_protocols
&= OFPUTIL_P_OF10_ANY
| OFPUTIL_P_OF15_UP
;
869 error
= xasprintf("unknown keyword %s", name
);
873 if (gm
->group_id
== OFPG_ANY
) {
874 error
= xstrdup("must specify a group_id");
877 if (fields
& F_GROUP_TYPE
&& !had_type
) {
878 error
= xstrdup("must specify a type");
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\"");
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\"");
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");
901 } else if (had_command_bucket_id
) {
902 error
= xstrdup("command bucket id is not needed");
906 /* Now parse the buckets, if any. */
910 bkt_str
= strchr(bkt_str
+ 1, '=');
912 error
= xstrdup("must specify bucket content");
917 next_bkt_str
= strstr(bkt_str
, "bucket=");
919 *next_bkt_str
= '\0';
922 bucket
= xzalloc(sizeof(struct ofputil_bucket
));
923 error
= parse_bucket_str(bucket
, bkt_str
, port_map
, table_map
,
924 gm
->type
, usable_protocols
);
929 ovs_list_push_back(&gm
->buckets
, &bucket
->list_node
);
931 if (gm
->type
!= OFPGT11_SELECT
&& bucket
->weight
) {
932 error
= xstrdup("Only select groups can have bucket weights.");
936 bkt_str
= next_bkt_str
;
938 if (gm
->type
== OFPGT11_INDIRECT
&& !ovs_list_is_short(&gm
->buckets
)) {
939 error
= xstrdup("Indirect groups can have at most one bucket.");
945 ofputil_uninit_group_mod(gm
);
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".
953 char * OVS_WARN_UNUSED_RESULT
954 parse_ofp_group_mod_str(struct ofputil_group_mod
*gm
, int command
,
956 const struct ofputil_port_map
*port_map
,
957 const struct ofputil_table_map
*table_map
,
958 enum ofputil_protocol
*usable_protocols
)
960 char *string
= xstrdup(str_
);
961 char *error
= parse_ofp_group_mod_str__(gm
, command
, string
, port_map
,
962 table_map
, usable_protocols
);
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".
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
,
976 struct ofputil_group_mod
**gms
, size_t *n_gms
,
977 enum ofputil_protocol
*usable_protocols
)
979 size_t allocated_gms
;
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
));
993 allocated_gms
= *n_gms
;
996 *usable_protocols
= OFPUTIL_P_ANY
;
997 while (!ds_get_preprocessed_line(&s
, stream
, &line_number
)) {
998 enum ofputil_protocol usable
;
1001 if (*n_gms
>= allocated_gms
) {
1002 struct ofputil_group_mod
*new_gms
;
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
);
1011 error
= parse_ofp_group_mod_str(&(*gms
)[*n_gms
], command
, ds_cstr(&s
),
1012 port_map
, table_map
, &usable
);
1016 for (i
= 0; i
< *n_gms
; i
++) {
1017 ofputil_uninit_group_mod(&(*gms
)[i
]);
1024 if (stream
!= stdin
) {
1028 char *ret
= xasprintf("%s:%d: %s", file_name
, line_number
, error
);
1032 *usable_protocols
&= usable
;
1037 if (stream
!= stdin
) {
1044 ofputil_put_ofp11_bucket(const struct ofputil_bucket
*bucket
,
1045 struct ofpbuf
*openflow
, enum ofp_version ofp_version
)
1047 struct ofp11_bucket
*ob
;
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
);
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
)
1066 struct ofp15_bucket
*ob
;
1067 size_t start
, actions_start
, actions_len
;
1069 start
= openflow
->size
;
1070 ofpbuf_put_zeros(openflow
, sizeof *ob
);
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
;
1077 if (group_type
== OFPGT11_SELECT
) {
1078 ofpprop_put_u16(openflow
, OFPGBPT15_WEIGHT
, bucket
->weight
);
1080 if (bucket
->watch_port
!= OFPP_ANY
) {
1081 ofpprop_put_be32(openflow
, OFPGBPT15_WATCH_PORT
,
1082 ofputil_port_to_ofp11(bucket
->watch_port
));
1084 if (bucket
->watch_group
!= OFPG_ANY
) {
1085 ofpprop_put_u32(openflow
, OFPGBPT15_WATCH_GROUP
, bucket
->watch_group
);
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
);
1095 ofputil_put_group_prop_ntr_selection_method(enum ofp_version ofp_version
,
1096 const struct ofputil_group_props
*gp
,
1097 struct ofpbuf
*openflow
)
1099 struct ntr_group_prop_selection_method
*prop
;
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
);
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
)
1120 struct ofpbuf
*reply
= ofpbuf_from_list(ovs_list_back(replies
));
1121 struct ofp11_group_desc_stats
*ogds
;
1122 struct ofputil_bucket
*bucket
;
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
);
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
);
1135 ofpmp_postappend(replies
, start_ogds
);
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
)
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
;
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
);
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
);
1161 /* Add group properties */
1162 if (gds
->props
.selection_method
[0]) {
1163 ofputil_put_group_prop_ntr_selection_method(version
, &gds
->props
,
1166 ogds
= ofpbuf_at_assert(reply
, start_ogds
, sizeof *ogds
);
1167 ogds
->length
= htons(reply
->size
- start_ogds
);
1169 ofpmp_postappend(replies
, start_ogds
);
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(). */
1176 ofputil_append_group_desc_reply(const struct ofputil_group_desc
*gds
,
1177 const struct ovs_list
*buckets
,
1178 struct ovs_list
*replies
)
1180 enum ofp_version version
= ofpmp_version(replies
);
1188 ofputil_append_ofp11_group_desc_reply(gds
, buckets
, replies
, version
);
1194 ofputil_append_ofp15_group_desc_reply(gds
, buckets
, replies
, version
);
1203 ofputil_pull_ofp11_buckets(struct ofpbuf
*msg
, size_t buckets_length
,
1204 enum ofp_version version
, struct ovs_list
*buckets
)
1206 struct ofp11_bucket
*ob
;
1207 uint32_t bucket_id
= 0;
1209 ovs_list_init(buckets
);
1210 while (buckets_length
> 0) {
1211 struct ofputil_bucket
*bucket
;
1212 struct ofpbuf ofpacts
;
1216 ob
= (buckets_length
>= sizeof *ob
1217 ? ofpbuf_try_pull(msg
, sizeof *ob
)
1220 VLOG_WARN_RL(&rl
, "buckets end with %"PRIuSIZE
" leftover bytes",
1222 ofputil_bucket_list_destroy(buckets
);
1223 return OFPERR_OFPGMFC_BAD_BUCKET
;
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
;
1239 buckets_length
-= ob_len
;
1241 ofpbuf_init(&ofpacts
, 0);
1242 error
= ofpacts_pull_openflow_actions(msg
, ob_len
- sizeof *ob
,
1243 version
, NULL
, NULL
, &ofpacts
);
1245 ofpbuf_uninit(&ofpacts
);
1246 ofputil_bucket_list_destroy(buckets
);
1250 bucket
= xzalloc(sizeof *bucket
);
1251 bucket
->weight
= ntohs(ob
->weight
);
1252 error
= ofputil_port_from_ofp11(ob
->watch_port
, &bucket
->watch_port
);
1254 ofpbuf_uninit(&ofpacts
);
1255 ofputil_bucket_list_destroy(buckets
);
1257 return OFPERR_OFPGMFC_BAD_WATCH
;
1259 bucket
->watch_group
= ntohl(ob
->watch_group
);
1260 bucket
->bucket_id
= bucket_id
++;
1262 bucket
->ofpacts
= ofpbuf_steal_data(&ofpacts
);
1263 bucket
->ofpacts_len
= ofpacts
.size
;
1264 ovs_list_push_back(buckets
, &bucket
->list_node
);
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
)
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);
1285 ofpbuf_init(&ofpacts
, 0);
1287 struct ofp15_bucket
*ob
= ofpbuf_try_pull(msg
, sizeof *ob
);
1289 VLOG_WARN_RL(&rl
, "buckets end with %"PRIuSIZE
1290 " leftover bytes", buckets_length
);
1294 ob_len
= ntohs(ob
->len
);
1295 actions_len
= ntohs(ob
->action_array_len
);
1297 if (ob_len
< sizeof *ob
) {
1298 VLOG_WARN_RL(&rl
, "OpenFlow message bucket length "
1299 "%"PRIuSIZE
" is not valid", ob_len
);
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
);
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
);
1313 buckets_length
-= ob_len
;
1315 err
= ofpacts_pull_openflow_actions(msg
, actions_len
, version
,
1316 NULL
, NULL
, &ofpacts
);
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
;
1328 err
= ofpprop_pull(&properties
, &payload
, &type
);
1334 case OFPGBPT15_WEIGHT
:
1335 err
= ofpprop_parse_be16(&payload
, &weight
);
1338 case OFPGBPT15_WATCH_PORT
:
1339 err
= ofpprop_parse_be32(&payload
, &watch_port
);
1342 case OFPGBPT15_WATCH_GROUP
:
1343 err
= ofpprop_parse_be32(&payload
, &watch_group
);
1347 err
= OFPPROP_UNKNOWN(false, "group bucket", type
);
1356 bucket
= xzalloc(sizeof *bucket
);
1358 bucket
->weight
= ntohs(weight
);
1359 err
= ofputil_port_from_ofp11(watch_port
, &bucket
->watch_port
);
1361 err
= OFPERR_OFPGMFC_BAD_WATCH
;
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",
1369 err
= OFPERR_OFPGMFC_BAD_BUCKET
;
1373 bucket
->ofpacts
= ofpbuf_steal_data(&ofpacts
);
1374 bucket
->ofpacts_len
= ofpacts
.size
;
1375 ovs_list_push_back(buckets
, &bucket
->list_node
);
1381 ofpbuf_uninit(&ofpacts
);
1382 ofputil_bucket_list_destroy(buckets
);
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
;
1396 ofputil_init_group_properties(struct ofputil_group_props
*gp
)
1398 memset(gp
, 0, sizeof *gp
);
1402 ofputil_group_properties_copy(struct ofputil_group_props
*to
,
1403 const struct ofputil_group_props
*from
)
1406 to
->fields
.values
= xmemdup(from
->fields
.values
, from
->fields
.values_size
);
1410 ofputil_group_properties_destroy(struct ofputil_group_props
*gp
)
1412 free(gp
->fields
.values
);
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
)
1421 struct ntr_group_prop_selection_method
*prop
= payload
->data
;
1422 size_t fields_len
, method_len
;
1425 switch (group_type
) {
1426 case OFPGT11_SELECT
:
1429 case OFPGT11_INDIRECT
:
1431 OFPPROP_LOG(&rl
, false, "ntr selection method property is "
1432 "only allowed for select groups");
1433 return OFPERR_OFPBPC_BAD_VALUE
;
1438 switch (group_cmd
) {
1440 case OFPGC15_MODIFY
:
1441 case OFPGC15_ADD_OR_MOD
:
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
;
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
;
1459 method_len
= strnlen(prop
->selection_method
, NTR_MAX_SELECTION_METHOD_LEN
);
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
;
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
;
1474 /* 'method_len' is now non-zero. */
1476 strcpy(gp
->selection_method
, prop
->selection_method
);
1477 gp
->selection_method_param
= ntohll(prop
->selection_method_param
);
1479 ofpbuf_pull(payload
, sizeof *prop
);
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
;
1488 error
= oxm_pull_field_array(payload
->data
, fields_len
,
1491 OFPPROP_LOG(&rl
, false,
1492 "ntr selection method fields are invalid");
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
)
1506 struct ofpbuf properties
= ofpbuf_const_initializer(
1507 ofpbuf_pull(msg
, properties_len
), properties_len
);
1508 while (properties
.size
> 0) {
1509 struct ofpbuf payload
;
1513 error
= ofpprop_pull(&properties
, &payload
, &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
,
1526 error
= OFPPROP_UNKNOWN(false, "group", type
);
1539 ofputil_decode_ofp11_group_desc_reply(struct ofputil_group_desc
*gd
,
1541 enum ofp_version version
)
1543 struct ofp11_group_desc_stats
*ogds
;
1547 ofpraw_pull_assert(msg
);
1554 ogds
= ofpbuf_try_pull(msg
, sizeof *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
;
1560 gd
->type
= ogds
->type
;
1561 gd
->group_id
= ntohl(ogds
->group_id
);
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
;
1570 return ofputil_pull_ofp11_buckets(msg
, length
- sizeof *ogds
, version
,
1575 ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc
*gd
,
1577 enum ofp_version version
)
1579 struct ofp15_group_desc_stats
*ogds
;
1580 uint16_t length
, bucket_list_len
;
1584 ofpraw_pull_assert(msg
);
1591 ogds
= ofpbuf_try_pull(msg
, sizeof *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
;
1597 gd
->type
= ogds
->type
;
1598 gd
->group_id
= ntohl(ogds
->group_id
);
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
;
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
;
1613 error
= ofputil_pull_ofp15_buckets(msg
, bucket_list_len
, version
, gd
->type
,
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
);
1631 ofputil_bucket_list_destroy(&gd
->buckets
);
1636 /* Converts a group description reply in 'msg' into an abstract
1637 * ofputil_group_desc in 'gd'.
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.
1644 * Returns 0 if successful, EOF if no replies were left in this 'msg',
1645 * otherwise a positive errno value. */
1647 ofputil_decode_group_desc_reply(struct ofputil_group_desc
*gd
,
1648 struct ofpbuf
*msg
, enum ofp_version version
)
1650 ofputil_init_group_properties(&gd
->props
);
1658 return ofputil_decode_ofp11_group_desc_reply(gd
, msg
, version
);
1663 return ofputil_decode_ofp15_group_desc_reply(gd
, msg
, version
);
1671 ofputil_uninit_group_mod(struct ofputil_group_mod
*gm
)
1673 ofputil_bucket_list_destroy(&gm
->buckets
);
1674 ofputil_group_properties_destroy(&gm
->props
);
1677 static struct ofpbuf
*
1678 ofputil_encode_ofp11_group_mod(enum ofp_version ofp_version
,
1679 const struct ofputil_group_mod
*gm
)
1682 struct ofp11_group_mod
*ogm
;
1684 struct ofputil_bucket
*bucket
;
1686 b
= ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD
, ofp_version
, 0);
1687 start_ogm
= b
->size
;
1688 ofpbuf_put_zeros(b
, sizeof *ogm
);
1690 LIST_FOR_EACH (bucket
, list_node
, &gm
->buckets
) {
1691 ofputil_put_ofp11_bucket(bucket
, b
, ofp_version
);
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
);
1701 static struct ofpbuf
*
1702 ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version
,
1703 const struct ofputil_group_mod
*gm
)
1706 struct ofp15_group_mod
*ogm
;
1708 struct ofputil_bucket
*bucket
;
1709 struct id_pool
*bucket_ids
= NULL
;
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
);
1717 LIST_FOR_EACH (bucket
, list_node
, &gm
->buckets
) {
1720 /* Generate a bucket id if none was supplied */
1721 if (bucket
->bucket_id
> OFPG15_BUCKET_MAX
) {
1723 const struct ofputil_bucket
*bkt
;
1725 bucket_ids
= id_pool_create(0, OFPG15_BUCKET_MAX
+ 1);
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
) {
1733 if (bkt
->bucket_id
<= OFPG15_BUCKET_MAX
) {
1734 id_pool_add(bucket_ids
, bkt
->bucket_id
);
1739 if (!id_pool_alloc_id(bucket_ids
, &bucket_id
)) {
1743 bucket_id
= bucket
->bucket_id
;
1746 ofputil_put_ofp15_bucket(bucket
, bucket_id
, gm
->type
, b
, ofp_version
);
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
);
1755 /* Add group properties */
1756 if (gm
->props
.selection_method
[0]) {
1757 ofputil_put_group_prop_ntr_selection_method(ofp_version
, &gm
->props
, b
);
1760 id_pool_destroy(bucket_ids
);
1765 bad_group_cmd(enum ofp15_group_mod_command cmd
)
1767 const char *opt_version
;
1768 const char *version
;
1769 const char *cmd_str
;
1773 case OFPGC15_MODIFY
:
1774 case OFPGC15_ADD_OR_MOD
:
1775 case OFPGC15_DELETE
:
1780 case OFPGC15_INSERT_BUCKET
:
1781 case OFPGC15_REMOVE_BUCKET
:
1792 cmd_str
= "add-group";
1795 case OFPGC15_MODIFY
:
1796 case OFPGC15_ADD_OR_MOD
:
1797 cmd_str
= "mod-group";
1800 case OFPGC15_DELETE
:
1801 cmd_str
= "del-group";
1804 case OFPGC15_INSERT_BUCKET
:
1805 cmd_str
= "insert-bucket";
1808 case OFPGC15_REMOVE_BUCKET
:
1809 cmd_str
= "remove-bucket";
1816 ovs_fatal(0, "%s needs OpenFlow %s or later (\'-O OpenFlow%s\')",
1817 cmd_str
, version
, opt_version
);
1821 /* Converts abstract group mod 'gm' into a message for OpenFlow version
1822 * 'ofp_version' and returns the message. */
1824 ofputil_encode_group_mod(enum ofp_version ofp_version
,
1825 const struct ofputil_group_mod
*gm
)
1828 switch (ofp_version
) {
1833 if (gm
->command
> OFPGC11_DELETE
&& gm
->command
!= OFPGC11_ADD_OR_MOD
) {
1834 bad_group_cmd(gm
->command
);
1836 return ofputil_encode_ofp11_group_mod(ofp_version
, gm
);
1841 return ofputil_encode_ofp15_group_mod(ofp_version
, gm
);
1849 ofputil_pull_ofp11_group_mod(struct ofpbuf
*msg
, enum ofp_version ofp_version
,
1850 struct ofputil_group_mod
*gm
)
1852 const struct ofp11_group_mod
*ogm
;
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
;
1861 error
= ofputil_pull_ofp11_buckets(msg
, msg
->size
, ofp_version
,
1864 /* OF1.3.5+ prescribes an error when an OFPGC_DELETE includes buckets. */
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
);
1877 ofputil_pull_ofp15_group_mod(struct ofpbuf
*msg
, enum ofp_version ofp_version
,
1878 struct ofputil_group_mod
*gm
)
1880 const struct ofp15_group_mod
*ogm
;
1881 uint16_t bucket_list_len
;
1882 enum ofperr error
= OFPERR_OFPGMFC_BAD_BUCKET
;
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
);
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
) {
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
) {
1905 case OFPGC11_MODIFY
:
1906 case OFPGC11_ADD_OR_MOD
:
1907 case OFPGC11_DELETE
:
1909 if (gm
->command_bucket_id
== OFPG15_BUCKET_ALL
) {
1916 "group command bucket id (%u) is out of range",
1917 gm
->command_bucket_id
);
1918 return OFPERR_OFPGMFC_BAD_BUCKET
;
1921 bucket_list_len
= ntohs(ogm
->bucket_array_len
);
1922 if (bucket_list_len
> msg
->size
) {
1923 return OFPERR_OFPBRC_BAD_LEN
;
1925 error
= ofputil_pull_ofp15_buckets(msg
, bucket_list_len
, ofp_version
,
1926 gm
->type
, &gm
->buckets
);
1931 error
= parse_ofp15_group_properties(msg
, gm
->type
, gm
->command
,
1932 &gm
->props
, msg
->size
);
1934 ofputil_bucket_list_destroy(&gm
->buckets
);
1940 ofputil_check_group_mod(const struct ofputil_group_mod
*gm
)
1943 case OFPGT11_INDIRECT
:
1944 if (gm
->command
!= OFPGC11_DELETE
1945 && !ovs_list_is_singleton(&gm
->buckets
) ) {
1946 return OFPERR_OFPGMFC_INVALID_GROUP
;
1950 case OFPGT11_SELECT
:
1954 return OFPERR_OFPGMFC_BAD_TYPE
;
1957 switch (gm
->command
) {
1959 case OFPGC11_MODIFY
:
1960 case OFPGC11_ADD_OR_MOD
:
1961 case OFPGC11_DELETE
:
1962 case OFPGC15_INSERT_BUCKET
:
1964 case OFPGC15_REMOVE_BUCKET
:
1965 if (!ovs_list_is_empty(&gm
->buckets
)) {
1966 return OFPERR_OFPGMFC_BAD_BUCKET
;
1970 return OFPERR_OFPGMFC_BAD_COMMAND
;
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
;
1981 case OFPGT11_INDIRECT
:
1982 if (ofputil_bucket_has_liveness(bucket
)) {
1983 return OFPERR_OFPGMFC_WATCH_UNSUPPORTED
;
1986 case OFPGT11_SELECT
:
1989 if (!ofputil_bucket_has_liveness(bucket
)) {
1990 return OFPERR_OFPGMFC_INVALID_GROUP
;
1994 /* Returning BAD TYPE to be consistent
1995 * though gm->type has been checked already. */
1996 return OFPERR_OFPGMFC_BAD_TYPE
;
2003 /* Converts OpenFlow group mod message 'oh' into an abstract group mod in
2004 * 'gm'. Returns 0 if successful, otherwise an OpenFlow error code. */
2006 ofputil_decode_group_mod(const struct ofp_header
*oh
,
2007 struct ofputil_group_mod
*gm
)
2009 ofputil_init_group_properties(&gm
->props
);
2011 enum ofp_version ofp_version
= oh
->version
;
2012 struct ofpbuf msg
= ofpbuf_const_initializer(oh
, ntohs(oh
->length
));
2013 ofpraw_pull_assert(&msg
);
2016 switch (ofp_version
) {
2021 err
= ofputil_pull_ofp11_group_mod(&msg
, ofp_version
, gm
);
2027 err
= ofputil_pull_ofp15_group_mod(&msg
, ofp_version
, gm
);
2037 err
= ofputil_check_group_mod(gm
);
2039 ofputil_uninit_group_mod(gm
);