ofpmsg_update_length(b);
return b;
}
-\f
+
/* ofputil_port_mod */
/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in
opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
break;
}
+ default:
+ NOT_REACHED();
+ }
+
+ return b;
+}
+
+/* ofputil_table_mod */
+
+/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
+ * '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */
+enum ofperr
+ofputil_decode_table_mod(const struct ofp_header *oh,
+ struct ofputil_table_mod *pm)
+{
+ enum ofpraw raw;
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+
+ if (raw == OFPRAW_OFPT11_TABLE_MOD) {
+ const struct ofp11_table_mod *otm = b.data;
+
+ pm->table_id = otm->table_id;
+ pm->config = ntohl(otm->config);
+ } else {
+ return OFPERR_OFPBRC_BAD_TYPE;
+ }
+
+ return 0;
+}
+
+/* Converts the abstract form of a "table mod" message in '*pm' into an OpenFlow
+ * message suitable for 'protocol', and returns that encoded form in a buffer
+ * owned by the caller. */
+struct ofpbuf *
+ofputil_encode_table_mod(const struct ofputil_table_mod *pm,
+ enum ofputil_protocol protocol)
+{
+ enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
+ struct ofpbuf *b;
+ switch (ofp_version) {
+ case OFP10_VERSION: {
+ ovs_fatal(0, "table mod needs OpenFlow 1.1 or later "
+ "(\'-O OpenFlow11\')");
+ break;
+ }
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ case OFP13_VERSION: {
+ struct ofp11_table_mod *otm;
+
+ b = ofpraw_alloc(OFPRAW_OFPT11_TABLE_MOD, ofp_version, 0);
+ otm = ofpbuf_put_zeros(b, sizeof *otm);
+ otm->table_id = pm->table_id;
+ otm->config = htonl(pm->config);
+ break;
+ }
default:
NOT_REACHED();
}
out->matched_count = in->matched_count;
}
+static void
+ofputil_put_ofp12_table_stats(const struct ofp12_table_stats *in,
+ struct ofpbuf *buf)
+{
+ struct ofp12_table_stats *out = ofpbuf_put(buf, in, sizeof *in);
+
+ /* Trim off OF1.3-only capabilities. */
+ out->match &= htonll(OFPXMT12_MASK);
+ out->wildcards &= htonll(OFPXMT12_MASK);
+ out->write_setfields &= htonll(OFPXMT12_MASK);
+ out->apply_setfields &= htonll(OFPXMT12_MASK);
+}
+
static void
ofputil_put_ofp13_table_stats(const struct ofp12_table_stats *in,
struct ofpbuf *buf)
reply = ofpraw_alloc_stats_reply(request, n * sizeof *stats);
- switch ((enum ofp_version) request->version) {
- case OFP10_VERSION:
- for (i = 0; i < n; i++) {
+ for (i = 0; i < n; i++) {
+ switch ((enum ofp_version) request->version) {
+ case OFP10_VERSION:
ofputil_put_ofp10_table_stats(&stats[i], reply);
- }
- break;
+ break;
- case OFP11_VERSION:
- for (i = 0; i < n; i++) {
+ case OFP11_VERSION:
ofputil_put_ofp11_table_stats(&stats[i], reply);
- }
- break;
+ break;
- case OFP12_VERSION:
- ofpbuf_put(reply, stats, n * sizeof *stats);
- break;
+ case OFP12_VERSION:
+ ofputil_put_ofp12_table_stats(&stats[i], reply);
+ break;
- case OFP13_VERSION:
- for (i = 0; i < n; i++) {
+ case OFP13_VERSION:
ofputil_put_ofp13_table_stats(&stats[i], reply);
- }
- break;
+ break;
- default:
- NOT_REACHED();
+ default:
+ NOT_REACHED();
+ }
}
return reply;
}
/* Converts a group stats reply in 'msg' into an abstract ofputil_group_stats
- * in 'gs'.
+ * in 'gs'. Assigns freshly allocated memory to gs->bucket_stats for the
+ * caller to eventually free.
*
* Multiple group stats replies can be packed into a single OpenFlow message.
* Calling this function multiple times for a single 'msg' iterates through the
size_t length;
size_t i;
+ gs->bucket_stats = NULL;
error = (msg->l2
? ofpraw_decode(&raw, msg->l2)
: ofpraw_pull(&raw, msg));
return OFPERR_OFPBRC_BAD_LEN;
}
+ gs->bucket_stats = xmalloc(gs->n_buckets * sizeof *gs->bucket_stats);
for (i = 0; i < gs->n_buckets; i++) {
gs->bucket_stats[i].packet_count = ntohll(obc[i].packet_count);
gs->bucket_stats[i].byte_count = ntohll(obc[i].byte_count);