summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--include/openflow/openflow-1.5.h3
-rw-r--r--include/openvswitch/ofp-errors.h54
-rw-r--r--include/openvswitch/ofp-msgs.h35
-rw-r--r--lib/nx-match.c11
-rw-r--r--lib/ofp-group.c120
-rw-r--r--lib/ofp-print.c2
-rw-r--r--tests/ofp-print.at126
-rw-r--r--tests/ofproto.at93
-rw-r--r--utilities/ovs-ofctl.8.in14
10 files changed, 312 insertions, 149 deletions
diff --git a/NEWS b/NEWS
index cb27aaedf..ec548b02a 100644
--- a/NEWS
+++ b/NEWS
@@ -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"