/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "unaligned.h"
#include "type-props.h"
#include "vlog.h"
+#include "bitmap.h"
VLOG_DEFINE_THIS_MODULE(ofp_util);
match->wc.masks.vlan_tci = htons(0xffff);
} else {
ovs_be16 vid, pcp, tci;
+ uint16_t hpcp;
vid = ofmatch->dl_vlan & htons(VLAN_VID_MASK);
- pcp = htons((ofmatch->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK);
+ hpcp = (ofmatch->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK;
+ pcp = htons(hpcp);
tci = vid | pcp | htons(VLAN_CFI);
match->flow.vlan_tci = tci & match->wc.masks.vlan_tci;
}
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
+ case OFPUTIL_P_OF14_OXM:
return NXM_TYPICAL_LEN;
default:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
+ case OFPUTIL_P_OF14_OXM:
return oxm_put_match(b, match);
}
};
/* Most users really don't care about some of the differences between
- * protocols. These abbreviations help with that. */
+ * protocols. These abbreviations help with that.
+ *
+ * Until it is safe to use the OpenFlow 1.4 protocol (which currently can
+ * cause aborts due to unimplemented features), we omit OpenFlow 1.4 from all
+ * abbrevations. */
static const struct proto_abbrev proto_abbrevs[] = {
- { OFPUTIL_P_ANY, "any" },
- { OFPUTIL_P_OF10_STD_ANY, "OpenFlow10" },
- { OFPUTIL_P_OF10_NXM_ANY, "NXM" },
- { OFPUTIL_P_ANY_OXM, "OXM" },
+ { OFPUTIL_P_ANY & ~OFPUTIL_P_OF14_OXM, "any" },
+ { OFPUTIL_P_OF10_STD_ANY & ~OFPUTIL_P_OF14_OXM, "OpenFlow10" },
+ { OFPUTIL_P_OF10_NXM_ANY & ~OFPUTIL_P_OF14_OXM, "NXM" },
+ { OFPUTIL_P_ANY_OXM & ~OFPUTIL_P_OF14_OXM, "OXM" },
};
#define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
enum ofputil_protocol ofputil_flow_dump_protocols[] = {
+ OFPUTIL_P_OF14_OXM,
OFPUTIL_P_OF13_OXM,
OFPUTIL_P_OF12_OXM,
OFPUTIL_P_OF11_STD,
return OFPUTIL_P_OF12_OXM;
case OFP13_VERSION:
return OFPUTIL_P_OF13_OXM;
+ case OFP14_VERSION:
+ return OFPUTIL_P_OF14_OXM;
default:
return 0;
}
return OFP12_VERSION;
case OFPUTIL_P_OF13_OXM:
return OFP13_VERSION;
+ case OFPUTIL_P_OF14_OXM:
+ return OFP14_VERSION;
}
OVS_NOT_REACHED();
case OFPUTIL_P_OF13_OXM:
return OFPUTIL_P_OF13_OXM;
+ case OFPUTIL_P_OF14_OXM:
+ return OFPUTIL_P_OF14_OXM;
+
default:
OVS_NOT_REACHED();
}
case OFPUTIL_P_OF13_OXM:
return ofputil_protocol_set_tid(OFPUTIL_P_OF13_OXM, tid);
+ case OFPUTIL_P_OF14_OXM:
+ return ofputil_protocol_set_tid(OFPUTIL_P_OF14_OXM, tid);
+
default:
OVS_NOT_REACHED();
}
case OFPUTIL_P_OF13_OXM:
return "OXM-OpenFlow13";
+
+ case OFPUTIL_P_OF14_OXM:
+ return "OXM-OpenFlow14";
}
/* Check abbreviations. */
if (!strcasecmp(s, "OpenFlow13")) {
return OFP13_VERSION;
}
+ if (!strcasecmp(s, "OpenFlow14")) {
+ return OFP14_VERSION;
+ }
return 0;
}
return "OpenFlow12";
case OFP13_VERSION:
return "OpenFlow13";
+ case OFP14_VERSION:
+ return "OpenFlow14";
default:
OVS_NOT_REACHED();
}
case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
+ case OFPUTIL_P_OF14_OXM:
/* There is only one variant of each OpenFlow 1.1+ protocol, and we
* verified above that we're not trying to change versions. */
OVS_NOT_REACHED();
switch (protocol) {
case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
- case OFPUTIL_P_OF13_OXM: {
+ case OFPUTIL_P_OF13_OXM:
+ case OFPUTIL_P_OF14_OXM: {
struct ofp11_flow_mod *ofm;
int tailroom;
switch (protocol) {
case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
- case OFPUTIL_P_OF13_OXM: {
+ case OFPUTIL_P_OF13_OXM:
+ case OFPUTIL_P_OF14_OXM: {
struct ofp11_flow_stats_request *ofsr;
raw = (fsr->aggregate
switch (protocol) {
case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
- case OFPUTIL_P_OF13_OXM: {
+ case OFPUTIL_P_OF13_OXM:
+ case OFPUTIL_P_OF14_OXM: {
struct ofp12_flow_removed *ofr;
msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
+ case OFPUTIL_P_OF14_OXM:
packet = ofputil_encode_ofp12_packet_in(pin, protocol);
break;
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
+ case OFP14_VERSION:
return sizeof(struct ofp11_port);
default:
OVS_NOT_REACHED();
break;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
+
default:
OVS_NOT_REACHED();
}
break;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
+
default:
OVS_NOT_REACHED();
}
case OFP12_VERSION:
case OFP13_VERSION:
return OFPC_COMMON | OFPC12_PORT_BLOCKED;
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
default:
/* Caller needs to check osf->header.version itself */
return 0;
raw = OFPRAW_OFPT11_FEATURES_REPLY;
break;
case OFP13_VERSION:
+ case OFP14_VERSION:
raw = OFPRAW_OFPT13_FEATURES_REPLY;
break;
default:
osf->actions = encode_action_bits(features->actions, of10_action_bits);
break;
case OFP13_VERSION:
+ case OFP14_VERSION:
osf->auxiliary_id = features->auxiliary_id;
/* fall through */
case OFP11_VERSION:
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
+ case OFP14_VERSION:
raw = OFPRAW_OFPT11_PORT_STATUS;
break;
opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
break;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
default:
OVS_NOT_REACHED();
}
return b;
}
+struct ofp_prop_header {
+ ovs_be16 type;
+ ovs_be16 len;
+};
+
+static enum ofperr
+ofputil_pull_property(struct ofpbuf *msg, struct ofpbuf *payload,
+ uint16_t *typep)
+{
+ struct ofp_prop_header *oph;
+ unsigned int len;
+
+ if (msg->size < sizeof *oph) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+
+ oph = msg->data;
+ len = ntohs(oph->len);
+ if (len < sizeof *oph || ROUND_UP(len, 8) > msg->size) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+
+ *typep = ntohs(oph->type);
+ if (payload) {
+ ofpbuf_use_const(payload, msg->data, len);
+ ofpbuf_pull(payload, sizeof *oph);
+ }
+ ofpbuf_pull(msg, ROUND_UP(len, 8));
+ return 0;
+}
+
+static void PRINTF_FORMAT(2, 3)
+log_property(bool loose, const char *message, ...)
+{
+ enum vlog_level level = loose ? VLL_DBG : VLL_WARN;
+ if (!vlog_should_drop(THIS_MODULE, level, &bad_ofmsg_rl)) {
+ va_list args;
+
+ va_start(args, message);
+ vlog_valist(THIS_MODULE, level, message, args);
+ va_end(args);
+ }
+}
+
+static enum ofperr
+parse_table_ids(struct ofpbuf *payload, uint32_t *ids)
+{
+ uint16_t type;
+
+ *ids = 0;
+ while (payload->size > 0) {
+ enum ofperr error = ofputil_pull_property(payload, NULL, &type);
+ if (error) {
+ return error;
+ }
+ if (type < CHAR_BIT * sizeof *ids) {
+ *ids |= 1u << type;
+ }
+ }
+ return 0;
+}
+
+static enum ofperr
+parse_instruction_ids(struct ofpbuf *payload, bool loose, uint32_t *insts)
+{
+ *insts = 0;
+ while (payload->size > 0) {
+ enum ovs_instruction_type inst;
+ enum ofperr error;
+ uint16_t ofpit;
+
+ error = ofputil_pull_property(payload, NULL, &ofpit);
+ if (error) {
+ return error;
+ }
+
+ error = ovs_instruction_type_from_inst_type(&inst, ofpit);
+ if (!error) {
+ *insts |= 1u << inst;
+ } else if (!loose) {
+ return error;
+ }
+ }
+ return 0;
+}
+
+static enum ofperr
+parse_table_features_next_table(struct ofpbuf *payload,
+ unsigned long int *next_tables)
+{
+ size_t i;
+
+ memset(next_tables, 0, bitmap_n_bytes(255));
+ for (i = 0; i < payload->size; i++) {
+ uint8_t id = ((const uint8_t *) payload->data)[i];
+ if (id >= 255) {
+ return OFPERR_OFPTFFC_BAD_ARGUMENT;
+ }
+ bitmap_set1(next_tables, id);
+ }
+ return 0;
+}
+
+static enum ofperr
+parse_oxm(struct ofpbuf *b, bool loose,
+ const struct mf_field **fieldp, bool *hasmask)
+{
+ ovs_be32 *oxmp;
+ uint32_t oxm;
+
+ oxmp = ofpbuf_try_pull(b, sizeof *oxmp);
+ if (!oxmp) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+ oxm = ntohl(*oxmp);
+
+ /* Determine '*hasmask'. If 'oxm' is masked, convert it to the equivalent
+ * unmasked version, because the table of OXM fields we support only has
+ * masked versions of fields that we support with masks, but we should be
+ * able to parse the masked versions of those here. */
+ *hasmask = NXM_HASMASK(oxm);
+ if (*hasmask) {
+ if (NXM_LENGTH(oxm) & 1) {
+ return OFPERR_OFPTFFC_BAD_ARGUMENT;
+ }
+ oxm = NXM_HEADER(NXM_VENDOR(oxm), NXM_FIELD(oxm), NXM_LENGTH(oxm) / 2);
+ }
+
+ *fieldp = mf_from_nxm_header(oxm);
+ if (!*fieldp) {
+ log_property(loose, "unknown OXM field %#"PRIx32, ntohl(*oxmp));
+ }
+ return *fieldp ? 0 : OFPERR_OFPBMC_BAD_FIELD;
+}
+
+static enum ofperr
+parse_oxms(struct ofpbuf *payload, bool loose,
+ uint64_t *exactp, uint64_t *maskedp)
+{
+ uint64_t exact, masked;
+
+ exact = masked = 0;
+ while (payload->size > 0) {
+ const struct mf_field *field;
+ enum ofperr error;
+ bool hasmask;
+
+ error = parse_oxm(payload, loose, &field, &hasmask);
+ if (!error) {
+ if (hasmask) {
+ masked |= UINT64_C(1) << field->id;
+ } else {
+ exact |= UINT64_C(1) << field->id;
+ }
+ } else if (error != OFPERR_OFPBMC_BAD_FIELD || !loose) {
+ return error;
+ }
+ }
+ if (exactp) {
+ *exactp = exact;
+ } else if (exact) {
+ return OFPERR_OFPBMC_BAD_MASK;
+ }
+ if (maskedp) {
+ *maskedp = masked;
+ } else if (masked) {
+ return OFPERR_OFPBMC_BAD_MASK;
+ }
+ return 0;
+}
+
+/* Converts an OFPMP_TABLE_FEATURES request or reply in 'msg' into an abstract
+ * ofputil_table_features in 'tf'.
+ *
+ * If 'loose' is true, this function ignores properties and values that it does
+ * not understand, as a controller would want to do when interpreting
+ * capabilities provided by a switch. If 'loose' is false, this function
+ * treats unknown properties and values as an error, as a switch would want to
+ * do when interpreting a configuration request made by a controller.
+ *
+ * A single OpenFlow message can specify features for multiple tables. Calling
+ * this function multiple times for a single 'msg' iterates through the tables
+ * in the message. The caller must initially leave 'msg''s layer pointers null
+ * and not modify them between calls.
+ *
+ * Returns 0 if successful, EOF if no tables were left in this 'msg', otherwise
+ * a positive "enum ofperr" value. */
+int
+ofputil_decode_table_features(struct ofpbuf *msg,
+ struct ofputil_table_features *tf, bool loose)
+{
+ struct ofp13_table_features *otf;
+ unsigned int len;
+
+ if (!msg->l2) {
+ msg->l2 = msg->data;
+ ofpraw_pull_assert(msg);
+ }
+
+ if (!msg->size) {
+ return EOF;
+ }
+
+ if (msg->size < sizeof *otf) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+
+ otf = msg->data;
+ len = ntohs(otf->length);
+ if (len < sizeof *otf || len % 8 || len > msg->size) {
+ return OFPERR_OFPTFFC_BAD_LEN;
+ }
+ ofpbuf_pull(msg, sizeof *otf);
+
+ tf->table_id = otf->table_id;
+ if (tf->table_id == OFPTT_ALL) {
+ return OFPERR_OFPTFFC_BAD_TABLE;
+ }
+
+ ovs_strlcpy(tf->name, otf->name, OFP_MAX_TABLE_NAME_LEN);
+ tf->metadata_match = otf->metadata_match;
+ tf->metadata_write = otf->metadata_write;
+ tf->config = ntohl(otf->config);
+ tf->max_entries = ntohl(otf->max_entries);
+
+ while (msg->size > 0) {
+ struct ofpbuf payload;
+ enum ofperr error;
+ uint16_t type;
+
+ error = ofputil_pull_property(msg, &payload, &type);
+ if (error) {
+ return error;
+ }
+
+ switch ((enum ofp13_table_feature_prop_type) type) {
+ case OFPTFPT13_INSTRUCTIONS:
+ error = parse_instruction_ids(&payload, loose,
+ &tf->nonmiss.instructions);
+ break;
+ case OFPTFPT13_INSTRUCTIONS_MISS:
+ error = parse_instruction_ids(&payload, loose,
+ &tf->miss.instructions);
+ break;
+
+ case OFPTFPT13_NEXT_TABLES:
+ error = parse_table_features_next_table(&payload,
+ tf->nonmiss.next);
+ break;
+ case OFPTFPT13_NEXT_TABLES_MISS:
+ error = parse_table_features_next_table(&payload, tf->miss.next);
+ break;
+
+ case OFPTFPT13_WRITE_ACTIONS:
+ error = parse_table_ids(&payload, &tf->nonmiss.write.actions);
+ break;
+ case OFPTFPT13_WRITE_ACTIONS_MISS:
+ error = parse_table_ids(&payload, &tf->miss.write.actions);
+ break;
+
+ case OFPTFPT13_APPLY_ACTIONS:
+ error = parse_table_ids(&payload, &tf->nonmiss.apply.actions);
+ break;
+ case OFPTFPT13_APPLY_ACTIONS_MISS:
+ error = parse_table_ids(&payload, &tf->miss.apply.actions);
+ break;
+
+ case OFPTFPT13_MATCH:
+ error = parse_oxms(&payload, loose, &tf->match, &tf->mask);
+ break;
+ case OFPTFPT13_WILDCARDS:
+ error = parse_oxms(&payload, loose, &tf->wildcard, NULL);
+ break;
+
+ case OFPTFPT13_WRITE_SETFIELD:
+ error = parse_oxms(&payload, loose,
+ &tf->nonmiss.write.set_fields, NULL);
+ break;
+ case OFPTFPT13_WRITE_SETFIELD_MISS:
+ error = parse_oxms(&payload, loose,
+ &tf->miss.write.set_fields, NULL);
+ break;
+ case OFPTFPT13_APPLY_SETFIELD:
+ error = parse_oxms(&payload, loose,
+ &tf->nonmiss.apply.set_fields, NULL);
+ break;
+ case OFPTFPT13_APPLY_SETFIELD_MISS:
+ error = parse_oxms(&payload, loose,
+ &tf->miss.apply.set_fields, NULL);
+ break;
+
+ case OFPTFPT13_EXPERIMENTER:
+ case OFPTFPT13_EXPERIMENTER_MISS:
+ log_property(loose,
+ "unknown table features experimenter property");
+ error = loose ? 0 : OFPERR_OFPTFFC_BAD_TYPE;
+ break;
+ }
+ if (error) {
+ return error;
+ }
+ }
+
+ /* Fix inconsistencies:
+ *
+ * - Turn off 'mask' and 'wildcard' bits that are not in 'match',
+ * because a field must be matchable to be masked or wildcarded.
+ *
+ * - Turn on 'wildcard' bits that are set in 'mask', because a field
+ * that is arbitrarily maskable can be wildcarded entirely. */
+ tf->mask &= tf->match;
+ tf->wildcard &= tf->match;
+
+ tf->wildcard |= tf->mask;
+
+ return 0;
+}
+
+/* Encodes and returns a request to obtain the table features of a switch.
+ * The message is encoded for OpenFlow version 'ofp_version'. */
+struct ofpbuf *
+ofputil_encode_table_features_request(enum ofp_version ofp_version)
+{
+ struct ofpbuf *request = NULL;
+
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ ovs_fatal(0, "dump-table-features needs OpenFlow 1.3 or later "
+ "(\'-O OpenFlow13\')");
+ case OFP13_VERSION:
+ case OFP14_VERSION:
+ request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
+ ofp_version, 0);
+ break;
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ return request;
+}
+
/* ofputil_table_mod */
/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
otm->config = htonl(pm->config);
break;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
default:
OVS_NOT_REACHED();
}
break;
case OFP13_VERSION:
+ case OFP14_VERSION:
ofputil_put_ofp13_table_stats(&stats[i], reply);
break;
case OFP11_VERSION:
case OFP12_VERSION:
- case OFP13_VERSION: {
+ case OFP13_VERSION:
+ case OFP14_VERSION:{
struct ofp11_packet_out *opo;
size_t len;
enum ofpraw type;
switch (ofp_version) {
+ case OFP14_VERSION:
case OFP13_VERSION:
case OFP12_VERSION:
case OFP11_VERSION:
const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
default:
OVS_NOT_REACHED();
}
NULL,
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME,
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
#include "ofp-util.def"
};
: "Unknown action";
}
+enum ofputil_action_code
+ofputil_action_code_from_ofp13_action(enum ofp13_action_type type)
+{
+ switch (type) {
+
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ case ENUM: \
+ return OFPUTIL_##ENUM;
+#include "ofp-util.def"
+
+ default:
+ return OFPUTIL_ACTION_INVALID;
+ }
+}
+
/* Appends an action of the type specified by 'code' to 'buf' and returns the
* action. Initializes the parts of 'action' that identify it as having type
* <ENUM> and length 'sizeof *action' and zeros the rest. For actions that
{
switch (code) {
case OFPUTIL_ACTION_INVALID:
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
OVS_NOT_REACHED();
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
}
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
OFPAT10_ACTION(ENUM, STRUCT, NAME)
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+ OFPAT10_ACTION(ENUM, STRUCT, NAME)
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
void \
ofputil_init_##ENUM(struct STRUCT *s) \
}
case OFP11_VERSION:
case OFP12_VERSION:
- case OFP13_VERSION: {
+ case OFP13_VERSION:
+ case OFP14_VERSION:{
struct ofp11_port_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST11_PORT_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
break;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
+
default:
OVS_NOT_REACHED();
}
return sizeof(struct ofp11_port_stats);
case OFP13_VERSION:
return sizeof(struct ofp13_port_stats);
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ return 0;
default:
OVS_NOT_REACHED();
}
return 0;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
+
default:
OVS_NOT_REACHED();
}
"(\'-O OpenFlow11\')");
case OFP11_VERSION:
case OFP12_VERSION:
- case OFP13_VERSION: {
+ case OFP13_VERSION:
+ case OFP14_VERSION: {
struct ofp11_group_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
"(\'-O OpenFlow11\')");
case OFP11_VERSION:
case OFP12_VERSION:
- case OFP13_VERSION: {
+ case OFP13_VERSION:
+ case OFP14_VERSION:
request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST, ofp_version, 0);
break;
- }
default:
OVS_NOT_REACHED();
}
ofputil_append_of13_group_stats(ogs, replies);
break;
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
+
case OFP10_VERSION:
default:
OVS_NOT_REACHED();
ovs_fatal(0, "dump-group-features needs OpenFlow 1.2 or later "
"(\'-O OpenFlow12\')");
case OFP12_VERSION:
- case OFP13_VERSION: {
+ case OFP13_VERSION:
+ case OFP14_VERSION:
request = ofpraw_alloc(OFPRAW_OFPST12_GROUP_FEATURES_REQUEST,
- ofp_version, 0);
+ ofp_version, 0);
break;
- }
default:
OVS_NOT_REACHED();
}
case OFP11_VERSION:
case OFP12_VERSION:
- case OFP13_VERSION: {
+ case OFP13_VERSION:
+ case OFP14_VERSION:
b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
start_ogm = b->size;
ofpbuf_put_zeros(b, sizeof *ogm);
ogm->group_id = htonl(gm->group_id);
break;
- }
default:
OVS_NOT_REACHED();
struct ofputil_queue_stats_request *oqsr)
{
switch ((enum ofp_version)request->version) {
+ case OFP14_VERSION:
case OFP13_VERSION:
case OFP12_VERSION:
case OFP11_VERSION: {
switch (ofp_version) {
case OFP11_VERSION:
case OFP12_VERSION:
- case OFP13_VERSION: {
+ case OFP13_VERSION:
+ case OFP14_VERSION: {
struct ofp11_queue_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
return sizeof(struct ofp11_queue_stats);
case OFP13_VERSION:
return sizeof(struct ofp13_queue_stats);
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ return 0;
default:
OVS_NOT_REACHED();
}
break;
}
+ case OFP14_VERSION:
+ OVS_NOT_REACHED();
+ break;
+
default:
OVS_NOT_REACHED();
}