case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
case OFPUTIL_P_OF14_OXM:
+ case OFPUTIL_P_OF15_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);
+ case OFPUTIL_P_OF15_OXM:
+ return oxm_put_match(b, match,
+ ofputil_protocol_to_ofp_version(protocol));
}
OVS_NOT_REACHED();
};
/* Most users really don't care about some of the differences between
- * 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. */
+ * protocols. These abbreviations help with that. */
static const struct proto_abbrev proto_abbrevs[] = {
- { 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" },
+ { OFPUTIL_P_ANY, "any" },
+ { OFPUTIL_P_OF10_STD_ANY, "OpenFlow10" },
+ { OFPUTIL_P_OF10_NXM_ANY, "NXM" },
+ { OFPUTIL_P_ANY_OXM, "OXM" },
};
#define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
enum ofputil_protocol ofputil_flow_dump_protocols[] = {
+ OFPUTIL_P_OF15_OXM,
OFPUTIL_P_OF14_OXM,
OFPUTIL_P_OF13_OXM,
OFPUTIL_P_OF12_OXM,
return OFPUTIL_P_OF13_OXM;
case OFP14_VERSION:
return OFPUTIL_P_OF14_OXM;
+ case OFP15_VERSION:
+ return OFPUTIL_P_OF15_OXM;
default:
return 0;
}
return OFP13_VERSION;
case OFPUTIL_P_OF14_OXM:
return OFP14_VERSION;
+ case OFPUTIL_P_OF15_OXM:
+ return OFP15_VERSION;
}
OVS_NOT_REACHED();
case OFPUTIL_P_OF14_OXM:
return OFPUTIL_P_OF14_OXM;
+ case OFPUTIL_P_OF15_OXM:
+ return OFPUTIL_P_OF15_OXM;
+
default:
OVS_NOT_REACHED();
}
case OFPUTIL_P_OF14_OXM:
return ofputil_protocol_set_tid(OFPUTIL_P_OF14_OXM, tid);
+ case OFPUTIL_P_OF15_OXM:
+ return ofputil_protocol_set_tid(OFPUTIL_P_OF15_OXM, tid);
+
default:
OVS_NOT_REACHED();
}
case OFPUTIL_P_OF14_OXM:
return "OXM-OpenFlow14";
+
+ case OFPUTIL_P_OF15_OXM:
+ return "OXM-OpenFlow15";
}
/* Check abbreviations. */
return protocols;
}
-static int
+enum ofp_version
ofputil_version_from_string(const char *s)
{
if (!strcasecmp(s, "OpenFlow10")) {
if (!strcasecmp(s, "OpenFlow14")) {
return OFP14_VERSION;
}
+ if (!strcasecmp(s, "OpenFlow15")) {
+ return OFP15_VERSION;
+ }
return 0;
}
return "OpenFlow13";
case OFP14_VERSION:
return "OpenFlow14";
+ case OFP15_VERSION:
+ return "OpenFlow15";
default:
OVS_NOT_REACHED();
}
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
case OFPUTIL_P_OF14_OXM:
+ case OFPUTIL_P_OF15_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();
case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
- case OFPUTIL_P_OF14_OXM: {
+ case OFPUTIL_P_OF14_OXM:
+ case OFPUTIL_P_OF15_OXM: {
struct ofp11_flow_mod *ofm;
int tailroom;
case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
- case OFPUTIL_P_OF14_OXM: {
+ case OFPUTIL_P_OF14_OXM:
+ case OFPUTIL_P_OF15_OXM: {
struct ofp11_flow_stats_request *ofsr;
raw = (fsr->aggregate
struct ofp11_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
- oxm_put_match(reply, &fs->match);
+ oxm_put_match(reply, &fs->match, version);
ofpacts_put_openflow_instructions(fs->ofpacts, fs->ofpacts_len, reply,
version);
case OFPUTIL_P_OF11_STD:
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
- case OFPUTIL_P_OF14_OXM: {
+ case OFPUTIL_P_OF14_OXM:
+ case OFPUTIL_P_OF15_OXM: {
struct ofp12_flow_removed *ofr;
msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
htonl(0), (sizeof(struct flow_metadata) * 2
+ 2 + pin->packet_len));
ofpbuf_put_zeros(packet, packet_in_size);
- oxm_put_match(packet, &match);
+ oxm_put_match(packet, &match, ofputil_protocol_to_ofp_version(protocol));
ofpbuf_put_zeros(packet, 2);
ofpbuf_put(packet, pin->packet, pin->packet_len);
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
case OFPUTIL_P_OF14_OXM:
+ case OFPUTIL_P_OF15_OXM:
packet = ofputil_encode_ofp12_packet_in(pin, protocol);
break;
return 0;
}
-static size_t
-ofputil_get_phy_port_size(enum ofp_version ofp_version)
-{
- switch (ofp_version) {
- case OFP10_VERSION:
- return sizeof(struct ofp10_phy_port);
- case OFP11_VERSION:
- case OFP12_VERSION:
- case OFP13_VERSION:
- case OFP14_VERSION:
- return sizeof(struct ofp11_port);
- default:
- OVS_NOT_REACHED();
- }
-}
-
static void
ofputil_encode_ofp10_phy_port(const struct ofputil_phy_port *pp,
struct ofp10_phy_port *opp)
}
case OFP14_VERSION:
+ case OFP15_VERSION:
ofputil_put_ofp14_port(pp, b);
break;
}
}
+enum ofperr
+ofputil_decode_port_desc_stats_request(const struct ofp_header *request,
+ ofp_port_t *port)
+{
+ struct ofpbuf b;
+ enum ofpraw raw;
+
+ ofpbuf_use_const(&b, request, ntohs(request->length));
+ raw = ofpraw_pull_assert(&b);
+ if (raw == OFPRAW_OFPST10_PORT_DESC_REQUEST) {
+ *port = OFPP_ANY;
+ return 0;
+ } else if (raw == OFPRAW_OFPST15_PORT_DESC_REQUEST) {
+ ovs_be32 *ofp11_port;
+
+ ofp11_port = ofpbuf_pull(&b, sizeof *ofp11_port);
+ return ofputil_port_from_ofp11(*ofp11_port, port);
+ } else {
+ OVS_NOT_REACHED();
+ }
+}
+
+struct ofpbuf *
+ofputil_encode_port_desc_stats_request(enum ofp_version ofp_version,
+ ofp_port_t port)
+{
+ struct ofpbuf *request;
+ ovs_be32 ofp11_port;
+
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ case OFP13_VERSION:
+ case OFP14_VERSION:
+ request = ofpraw_alloc(OFPRAW_OFPST10_PORT_DESC_REQUEST,
+ ofp_version, 0);
+ break;
+
+ case OFP15_VERSION:
+ request = ofpraw_alloc(OFPRAW_OFPST15_PORT_DESC_REQUEST,
+ ofp_version, 0);
+ ofp11_port = ofputil_port_to_ofp11(port);
+ ofpbuf_put(request, &ofp11_port, sizeof ofp11_port);
+ break;
+
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ return request;
+}
+
void
ofputil_append_port_desc_stats_reply(const struct ofputil_phy_port *pp,
struct list *replies)
case OFP12_VERSION:
case OFP13_VERSION:
case OFP14_VERSION:
+ case OFP15_VERSION:
return OFPC_COMMON | OFPC12_PORT_BLOCKED;
default:
/* Caller needs to check osf->header.version itself */
features->capabilities = ntohl(osf->capabilities) &
ofputil_capabilities_mask(oh->version);
- if (ofpbuf_size(b) % ofputil_get_phy_port_size(oh->version)) {
- return OFPERR_OFPBRC_BAD_LEN;
- }
-
if (raw == OFPRAW_OFPT10_FEATURES_REPLY) {
if (osf->capabilities & htonl(OFPC10_STP)) {
features->capabilities |= OFPUTIL_C_STP;
return 0;
}
-/* Returns true if the maximum number of ports are in 'oh'. */
-static bool
-max_ports_in_features(const struct ofp_header *oh)
-{
- size_t pp_size = ofputil_get_phy_port_size(oh->version);
- return ntohs(oh->length) + pp_size > UINT16_MAX;
-}
-
/* In OpenFlow 1.0, 1.1, and 1.2, an OFPT_FEATURES_REPLY message lists all the
* switch's ports, unless there are too many to fit. In OpenFlow 1.3 and
* later, an OFPT_FEATURES_REPLY does not list ports at all.
ofputil_switch_features_has_ports(struct ofpbuf *b)
{
struct ofp_header *oh = ofpbuf_data(b);
+ size_t phy_port_size;
if (oh->version >= OFP13_VERSION) {
+ /* OpenFlow 1.3+ never has ports in the feature reply. */
return false;
- } else if (max_ports_in_features(oh)) {
- ofpbuf_set_size(b, sizeof *oh + sizeof(struct ofp_switch_features));
- ofpmsg_update_length(b);
- return false;
- } else {
+ }
+
+ phy_port_size = (oh->version == OFP10_VERSION
+ ? sizeof(struct ofp10_phy_port)
+ : sizeof(struct ofp11_port));
+ if (ntohs(oh->length) + phy_port_size <= UINT16_MAX) {
+ /* There's room for additional ports in the feature reply.
+ * Assume that the list is complete. */
return true;
}
+
+ /* The feature reply has no room for more ports. Probably the list is
+ * truncated. Drop the ports and tell the caller to retrieve them with
+ * OFPST_PORT_DESC. */
+ ofpbuf_set_size(b, sizeof *oh + sizeof(struct ofp_switch_features));
+ ofpmsg_update_length(b);
+ return false;
}
static ovs_be32
break;
case OFP13_VERSION:
case OFP14_VERSION:
+ case OFP15_VERSION:
raw = OFPRAW_OFPT13_FEATURES_REPLY;
break;
default:
break;
case OFP13_VERSION:
case OFP14_VERSION:
+ case OFP15_VERSION:
osf->auxiliary_id = features->auxiliary_id;
/* fall through */
case OFP11_VERSION:
break;
case OFP14_VERSION:
+ case OFP15_VERSION:
raw = OFPRAW_OFPT14_PORT_STATUS;
break;
opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
break;
}
- case OFP14_VERSION: {
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
struct ofp14_port_mod_prop_ethernet *eth;
struct ofp14_port_mod *opm;
"(\'-O OpenFlow13\')");
case OFP13_VERSION:
case OFP14_VERSION:
+ case OFP15_VERSION:
request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
ofp_version, 0);
break;
otm->config = htonl(pm->config);
break;
}
- case OFP14_VERSION: {
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
struct ofp14_table_mod *otm;
b = ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD, ofp_version, 0);
return buf;
}
\f
+/* Encodes "role status" message 'status' for sending in the given
+ * 'protocol'. Returns the role status message, if 'protocol' supports them,
+ * otherwise a null pointer. */
struct ofpbuf *
ofputil_encode_role_status(const struct ofputil_role_status *status,
enum ofputil_protocol protocol)
{
- struct ofpbuf *buf;
enum ofp_version version;
- struct ofp14_role_status *rstatus;
version = ofputil_protocol_to_ofp_version(protocol);
- buf = ofpraw_alloc_xid(OFPRAW_OFPT14_ROLE_STATUS, version, htonl(0), 0);
- rstatus = ofpbuf_put_zeros(buf, sizeof *rstatus);
- rstatus->role = htonl(status->role);
- rstatus->reason = status->reason;
- rstatus->generation_id = htonll(status->generation_id);
-
- return buf;
+ if (version >= OFP14_VERSION) {
+ struct ofp14_role_status *rstatus;
+ struct ofpbuf *buf;
+
+ buf = ofpraw_alloc_xid(OFPRAW_OFPT14_ROLE_STATUS, version, htonl(0),
+ 0);
+ rstatus = ofpbuf_put_zeros(buf, sizeof *rstatus);
+ rstatus->role = htonl(status->role);
+ rstatus->reason = status->reason;
+ rstatus->generation_id = htonll(status->generation_id);
+
+ return buf;
+ } else {
+ return NULL;
+ }
}
enum ofperr
case OFP13_VERSION:
case OFP14_VERSION:
+ case OFP15_VERSION:
ofputil_put_ofp13_table_stats(&stats[i], reply);
break;
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
- case OFP14_VERSION:{
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
struct ofp11_packet_out *opo;
size_t len;
enum ofpraw type;
switch (ofp_version) {
+ case OFP15_VERSION:
case OFP14_VERSION:
case OFP13_VERSION:
case OFP12_VERSION:
return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
}
case OFP14_VERSION:
+ case OFP15_VERSION:
return ofpbuf_size(b) ? ofputil_pull_ofp14_port(pp, b) : EOF;
default:
OVS_NOT_REACHED();
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
- case OFP14_VERSION:{
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
struct ofp11_port_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST11_PORT_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
ps13->duration_nsec = htonl(ops->duration_nsec);
}
+static void
+ofputil_append_ofp14_port_stats(const struct ofputil_port_stats *ops,
+ struct list *replies)
+{
+ struct ofp14_port_stats_prop_ethernet *eth;
+ struct ofp14_port_stats *ps14;
+ struct ofpbuf *reply;
+
+ reply = ofpmp_reserve(replies, sizeof *ps14 + sizeof *eth);
+
+ ps14 = ofpbuf_put_uninit(reply, sizeof *ps14);
+ ps14->length = htons(sizeof *ps14 + sizeof *eth);
+ memset(ps14->pad, 0, sizeof ps14->pad);
+ ps14->port_no = ofputil_port_to_ofp11(ops->port_no);
+ ps14->duration_sec = htonl(ops->duration_sec);
+ ps14->duration_nsec = htonl(ops->duration_nsec);
+ ps14->rx_packets = htonll(ops->stats.rx_packets);
+ ps14->tx_packets = htonll(ops->stats.tx_packets);
+ ps14->rx_bytes = htonll(ops->stats.rx_bytes);
+ ps14->tx_bytes = htonll(ops->stats.tx_bytes);
+ ps14->rx_dropped = htonll(ops->stats.rx_dropped);
+ ps14->tx_dropped = htonll(ops->stats.tx_dropped);
+ ps14->rx_errors = htonll(ops->stats.rx_errors);
+ ps14->tx_errors = htonll(ops->stats.tx_errors);
+
+ eth = ofpbuf_put_uninit(reply, sizeof *eth);
+ eth->type = htons(OFPPSPT14_ETHERNET);
+ eth->length = htons(sizeof *eth);
+ memset(eth->pad, 0, sizeof eth->pad);
+ eth->rx_frame_err = htonll(ops->stats.rx_frame_errors);
+ eth->rx_over_err = htonll(ops->stats.rx_over_errors);
+ eth->rx_crc_err = htonll(ops->stats.rx_crc_errors);
+ eth->collisions = htonll(ops->stats.collisions);
+}
/* Encode a ports stat for 'ops' and append it to 'replies'. */
void
}
case OFP14_VERSION:
- OVS_NOT_REACHED();
+ case OFP15_VERSION:
+ ofputil_append_ofp14_port_stats(ops, replies);
break;
default:
return error;
}
-static size_t
-ofputil_get_port_stats_size(enum ofp_version ofp_version)
+static enum ofperr
+parse_ofp14_port_stats_ethernet_property(const struct ofpbuf *payload,
+ struct ofputil_port_stats *ops)
{
- switch (ofp_version) {
- case OFP10_VERSION:
- return sizeof(struct ofp10_port_stats);
- case OFP11_VERSION:
- case OFP12_VERSION:
- 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();
+ const struct ofp14_port_stats_prop_ethernet *eth = ofpbuf_data(payload);
+
+ if (ofpbuf_size(payload) != sizeof *eth) {
+ return OFPERR_OFPBPC_BAD_LEN;
}
+
+ ops->stats.rx_frame_errors = ntohll(eth->rx_frame_err);
+ ops->stats.rx_over_errors = ntohll(eth->rx_over_err);
+ ops->stats.rx_crc_errors = ntohll(eth->rx_crc_err);
+ ops->stats.collisions = ntohll(eth->collisions);
+
+ return 0;
+}
+
+static enum ofperr
+ofputil_pull_ofp14_port_stats(struct ofputil_port_stats *ops,
+ struct ofpbuf *msg)
+{
+ const struct ofp14_port_stats *ps14;
+ struct ofpbuf properties;
+ enum ofperr error;
+ size_t len;
+
+ ps14 = ofpbuf_try_pull(msg, sizeof *ps14);
+ if (!ps14) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ len = ntohs(ps14->length);
+ if (len < sizeof *ps14 || len - sizeof *ps14 > ofpbuf_size(msg)) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ len -= sizeof *ps14;
+ ofpbuf_use_const(&properties, ofpbuf_pull(msg, len), len);
+
+ error = ofputil_port_from_ofp11(ps14->port_no, &ops->port_no);
+ if (error) {
+ return error;
+ }
+
+ ops->duration_sec = ntohl(ps14->duration_sec);
+ ops->duration_nsec = ntohl(ps14->duration_nsec);
+ ops->stats.rx_packets = ntohll(ps14->rx_packets);
+ ops->stats.tx_packets = ntohll(ps14->tx_packets);
+ ops->stats.rx_bytes = ntohll(ps14->rx_bytes);
+ ops->stats.tx_bytes = ntohll(ps14->tx_bytes);
+ ops->stats.rx_dropped = ntohll(ps14->rx_dropped);
+ ops->stats.tx_dropped = ntohll(ps14->tx_dropped);
+ ops->stats.rx_errors = ntohll(ps14->rx_errors);
+ ops->stats.tx_errors = ntohll(ps14->tx_errors);
+ ops->stats.rx_frame_errors = UINT64_MAX;
+ ops->stats.rx_over_errors = UINT64_MAX;
+ ops->stats.rx_crc_errors = UINT64_MAX;
+ ops->stats.collisions = UINT64_MAX;
+
+ while (ofpbuf_size(&properties) > 0) {
+ struct ofpbuf payload;
+ enum ofperr error;
+ uint16_t type;
+
+ error = ofputil_pull_property(&properties, &payload, &type);
+ if (error) {
+ return error;
+ }
+
+ switch (type) {
+ case OFPPSPT14_ETHERNET:
+ error = parse_ofp14_port_stats_ethernet_property(&payload, ops);
+ break;
+
+ default:
+ log_property(true, "unknown port stats property %"PRIu16, type);
+ error = 0;
+ break;
+ }
+
+ if (error) {
+ return error;
+ }
+ }
+
+ return 0;
}
/* Returns the number of port stats elements in OFPTYPE_PORT_STATS_REPLY
size_t
ofputil_count_port_stats(const struct ofp_header *oh)
{
+ struct ofputil_port_stats ps;
struct ofpbuf b;
+ size_t n = 0;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpraw_pull_assert(&b);
-
- return ofpbuf_size(&b) / ofputil_get_port_stats_size(oh->version);
+ while (!ofputil_decode_port_stats(&ps, &b)) {
+ n++;
+ }
+ return n;
}
/* Converts an OFPST_PORT_STATS reply in 'msg' into an abstract
if (!ofpbuf_size(msg)) {
return EOF;
+ } else if (raw == OFPRAW_OFPST14_PORT_REPLY) {
+ return ofputil_pull_ofp14_port_stats(ps, msg);
} else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
const struct ofp13_port_stats *ps13;
ofp_port_t *ofp10_port)
{
switch ((enum ofp_version)request->version) {
+ case OFP15_VERSION:
+ case OFP14_VERSION:
case OFP13_VERSION:
case OFP12_VERSION:
case OFP11_VERSION: {
return 0;
}
- case OFP14_VERSION:
- OVS_NOT_REACHED();
- break;
-
default:
OVS_NOT_REACHED();
}
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
- case OFP14_VERSION: {
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
struct ofp11_group_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
return request;
}
+/* Decodes the OpenFlow group description request in 'oh', returning the group
+ * whose description is requested, or OFPG_ALL if stats for all groups was
+ * requested. */
+uint32_t
+ofputil_decode_group_desc_request(const struct ofp_header *oh)
+{
+ struct ofpbuf request;
+ enum ofpraw raw;
+
+ ofpbuf_use_const(&request, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&request);
+ if (raw == OFPRAW_OFPST11_GROUP_DESC_REQUEST) {
+ return OFPG_ALL;
+ } else if (raw == OFPRAW_OFPST15_GROUP_DESC_REQUEST) {
+ ovs_be32 *group_id = ofpbuf_pull(&request, sizeof *group_id);
+ return ntohl(*group_id);
+ } else {
+ OVS_NOT_REACHED();
+ }
+}
+
/* Returns an OpenFlow group description request for OpenFlow version
- * 'ofp_version', that requests stats for group 'group_id'. (Use OFPG_ALL to
- * request stats for all groups.)
+ * 'ofp_version', that requests stats for group 'group_id'. Use OFPG_ALL to
+ * request stats for all groups (OpenFlow 1.4 and earlier always request all
+ * groups).
*
* Group descriptions include the bucket and action configuration for each
* group. */
struct ofpbuf *
-ofputil_encode_group_desc_request(enum ofp_version ofp_version)
+ofputil_encode_group_desc_request(enum ofp_version ofp_version,
+ uint32_t group_id)
{
struct ofpbuf *request;
+ ovs_be32 gid;
switch (ofp_version) {
case OFP10_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
case OFP14_VERSION:
- request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST, ofp_version, 0);
+ request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST,
+ ofp_version, 0);
+ break;
+ case OFP15_VERSION:
+ request = ofpraw_alloc(OFPRAW_OFPST15_GROUP_DESC_REQUEST,
+ ofp_version, 0);
+ gid = htonl(group_id);
+ ofpbuf_put(request, &gid, sizeof gid);
break;
default:
OVS_NOT_REACHED();
}
case OFP13_VERSION:
- case OFP14_VERSION:{
+ case OFP14_VERSION:
+ case OFP15_VERSION: {
struct ofp13_group_stats *gs13;
length = sizeof *gs13 + bucket_counter_size;
case OFP12_VERSION:
case OFP13_VERSION:
case OFP14_VERSION:
+ case OFP15_VERSION:
request = ofpraw_alloc(OFPRAW_OFPST12_GROUP_FEATURES_REQUEST,
ofp_version, 0);
break;
if (!ob) {
VLOG_WARN_RL(&bad_ofmsg_rl, "buckets end with %"PRIuSIZE" leftover bytes",
buckets_length);
+ return OFPERR_OFPGMFC_BAD_BUCKET;
}
ob_len = ntohs(ob->len);
case OFP12_VERSION:
case OFP13_VERSION:
case OFP14_VERSION:
+ case OFP15_VERSION:
b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
start_ogm = ofpbuf_size(b);
ofpbuf_put_zeros(b, sizeof *ogm);
struct ofputil_queue_stats_request *oqsr)
{
switch ((enum ofp_version)request->version) {
+ case OFP15_VERSION:
case OFP14_VERSION:
case OFP13_VERSION:
case OFP12_VERSION:
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
- case OFP14_VERSION: {
+ case OFP14_VERSION:
+ case OFP15_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 request;
}
-static size_t
-ofputil_get_queue_stats_size(enum ofp_version ofp_version)
-{
- switch (ofp_version) {
- case OFP10_VERSION:
- return sizeof(struct ofp10_queue_stats);
- case OFP11_VERSION:
- case OFP12_VERSION:
- 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();
- }
-}
-
/* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY
* message 'oh'. */
size_t
ofputil_count_queue_stats(const struct ofp_header *oh)
{
+ struct ofputil_queue_stats qs;
struct ofpbuf b;
+ size_t n = 0;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpraw_pull_assert(&b);
-
- return ofpbuf_size(&b) / ofputil_get_queue_stats_size(oh->version);
+ while (!ofputil_decode_queue_stats(&qs, &b)) {
+ n++;
+ }
+ return n;
}
static enum ofperr
return error;
}
+static enum ofperr
+ofputil_pull_ofp14_queue_stats(struct ofputil_queue_stats *oqs,
+ struct ofpbuf *msg)
+{
+ const struct ofp14_queue_stats *qs14;
+ size_t len;
+
+ qs14 = ofpbuf_try_pull(msg, sizeof *qs14);
+ if (!qs14) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ len = ntohs(qs14->length);
+ if (len < sizeof *qs14 || len - sizeof *qs14 > ofpbuf_size(msg)) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ ofpbuf_pull(msg, len - sizeof *qs14);
+
+ /* No properties yet defined, so ignore them for now. */
+
+ return ofputil_queue_stats_from_ofp13(oqs, &qs14->qs);
+}
+
/* Converts an OFPST_QUEUE_STATS reply in 'msg' into an abstract
* ofputil_queue_stats in 'qs'.
*
if (!ofpbuf_size(msg)) {
return EOF;
+ } else if (raw == OFPRAW_OFPST14_QUEUE_REPLY) {
+ return ofputil_pull_ofp14_queue_stats(qs, msg);
} else if (raw == OFPRAW_OFPST13_QUEUE_REPLY) {
const struct ofp13_queue_stats *qs13;
}
}
+static void
+ofputil_queue_stats_to_ofp14(const struct ofputil_queue_stats *oqs,
+ struct ofp14_queue_stats *qs14)
+{
+ qs14->length = htons(sizeof *qs14);
+ memset(qs14->pad, 0, sizeof qs14->pad);
+ ofputil_queue_stats_to_ofp13(oqs, &qs14->qs);
+}
+
+
/* Encode a queue stat for 'oqs' and append it to 'replies'. */
void
ofputil_append_queue_stat(struct list *replies,
}
case OFP14_VERSION:
- OVS_NOT_REACHED();
+ case OFP15_VERSION: {
+ struct ofp14_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
+ ofputil_queue_stats_to_ofp14(oqs, reply);
break;
+ }
default:
OVS_NOT_REACHED();