diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | include/openflow/openflow-1.5.h | 3 | ||||
-rw-r--r-- | include/openvswitch/ofp-errors.h | 54 | ||||
-rw-r--r-- | include/openvswitch/ofp-msgs.h | 35 | ||||
-rw-r--r-- | lib/nx-match.c | 11 | ||||
-rw-r--r-- | lib/ofp-group.c | 120 | ||||
-rw-r--r-- | lib/ofp-print.c | 2 | ||||
-rw-r--r-- | tests/ofp-print.at | 126 | ||||
-rw-r--r-- | tests/ofproto.at | 93 | ||||
-rw-r--r-- | utilities/ovs-ofctl.8.in | 14 |
10 files changed, 312 insertions, 149 deletions
@@ -15,7 +15,8 @@ Post-v2.9.0 - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". - OpenFlow: * OFPT_ROLE_STATUS is now available in OpenFlow 1.3. - * OpenFlow 1.5 extensibile statistics (OXS) now implemented. + * OpenFlow 1.5 extensible statistics (OXS) now implemented. + * New OpenFlow 1.0 extensions for group support. - Linux kernel 4.14 * Add support for compiling OVS with the latest Linux 4.14 kernel - ovn: diff --git a/include/openflow/openflow-1.5.h b/include/openflow/openflow-1.5.h index d9b867cf2..c146052af 100644 --- a/include/openflow/openflow-1.5.h +++ b/include/openflow/openflow-1.5.h @@ -77,12 +77,11 @@ struct ofp15_bucket { 64-bit aligned. */ ovs_be16 action_array_len; /* Length of all actions in bytes. */ ovs_be32 bucket_id; /* Bucket Id used to identify bucket*/ - /* Followed by exactly len - 8 bytes of group bucket properties. */ /* Followed by: * - Exactly 'action_array_len' bytes containing an array of * struct ofp_action_*. * - Zero or more bytes of group bucket properties to fill out the - * overall length in header.length. */ + * overall length in 'len'. */ }; OFP_ASSERT(sizeof(struct ofp15_bucket) == 8); diff --git a/include/openvswitch/ofp-errors.h b/include/openvswitch/ofp-errors.h index 16feacb55..6e8e55ab4 100644 --- a/include/openvswitch/ofp-errors.h +++ b/include/openvswitch/ofp-errors.h @@ -254,7 +254,7 @@ enum ofperr { /* OF1.0+(2,8). Problem validating output queue. */ OFPERR_OFPBAC_BAD_QUEUE, - /* OF1.1+(2,9). Invalid group id in output action. */ + /* NX1.0(2,9), OF1.1+(2,9). Invalid group id in output action. */ OFPERR_OFPBAC_BAD_OUT_GROUP, /* NX1.0(1,522), OF1.1+(2,10). Action can't apply for this match or a @@ -460,63 +460,65 @@ enum ofperr { /* ## OFPET_GROUP_MOD_FAILED ## */ /* ## ---------------------- ## */ - /* OF1.1+(6,0). Group not added because a group ADD attempted to replace - * an already-present group. */ + /* NX1.0(6,0), OF1.1+(6,0). Group not added because a group ADD attempted + * to replace an already-present group. */ OFPERR_OFPGMFC_GROUP_EXISTS, - /* OF1.1+(6,1). Group not added because Group specified is invalid. */ + /* NX1.0(6,1), OF1.1+(6,1). Group not added because Group specified is + * invalid. */ OFPERR_OFPGMFC_INVALID_GROUP, - /* OF1.1+(6,2). Switch does not support unequal load sharing with select - * groups. */ + /* NX1.0(6,2), OF1.1+(6,2). Switch does not support unequal load sharing + * with select groups. */ OFPERR_OFPGMFC_WEIGHT_UNSUPPORTED, - /* OF1.1+(6,3). The group table is full. */ + /* NX1.0(6,3), OF1.1+(6,3). The group table is full. */ OFPERR_OFPGMFC_OUT_OF_GROUPS, - /* OF1.1+(6,4). The maximum number of action buckets for a group has been - * exceeded. */ + /* NX1.0(6,4), OF1.1+(6,4). The maximum number of action buckets for a + * group has been exceeded. */ OFPERR_OFPGMFC_OUT_OF_BUCKETS, - /* OF1.1+(6,5). Switch does not support groups that forward to groups. */ + /* NX1.0(6,5), OF1.1+(6,5). Switch does not support groups that forward to + * groups. */ OFPERR_OFPGMFC_CHAINING_UNSUPPORTED, - /* OF1.1+(6,6). This group cannot watch the watch_port or watch_group - * specified. */ + /* NX1.0(6,6), OF1.1+(6,6). This group cannot watch the watch_port or + * watch_group specified. */ OFPERR_OFPGMFC_WATCH_UNSUPPORTED, - /* OF1.1+(6,7). Group entry would cause a loop. */ + /* NX1.0(6,7), OF1.1+(6,7). Group entry would cause a loop. */ OFPERR_OFPGMFC_LOOP, - /* OF1.1+(6,8). Group not modified because a group MODIFY attempted to - * modify a non-existent group. */ + /* NX1.0(6,8), OF1.1+(6,8). Group not modified because a group MODIFY + * attempted to modify a non-existent group. */ OFPERR_OFPGMFC_UNKNOWN_GROUP, - /* OF1.2+(6,9). Group not deleted because another - group is forwarding to it. */ + /* NX1.0(6,9), OF1.2+(6,9). Group not deleted because another group is + * forwarding to it. */ OFPERR_OFPGMFC_CHAINED_GROUP, - /* OF1.2+(6,10). Unsupported or unknown group type. */ + /* NX1.0(6,10), OF1.2+(6,10). Unsupported or unknown group type. */ OFPERR_OFPGMFC_BAD_TYPE, - /* OF1.2+(6,11). Unsupported or unknown command. */ + /* NX1.0(6,11), OF1.2+(6,11). Unsupported or unknown command. */ OFPERR_OFPGMFC_BAD_COMMAND, - /* OF1.2+(6,12). Error in bucket. */ + /* NX1.0(6,12), OF1.2+(6,12). Error in bucket. */ OFPERR_OFPGMFC_BAD_BUCKET, - /* OF1.2+(6,13). Error in watch port/group. */ + /* NX1.0(6,13), OF1.2+(6,13). Error in watch port/group. */ OFPERR_OFPGMFC_BAD_WATCH, - /* OF1.2+(6,14). Permissions error. */ + /* NX1.0(6,14), OF1.2+(6,14). Permissions error. */ OFPERR_OFPGMFC_EPERM, - /* OF1.5+(6,15). Invalid bucket identifier used in - * INSERT BUCKET or REMOVE BUCKET command. */ + /* NX1.0(6,15), OF1.5+(6,15). Invalid bucket identifier used in INSERT + * BUCKET or REMOVE BUCKET command. */ OFPERR_OFPGMFC_UNKNOWN_BUCKET, - /* OF1.5+(6,16). Can't insert bucket because a bucket - * already exist with that bucket-id. */ + /* NX1.0(6,16), OF1.5+(6,16). Can't insert bucket because a bucket already + * exist with that bucket-id. */ OFPERR_OFPGMFC_BUCKET_EXISTS, /* ## --------------------- ## */ diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h index ea2fa5bb0..f18027302 100644 --- a/include/openvswitch/ofp-msgs.h +++ b/include/openvswitch/ofp-msgs.h @@ -195,6 +195,8 @@ enum ofpraw { /* NXT 1.0+ (13): struct nx_flow_mod, uint8_t[8][]. */ OFPRAW_NXT_FLOW_MOD, + /* NXT 1.0 (31): struct ofp15_group_mod, uint8_t[8][]. */ + OFPRAW_NXT_GROUP_MOD, /* OFPT 1.1-1.4 (15): struct ofp11_group_mod, uint8_t[8][]. */ OFPRAW_OFPT11_GROUP_MOD, /* OFPT 1.5+ (15): struct ofp15_group_mod, uint8_t[8][]. */ @@ -367,25 +369,37 @@ enum ofpraw { /* OFPST 1.4+ (5): uint8_t[8][]. */ OFPRAW_OFPST14_QUEUE_REPLY, + /* NXST 1.0 (7): struct ofp11_group_stats_request. */ + OFPRAW_NXST_GROUP_REQUEST, /* OFPST 1.1+ (6): struct ofp11_group_stats_request. */ OFPRAW_OFPST11_GROUP_REQUEST, + /* NXST 1.0 (7): uint8_t[8][]. */ + OFPRAW_NXST_GROUP_REPLY, /* OFPST 1.1-1.2 (6): uint8_t[8][]. */ OFPRAW_OFPST11_GROUP_REPLY, /* OFPST 1.3+ (6): uint8_t[8][]. */ OFPRAW_OFPST13_GROUP_REPLY, + /* NXST 1.0 (8): struct ofp15_group_desc_request. */ + OFPRAW_NXST_GROUP_DESC_REQUEST, /* OFPST 1.1-1.4 (7): void. */ OFPRAW_OFPST11_GROUP_DESC_REQUEST, /* OFPST 1.5+ (7): struct ofp15_group_desc_request. */ OFPRAW_OFPST15_GROUP_DESC_REQUEST, + /* NXST 1.0 (8): uint8_t[8][]. */ + OFPRAW_NXST_GROUP_DESC_REPLY, /* OFPST 1.1+ (7): uint8_t[8][]. */ OFPRAW_OFPST11_GROUP_DESC_REPLY, + /* NXST 1.0-1.1 (9): void. */ + OFPRAW_NXST_GROUP_FEATURES_REQUEST, /* OFPST 1.2+ (8): void. */ OFPRAW_OFPST12_GROUP_FEATURES_REQUEST, + /* NXST 1.0-1.1 (9): struct ofp12_group_features_stats. */ + OFPRAW_NXST_GROUP_FEATURES_REPLY, /* OFPST 1.2+ (8): struct ofp12_group_features_stats. */ OFPRAW_OFPST12_GROUP_FEATURES_REPLY, @@ -583,7 +597,8 @@ enum ofptype { OFPTYPE_FLOW_MOD, /* OFPRAW_OFPT10_FLOW_MOD. * OFPRAW_OFPT11_FLOW_MOD. * OFPRAW_NXT_FLOW_MOD. */ - OFPTYPE_GROUP_MOD, /* OFPRAW_OFPT11_GROUP_MOD. + OFPTYPE_GROUP_MOD, /* OFPRAW_NXT_GROUP_MOD. + * OFPRAW_OFPT11_GROUP_MOD. * OFPRAW_OFPT15_GROUP_MOD. */ OFPTYPE_PORT_MOD, /* OFPRAW_OFPT10_PORT_MOD. * OFPRAW_OFPT11_PORT_MOD. @@ -677,19 +692,25 @@ enum ofptype { * OFPRAW_OFPST13_QUEUE_REPLY. * OFPRAW_OFPST14_QUEUE_REPLY. */ - OFPTYPE_GROUP_STATS_REQUEST, /* OFPRAW_OFPST11_GROUP_REQUEST. */ + OFPTYPE_GROUP_STATS_REQUEST, /* OFPRAW_NXST_GROUP_REQUEST. + * OFPRAW_OFPST11_GROUP_REQUEST. */ - OFPTYPE_GROUP_STATS_REPLY, /* OFPRAW_OFPST11_GROUP_REPLY. + OFPTYPE_GROUP_STATS_REPLY, /* OFPRAW_NXST_GROUP_REPLY. + * OFPRAW_OFPST11_GROUP_REPLY. * OFPRAW_OFPST13_GROUP_REPLY. */ - OFPTYPE_GROUP_DESC_STATS_REQUEST, /* OFPRAW_OFPST11_GROUP_DESC_REQUEST. + OFPTYPE_GROUP_DESC_STATS_REQUEST, /* OFPRAW_NXST_GROUP_DESC_REQUEST. + * OFPRAW_OFPST11_GROUP_DESC_REQUEST. * OFPRAW_OFPST15_GROUP_DESC_REQUEST. */ - OFPTYPE_GROUP_DESC_STATS_REPLY, /* OFPRAW_OFPST11_GROUP_DESC_REPLY. */ + OFPTYPE_GROUP_DESC_STATS_REPLY, /* OFPRAW_NXST_GROUP_DESC_REPLY. + * OFPRAW_OFPST11_GROUP_DESC_REPLY. */ - OFPTYPE_GROUP_FEATURES_STATS_REQUEST, /* OFPRAW_OFPST12_GROUP_FEATURES_REQUEST. */ + OFPTYPE_GROUP_FEATURES_STATS_REQUEST, /* OFPRAW_NXST_GROUP_FEATURES_REQUEST. + * OFPRAW_OFPST12_GROUP_FEATURES_REQUEST. */ - OFPTYPE_GROUP_FEATURES_STATS_REPLY, /* OFPRAW_OFPST12_GROUP_FEATURES_REPLY. */ + OFPTYPE_GROUP_FEATURES_STATS_REPLY, /* OFPRAW_NXST_GROUP_FEATURES_REPLY. + * OFPRAW_OFPST12_GROUP_FEATURES_REPLY. */ OFPTYPE_METER_STATS_REQUEST, /* OFPRAW_OFPST13_METER_REQUEST. */ diff --git a/lib/nx-match.c b/lib/nx-match.c index a8edb2e9d..a3c22ee88 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1375,18 +1375,13 @@ oxm_put_field_array(struct ofpbuf *b, const struct field_array *fa, { size_t start_len = b->size; - /* Field arrays are only used with the group selection method - * property and group properties are only available in OpenFlow 1.5+. - * So the following assertion should never fail. - * - * If support for older OpenFlow versions is desired then some care - * will need to be taken of different TLVs that handle the same - * flow fields. In particular: + /* XXX Some care might need to be taken of different TLVs that handle the + * same flow fields. In particular: + * - VLAN_TCI, VLAN_VID and MFF_VLAN_PCP * - IP_DSCP_MASK and DSCP_SHIFTED * - REGS and XREGS */ - ovs_assert(version >= OFP15_VERSION); size_t i, offset = 0; diff --git a/lib/ofp-group.c b/lib/ofp-group.c index 5b54faee9..a2755ee47 100644 --- a/lib/ofp-group.c +++ b/lib/ofp-group.c @@ -215,29 +215,14 @@ struct ofpbuf * ofputil_encode_group_stats_request(enum ofp_version ofp_version, uint32_t group_id) { - struct ofpbuf *request; - - switch (ofp_version) { - case OFP10_VERSION: - ovs_fatal(0, "dump-group-stats needs OpenFlow 1.1 or later " - "(\'-O OpenFlow11\')"); - case OFP11_VERSION: - case OFP12_VERSION: - case OFP13_VERSION: - case OFP14_VERSION: - case OFP15_VERSION: - case OFP16_VERSION: { - struct ofp11_group_stats_request *req; - request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_REQUEST, ofp_version, 0); - req = ofpbuf_put_zeros(request, sizeof *req); - req->group_id = htonl(group_id); - break; - } - default: - OVS_NOT_REACHED(); - } - - return request; + struct ofpbuf *msg = ofpraw_alloc((ofp_version == OFP10_VERSION + ? OFPRAW_NXST_GROUP_REQUEST + : OFPRAW_OFPST11_GROUP_REQUEST), + ofp_version, 0); + struct ofp11_group_stats_request *req = ofpbuf_put_zeros(msg, sizeof *req); + req->group_id = htonl(group_id); + + return msg; } void @@ -257,7 +242,8 @@ ofputil_decode_group_desc_request(const struct ofp_header *oh) enum ofpraw raw = ofpraw_pull_assert(&request); if (raw == OFPRAW_OFPST11_GROUP_DESC_REQUEST) { return OFPG_ALL; - } else if (raw == OFPRAW_OFPST15_GROUP_DESC_REQUEST) { + } else if (raw == OFPRAW_NXST_GROUP_DESC_REQUEST || + raw == OFPRAW_OFPST15_GROUP_DESC_REQUEST) { ovs_be32 *group_id = ofpbuf_pull(&request, sizeof *group_id); return ntohl(*group_id); } else { @@ -279,9 +265,6 @@ ofputil_encode_group_desc_request(enum ofp_version ofp_version, struct ofpbuf *request; switch (ofp_version) { - case OFP10_VERSION: - ovs_fatal(0, "dump-groups needs OpenFlow 1.1 or later " - "(\'-O OpenFlow11\')"); case OFP11_VERSION: case OFP12_VERSION: case OFP13_VERSION: @@ -289,10 +272,13 @@ ofputil_encode_group_desc_request(enum ofp_version ofp_version, request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST, ofp_version, 0); break; + case OFP10_VERSION: case OFP15_VERSION: case OFP16_VERSION: { struct ofp15_group_desc_request *req; - request = ofpraw_alloc(OFPRAW_OFPST15_GROUP_DESC_REQUEST, + request = ofpraw_alloc((ofp_version == OFP10_VERSION + ? OFPRAW_NXST_GROUP_DESC_REQUEST + : OFPRAW_OFPST15_GROUP_DESC_REQUEST), ofp_version, 0); req = ofpbuf_put_zeros(request, sizeof *req); req->group_id = htonl(group_id); @@ -367,6 +353,7 @@ ofputil_append_group_stats(struct ovs_list *replies, break; } + case OFP10_VERSION: case OFP13_VERSION: case OFP14_VERSION: case OFP15_VERSION: @@ -380,7 +367,6 @@ ofputil_append_group_stats(struct ovs_list *replies, break; } - case OFP10_VERSION: default: OVS_NOT_REACHED(); } @@ -390,26 +376,10 @@ ofputil_append_group_stats(struct ovs_list *replies, struct ofpbuf * ofputil_encode_group_features_request(enum ofp_version ofp_version) { - struct ofpbuf *request = NULL; - - switch (ofp_version) { - case OFP10_VERSION: - case OFP11_VERSION: - ovs_fatal(0, "dump-group-features needs OpenFlow 1.2 or later " - "(\'-O OpenFlow12\')"); - case OFP12_VERSION: - case OFP13_VERSION: - case OFP14_VERSION: - case OFP15_VERSION: - case OFP16_VERSION: - request = ofpraw_alloc(OFPRAW_OFPST12_GROUP_FEATURES_REQUEST, - ofp_version, 0); - break; - default: - OVS_NOT_REACHED(); - } - - return request; + return ofpraw_alloc((ofp_version < OFP12_VERSION + ? OFPRAW_NXST_GROUP_FEATURES_REQUEST + : OFPRAW_OFPST12_GROUP_FEATURES_REQUEST), + ofp_version, 0); } /* Returns a OpenFlow message that encodes 'features' properly as a reply to @@ -419,16 +389,12 @@ ofputil_encode_group_features_reply( const struct ofputil_group_features *features, const struct ofp_header *request) { - struct ofp12_group_features_stats *ogf; - struct ofpbuf *reply; - int i; - - reply = ofpraw_alloc_xid(OFPRAW_OFPST12_GROUP_FEATURES_REPLY, - request->version, request->xid, 0); - ogf = ofpbuf_put_zeros(reply, sizeof *ogf); + struct ofpbuf *reply = ofpraw_alloc_stats_reply(request, 0); + struct ofp12_group_features_stats *ogf + = ofpbuf_put_zeros(reply, sizeof *ogf); ogf->types = htonl(features->types); ogf->capabilities = htonl(features->capabilities); - for (i = 0; i < OFPGT12_N_TYPES; i++) { + for (int i = 0; i < OFPGT12_N_TYPES; i++) { ogf->max_groups[i] = htonl(features->max_groups[i]); ogf->actions[i] = ofpact_bitmap_to_openflow(features->ofpacts[i], request->version); @@ -504,7 +470,8 @@ ofputil_decode_group_stats_reply(struct ofpbuf *msg, base_len = sizeof *ogs11; ogs11 = ofpbuf_try_pull(msg, sizeof *ogs11); gs->duration_sec = gs->duration_nsec = UINT32_MAX; - } else if (raw == OFPRAW_OFPST13_GROUP_REPLY) { + } else if (raw == OFPRAW_NXST_GROUP_REPLY || + raw == OFPRAW_OFPST13_GROUP_REPLY) { struct ofp13_group_stats *ogs13; base_len = sizeof *ogs13; @@ -595,7 +562,7 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_, error = xasprintf("invalid bucket_id id %"PRIu32, bucket->bucket_id); } - *usable_protocols &= OFPUTIL_P_OF15_UP; + *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP; } else if (!strcasecmp(key, "action") || !strcasecmp(key, "actions")) { ds_put_format(&actions, "%s,", value); } else { @@ -713,7 +680,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command, struct ofputil_bucket *bucket; char *error = NULL; - *usable_protocols = OFPUTIL_P_OF11_UP; + *usable_protocols = OFPUTIL_P_ANY; if (command == -2) { size_t len; @@ -759,12 +726,12 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command, case OFPGC15_INSERT_BUCKET: fields = F_BUCKETS | F_COMMAND_BUCKET_ID; - *usable_protocols &= OFPUTIL_P_OF15_UP; + *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP; break; case OFPGC15_REMOVE_BUCKET: fields = F_COMMAND_BUCKET_ID | F_COMMAND_BUCKET_ID_ALL; - *usable_protocols &= OFPUTIL_P_OF15_UP; + *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP; break; default: @@ -781,8 +748,6 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command, return NULL; } - *usable_protocols = OFPUTIL_P_OF11_UP; - /* Strip the buckets off the end of 'string', if there are any, saving a * pointer for later. We want to parse the buckets last because the bucket * type influences bucket defaults. */ @@ -877,7 +842,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command, memset(gm->props.selection_method, '\0', NTR_MAX_SELECTION_METHOD_LEN); strcpy(gm->props.selection_method, value); - *usable_protocols &= OFPUTIL_P_OF15_UP; + *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP; } else if (!strcmp(name, "selection_method_param")) { if (!(fields & F_GROUP_TYPE)) { error = xstrdup("selection method param is not needed"); @@ -887,7 +852,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command, if (error) { goto out; } - *usable_protocols &= OFPUTIL_P_OF15_UP; + *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP; } else if (!strcmp(name, "fields")) { if (!(fields & F_GROUP_TYPE)) { error = xstrdup("fields are not needed"); @@ -899,7 +864,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command, if (error) { goto out; } - *usable_protocols &= OFPUTIL_P_OF15_UP; + *usable_protocols &= OFPUTIL_P_OF10_ANY | OFPUTIL_P_OF15_UP; } else { error = xasprintf("unknown keyword %s", name); goto out; @@ -1028,7 +993,7 @@ parse_ofp_group_mod_file(const char *file_name, allocated_gms = *n_gms; ds_init(&s); line_number = 0; - *usable_protocols = OFPUTIL_P_OF11_UP; + *usable_protocols = OFPUTIL_P_ANY; while (!ds_get_preprocessed_line(&s, stream, &line_number)) { enum ofputil_protocol usable; char *error; @@ -1223,12 +1188,12 @@ ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds, ofputil_append_ofp11_group_desc_reply(gds, buckets, replies, version); break; + case OFP10_VERSION: case OFP15_VERSION: case OFP16_VERSION: ofputil_append_ofp15_group_desc_reply(gds, buckets, replies, version); break; - case OFP10_VERSION: default: OVS_NOT_REACHED(); } @@ -1307,8 +1272,6 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length, enum ofp_version version, uint8_t group_type, struct ovs_list *buckets) { - struct ofp15_bucket *ob; - ovs_list_init(buckets); while (buckets_length > 0) { struct ofputil_bucket *bucket = NULL; @@ -1321,7 +1284,7 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length, ofpbuf_init(&ofpacts, 0); - ob = ofpbuf_try_pull(msg, sizeof *ob); + struct ofp15_bucket *ob = ofpbuf_try_pull(msg, sizeof *ob); if (!ob) { VLOG_WARN_RL(&rl, "buckets end with %"PRIuSIZE " leftover bytes", buckets_length); @@ -1694,11 +1657,11 @@ ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd, case OFP14_VERSION: return ofputil_decode_ofp11_group_desc_reply(gd, msg, version); + case OFP10_VERSION: case OFP15_VERSION: case OFP16_VERSION: return ofputil_decode_ofp15_group_desc_reply(gd, msg, version); - case OFP10_VERSION: default: OVS_NOT_REACHED(); } @@ -1745,7 +1708,9 @@ ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version, struct ofputil_bucket *bucket; struct id_pool *bucket_ids = NULL; - b = ofpraw_alloc(OFPRAW_OFPT15_GROUP_MOD, ofp_version, 0); + b = ofpraw_alloc((ofp_version == OFP10_VERSION + ? OFPRAW_NXT_GROUP_MOD + : OFPRAW_OFPT15_GROUP_MOD), ofp_version, 0); start_ogm = b->size; ofpbuf_put_zeros(b, sizeof *ogm); @@ -1861,10 +1826,6 @@ ofputil_encode_group_mod(enum ofp_version ofp_version, { switch (ofp_version) { - case OFP10_VERSION: - bad_group_cmd(gm->command); - /* fall through */ - case OFP11_VERSION: case OFP12_VERSION: case OFP13_VERSION: @@ -1874,6 +1835,7 @@ ofputil_encode_group_mod(enum ofp_version ofp_version, } return ofputil_encode_ofp11_group_mod(ofp_version, gm); + case OFP10_VERSION: case OFP15_VERSION: case OFP16_VERSION: return ofputil_encode_ofp15_group_mod(ofp_version, gm); @@ -2059,12 +2021,12 @@ ofputil_decode_group_mod(const struct ofp_header *oh, err = ofputil_pull_ofp11_group_mod(&msg, ofp_version, gm); break; + case OFP10_VERSION: case OFP15_VERSION: case OFP16_VERSION: err = ofputil_pull_ofp15_group_mod(&msg, ofp_version, gm); break; - case OFP10_VERSION: default: OVS_NOT_REACHED(); } diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 096c341c9..0d1406873 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1528,7 +1528,7 @@ static void ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id, enum ofp_version ofp_version) { - if (ofp_version < OFP15_VERSION) { + if (ofp_version > OFP10_VERSION && ofp_version < OFP15_VERSION) { return; } diff --git a/tests/ofp-print.at b/tests/ofp-print.at index cfce78002..5d1541f9f 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -2150,7 +2150,16 @@ OFPST_QUEUE reply (OF1.4) (xid=0x1): 6 queues ]) AT_CLEANUP -AT_SETUP([OFPST_GROUP request]) +AT_SETUP([NXST_GROUP request - OF1.0]) +AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 10 00 20 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 07 00 00 00 00 \ +ff ff ff ff 00 00 00 00 \ +"], [0], [NXST_GROUP request (xid=0x4): group_id=ANY +]) +AT_CLEANUP + +AT_SETUP([OFPST_GROUP request - OF1.1]) AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) AT_CHECK([ovs-ofctl ofp-print "\ 02 12 00 18 00 00 00 02 00 06 00 00 00 00 00 00 \ @@ -2159,6 +2168,28 @@ ff ff ff ff 00 00 00 00 \ ]) AT_CLEANUP +AT_SETUP([NXST_GROUP reply - OF1.0]) +AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 11 00 b8 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 07 00 00 00 00 \ +00 58 00 00 87 65 43 21 00 00 00 04 00 00 00 00 \ +00 00 00 00 00 00 88 88 00 00 00 00 00 77 77 77 \ +00 00 00 12 1d cd 65 00 \ +00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \ +00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \ +00 00 00 00 00 00 66 66 00 00 00 00 00 33 33 33 \ +00 48 00 00 00 00 00 05 00 00 00 02 00 00 00 00 \ +00 00 00 00 00 00 88 88 00 00 00 00 00 77 77 77 \ +00 00 00 10 1d cd 65 00 \ +00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \ +00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \ +"], [0], [dnl +NXST_GROUP reply (xid=0x4): + group_id=2271560481,duration=18.500s,ref_count=4,packet_count=34952,byte_count=7829367,bucket0:packet_count=4369,byte_count=2236962,bucket1:packet_count=4369,byte_count=2236962,bucket2:packet_count=26214,byte_count=3355443 + group_id=5,duration=16.500s,ref_count=2,packet_count=34952,byte_count=7829367,bucket0:packet_count=4369,byte_count=2236962,bucket1:packet_count=4369,byte_count=2236962 +]) +AT_CLEANUP + AT_SETUP([OFPST_GROUP reply - OF1.1]) AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) AT_CHECK([ovs-ofctl ofp-print "\ @@ -2201,6 +2232,15 @@ OFPST_GROUP reply (OF1.3) (xid=0x2): ]) AT_CLEANUP +AT_SETUP([NXST_GROUP_DESC request - OF1.0]) +AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 10 00 20 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 08 00 00 00 00 \ +00 00 00 01 00 00 00 00 +"], [0], [NXST_GROUP_DESC request (xid=0x4): group_id=1 +]) +AT_CLEANUP + AT_SETUP([OFPST_GROUP_DESC request - OF1.1]) AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) AT_CHECK([ovs-ofctl ofp-print "\ @@ -2218,6 +2258,31 @@ AT_CHECK([ovs-ofctl ofp-print "\ ]) AT_CLEANUP +AT_SETUP([NXST_GROUP_DESC reply - OF1.0]) +AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 11 00 c8 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 08 00 00 00 00 \ +00 b0 01 00 00 00 20 00 00 60 00 00 00 00 00 00 \ +00 20 00 08 00 00 00 00 00 00 00 08 00 01 00 00 \ +00 00 00 08 00 64 00 00 \ +00 01 00 08 00 00 00 01 \ +00 20 00 08 00 00 00 01 00 00 00 08 00 02 00 00 \ +00 00 00 08 00 c8 00 00 \ +00 01 00 08 00 00 00 02 \ +00 20 00 08 00 00 00 02 00 00 00 08 00 03 00 00 \ +00 00 00 08 00 c8 00 00 \ +00 01 00 08 00 00 00 03 \ +ff ff 00 3b 00 00 15 40 00 00 00 01 00 00 00 00 \ +68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 \ +80 00 18 04 ff ff ff 00 80 00 1a 02 ff ff 80 00 \ +14 01 ff 00 00 00 00 00 \ +"], [0], [dnl +NXST_GROUP_DESC reply (xid=0x4): + group_id=8192,type=select,selection_method=hash,fields(ip_dst=255.255.255.0,nw_proto,tcp_src),bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 +]) +AT_CLEANUP + AT_SETUP([OFPST_GROUP_DESC reply - OF1.1]) AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) AT_CHECK([ovs-ofctl ofp-print "\ @@ -2260,6 +2325,14 @@ OFPST_GROUP_DESC reply (OF1.5) (xid=0x2): ]) AT_CLEANUP +AT_SETUP([NXST_GROUP_FEATURES request]) +AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 10 00 18 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 09 00 00 00 00 \ +"], [0], [NXST_GROUP_FEATURES request (xid=0x4): +]) +AT_CLEANUP + AT_SETUP([OFPST_GROUP_FEATURES request]) AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) AT_CHECK([ovs-ofctl ofp-print "\ @@ -2268,6 +2341,33 @@ AT_CHECK([ovs-ofctl ofp-print "\ ]) AT_CLEANUP +AT_SETUP([NXST_GROUP_FEATURES reply]) +AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 11 00 40 00 00 00 04 ff ff 00 00 00 00 23 20 00 00 00 09 00 00 00 00 \ +00 00 00 0f 00 00 00 0f \ +00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 \ +00 00 00 01 00 00 00 07 00 00 00 0f 00 00 00 1f \ +"], [0], [dnl +NXST_GROUP_FEATURES reply (xid=0x4): + Group table: + Types: 0xf + Capabilities: 0xf + all group: + max_groups=0x1 + actions: output + select group: + max_groups=0x2 + actions: output set_vlan_vid set_vlan_pcp + indirect group: + max_groups=0x3 + actions: output set_vlan_vid set_vlan_pcp strip_vlan + fast failover group: + max_groups=0x4 + actions: output set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src +]) +AT_CLEANUP + AT_SETUP([OFPST_GROUP_FEATURES reply]) AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) AT_CHECK([ovs-ofctl ofp-print "\ @@ -3289,6 +3389,30 @@ NXT_FLOW_MOD (xid=0x2): ADD NXM_NX_TUN_ID(00000000000001c8), NXM_NX_REG0(0000007 ]) AT_CLEANUP +AT_SETUP([NXT_GROUP_MOD add - OF1.0]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +01 04 00 a8 00 00 00 02 00 00 23 20 00 00 00 1f \ +00 00 01 00 87 65 43 21 \ +00 60 00 00 ff ff ff ff \ +\ +00 20 00 08 00 00 00 00 00 00 00 08 00 01 00 00 \ +00 00 00 08 00 64 00 00 00 01 00 08 00 00 00 01 \ +\ +00 20 00 08 00 00 00 01 00 00 00 08 00 02 00 00 \ +00 00 00 08 00 c8 00 00 00 01 00 08 00 00 00 02 +\ +00 20 00 08 00 00 00 02 00 00 00 08 00 03 00 00 \ +00 00 00 08 00 c8 00 00 00 01 00 08 00 00 00 03 \ +ff ff 00 28 00 00 15 40 00 00 00 01 00 00 00 00 \ +68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 07 \ +"], [0], [dnl +NXT_GROUP_MOD (xid=0x2): + ADD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 +]) +AT_CLEANUP + AT_SETUP([OFPT_GROUP_MOD - OF1.1]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print "\ diff --git a/tests/ofproto.at b/tests/ofproto.at index d8e9cc093..fff06eb0d 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -357,19 +357,41 @@ AT_CLEANUP dnl This is really bare-bones. dnl It at least checks request and reply serialization and deserialization. dnl Actions definition listed in both supported formats (w/ actions=) -AT_SETUP([ofproto - no group support (OpenFlow 1.0)]) +AT_SETUP([ofproto - del group (OpenFlow 1.0 extension)]) OVS_VSWITCHD_START AT_DATA([groups.txt], [dnl -group_id=1234,type=all,bucket=output:10 -group_id=1235,type=all,bucket=actions=output:10 +group_id=1233,type=select,selection_method=hash,bucket=output:10,bucket=output:11 +group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=output:10,bucket=output:11 +group_id=1235,type=all,bucket=actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 +group_id=1236,type=select,selection_method=dp_hash,bucket=output:10,bucket=output:11 ]) -AT_DATA([stderr], [dnl -ovs-ofctl: none of the usable flow formats (OXM,OpenFlow11) is among the allowed flow formats (OpenFlow10,NXM) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn add-groups br0 groups.txt]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0 1234], [0], [stdout]) +AT_CHECK([strip_xids < stdout], [0], [dnl +NXST_GROUP_DESC reply: + group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 +]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn del-groups br0 group_id=1234]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sort], [0], [dnl + group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 + group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 + group_id=1236,type=select,selection_method=dp_hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 +NXST_GROUP_DESC reply: +]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn del-groups br0 group_id=1234]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sort], [0], [dnl + group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 + group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 + group_id=1236,type=select,selection_method=dp_hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11 +NXST_GROUP_DESC reply: +]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn del-groups br0], [0]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout], [0], [dnl +NXST_GROUP_DESC reply: ]) -AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn add-groups br0 groups.txt], [1], ,[stderr]) -AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn mod-group br0 'group_id=1234,type=all,bucket=output:10'], [1], ,[stderr]) -AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn del-groups br0], [1], ,[stderr]) -AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0 ], [1], ,[stderr]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -711,7 +733,7 @@ OFPT_GROUP_MOD (OF1.5): ]) # Negative test. AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last], [1], [], - [ovs-ofctl: remove-bucket needs OpenFlow 1.5 or later ('-O OpenFlow15') + [ovs-ofctl: none of the usable flow formats (OpenFlow10,NXM,OXM-OpenFlow15,OXM-OpenFlow16) is among the allowed flow formats (OpenFlow11) ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -1018,7 +1040,7 @@ Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.5): ]) # Negative test. AT_CHECK([ovs-ofctl --bundle -O OpenFlow11 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last], [1], [], - [ovs-ofctl: remove-bucket needs OpenFlow 1.5 or later ('-O OpenFlow15') + [ovs-ofctl: none of the usable flow formats (OXM-OpenFlow15,OXM-OpenFlow16) is among the allowed flow formats (OXM-OpenFlow14) ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -1075,20 +1097,33 @@ AT_CLEANUP dnl This is really bare-bones. dnl It at least checks request and reply serialization and deserialization. -AT_SETUP([ofproto - group description]) +AT_SETUP([ofproto - group features (OpenFlow 1.0 extension)]) OVS_VSWITCHD_START -AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-group br0 group_id=1234,type=all,bucket=output:10]) -AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-groups br0], [0], [stdout]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-group-features br0], [0], [stdout]) AT_CHECK([strip_xids < stdout], [0], [dnl -OFPST_GROUP_DESC reply (OF1.1): - group_id=1234,type=all,bucket=actions=output:10 +NXST_GROUP_FEATURES reply: + Group table: + Types: 0xf + Capabilities: 0x7 + all group: + max_groups=0xffffff00 + actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst + select group: + max_groups=0xffffff00 + actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst + indirect group: + max_groups=0xffffff00 + actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst + fast failover group: + max_groups=0xffffff00 + actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst ]) OVS_VSWITCHD_STOP AT_CLEANUP dnl This is really bare-bones. dnl It at least checks request and reply serialization and deserialization. -AT_SETUP([ofproto - group features]) +AT_SETUP([ofproto - group features (OpenFlow 1.2)]) OVS_VSWITCHD_START AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn dump-group-features br0], [0], [stdout]) AT_CHECK([strip_xids < stdout], [0], [dnl @@ -1114,6 +1149,30 @@ AT_CLEANUP dnl This is really bare-bones. dnl It at least checks request and reply serialization and deserialization. +AT_SETUP([ofproto - group stats (OpenFlow 1.0 extension)]) +OVS_VSWITCHD_START +AT_DATA([groups.txt], [dnl +group_id=1234,type=all,bucket=output:10 +group_id=1235,type=all,bucket=output:10 +]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn add-groups br0 groups.txt]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn add-flow br0 'tcp actions=group:1234']) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-group-stats br0 group_id=1234], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl + group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0 +NXST_GROUP reply: +]) +AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-group-stats br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl + group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0 + group_id=1235,duration=?s,ref_count=0,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0 +NXST_GROUP reply: +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + +dnl This is really bare-bones. +dnl It at least checks request and reply serialization and deserialization. AT_SETUP([ofproto - group stats (OpenFlow 1.1)]) OVS_VSWITCHD_START AT_DATA([groups.txt], [dnl diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index abf3d87d1..2e2f6966e 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -364,7 +364,7 @@ Connects to \fIswitch\fR and instructs it to execute the \fIpacket-out\fR OpenFlow message, specified as defined in \fBPacket\-Out Syntax\fR section. . -.SS "OpenFlow 1.1+ Switch Group Table Commands" +.SS "Group Table Commands" . These commands manage the group table in an OpenFlow switch. In each case, \fIgroup\fR specifies a group entry in the format described in @@ -373,12 +373,12 @@ zero or more groups in the same syntax, one per line, and the optional \fB\-\-bundle\fR option operates the command as a single atomic transation, see option \fB\-\-bundle\fR, below. .PP -The group commands work only with switches that support OpenFlow 1.1 or -later. It is necessary to explicitly enable these protocol versions in -\fBovs\-ofctl\fR (using \fB\-O\fR) and in the switch itself (with the -\fBprotocols\fR column in the \fBBridge\fR table). For more -information, see ``Q: What versions of OpenFlow does Open vSwitch -support?'' in the Open vSwitch FAQ. +The group commands work only with switches that support OpenFlow 1.1 +or later or the Open vSwitch group extensions to OpenFlow 1.0 (added +in Open vSwitch 2.9.90). For OpenFlow 1.1 or later, it is necessary +to explicitly enable these protocol versions in \fBovs\-ofctl\fR +(using \fB\-O\fR). For more information, see ``Q: What versions of +OpenFlow does Open vSwitch support?'' in the Open vSwitch FAQ. . .IP "[\fB\-\-bundle\fR] \fBadd\-group \fIswitch group\fR" .IQ "[\fB\-\-bundle\fR] \fBadd\-group \fIswitch \fB\- < \fIfile\fR" |