vswitchd: Log all tunnel parameters of given flow.
[sliver-openvswitch.git] / lib / ofp-util.c
index b814768..4facf0a 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <config.h>
 #include "ofp-print.h"
+#include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <sys/types.h>
@@ -84,7 +85,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
 void
 ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
 
     /* Initialize most of wc. */
     flow_wildcards_init_catchall(wc);
@@ -580,15 +581,16 @@ struct proto_abbrev {
 /* Most users really don't care about some of the differences between
  * protocols.  These abbreviations help with that. */
 static const struct proto_abbrev proto_abbrevs[] = {
-    { OFPUTIL_P_ANY,      "any" },
-    { OFPUTIL_P_OF10_ANY, "OpenFlow10" },
-    { OFPUTIL_P_NXM_ANY,  "NXM" },
+    { OFPUTIL_P_ANY,          "any" },
+    { OFPUTIL_P_OF10_STD_ANY, "OpenFlow10" },
+    { OFPUTIL_P_OF10_NXM_ANY,  "NXM" },
 };
 #define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
 
 enum ofputil_protocol ofputil_flow_dump_protocols[] = {
-    OFPUTIL_P_NXM,
-    OFPUTIL_P_OF10,
+    OFPUTIL_P_OF12_OXM,
+    OFPUTIL_P_OF10_NXM,
+    OFPUTIL_P_OF10_STD,
 };
 size_t ofputil_n_flow_dump_protocols = ARRAY_SIZE(ofputil_flow_dump_protocols);
 
@@ -602,9 +604,9 @@ ofputil_protocol_from_ofp_version(enum ofp_version version)
 {
     switch (version) {
     case OFP10_VERSION:
-        return OFPUTIL_P_OF10;
+        return OFPUTIL_P_OF10_STD;
     case OFP12_VERSION:
-        return OFPUTIL_P_OF12;
+        return OFPUTIL_P_OF12_OXM;
     case OFP11_VERSION:
     default:
         return 0;
@@ -617,12 +619,12 @@ enum ofp_version
 ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
 {
     switch (protocol) {
-    case OFPUTIL_P_OF10:
-    case OFPUTIL_P_OF10_TID:
-    case OFPUTIL_P_NXM:
-    case OFPUTIL_P_NXM_TID:
+    case OFPUTIL_P_OF10_STD:
+    case OFPUTIL_P_OF10_STD_TID:
+    case OFPUTIL_P_OF10_NXM:
+    case OFPUTIL_P_OF10_NXM_TID:
         return OFP10_VERSION;
-    case OFPUTIL_P_OF12:
+    case OFPUTIL_P_OF12_OXM:
         return OFP12_VERSION;
     }
 
@@ -651,16 +653,16 @@ enum ofputil_protocol
 ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable)
 {
     switch (protocol) {
-    case OFPUTIL_P_OF10:
-    case OFPUTIL_P_OF10_TID:
-        return enable ? OFPUTIL_P_OF10_TID : OFPUTIL_P_OF10;
+    case OFPUTIL_P_OF10_STD:
+    case OFPUTIL_P_OF10_STD_TID:
+        return enable ? OFPUTIL_P_OF10_STD_TID : OFPUTIL_P_OF10_STD;
 
-    case OFPUTIL_P_NXM:
-    case OFPUTIL_P_NXM_TID:
-        return enable ? OFPUTIL_P_NXM_TID : OFPUTIL_P_NXM;
+    case OFPUTIL_P_OF10_NXM:
+    case OFPUTIL_P_OF10_NXM_TID:
+        return enable ? OFPUTIL_P_OF10_NXM_TID : OFPUTIL_P_OF10_NXM;
 
-    case OFPUTIL_P_OF12:
-        return OFPUTIL_P_OF12;
+    case OFPUTIL_P_OF12_OXM:
+        return OFPUTIL_P_OF12_OXM;
 
     default:
         NOT_REACHED();
@@ -685,16 +687,16 @@ ofputil_protocol_set_base(enum ofputil_protocol cur,
     bool tid = (cur & OFPUTIL_P_TID) != 0;
 
     switch (new_base) {
-    case OFPUTIL_P_OF10:
-    case OFPUTIL_P_OF10_TID:
-        return ofputil_protocol_set_tid(OFPUTIL_P_OF10, tid);
+    case OFPUTIL_P_OF10_STD:
+    case OFPUTIL_P_OF10_STD_TID:
+        return ofputil_protocol_set_tid(OFPUTIL_P_OF10_STD, tid);
 
-    case OFPUTIL_P_NXM:
-    case OFPUTIL_P_NXM_TID:
-        return ofputil_protocol_set_tid(OFPUTIL_P_NXM, tid);
+    case OFPUTIL_P_OF10_NXM:
+    case OFPUTIL_P_OF10_NXM_TID:
+        return ofputil_protocol_set_tid(OFPUTIL_P_OF10_NXM, tid);
 
-    case OFPUTIL_P_OF12:
-        return ofputil_protocol_set_tid(OFPUTIL_P_OF12, tid);
+    case OFPUTIL_P_OF12_OXM:
+        return ofputil_protocol_set_tid(OFPUTIL_P_OF12_OXM, tid);
 
     default:
         NOT_REACHED();
@@ -712,20 +714,20 @@ ofputil_protocol_to_string(enum ofputil_protocol protocol)
     /* Use a "switch" statement for single-bit names so that we get a compiler
      * warning if we forget any. */
     switch (protocol) {
-    case OFPUTIL_P_NXM:
+    case OFPUTIL_P_OF10_NXM:
         return "NXM-table_id";
 
-    case OFPUTIL_P_NXM_TID:
+    case OFPUTIL_P_OF10_NXM_TID:
         return "NXM+table_id";
 
-    case OFPUTIL_P_OF10:
+    case OFPUTIL_P_OF10_STD:
         return "OpenFlow10-table_id";
 
-    case OFPUTIL_P_OF10_TID:
+    case OFPUTIL_P_OF10_STD_TID:
         return "OpenFlow10+table_id";
 
-    case OFPUTIL_P_OF12:
-        return NULL;
+    case OFPUTIL_P_OF12_OXM:
+        return "OXM";
     }
 
     /* Check abbreviations. */
@@ -846,6 +848,91 @@ ofputil_protocols_from_string(const char *s)
     return protocols;
 }
 
+static int
+ofputil_version_from_string(const char *s)
+{
+    if (!strcasecmp(s, "OpenFlow10")) {
+        return OFP10_VERSION;
+    }
+    if (!strcasecmp(s, "OpenFlow11")) {
+        return OFP11_VERSION;
+    }
+    if (!strcasecmp(s, "OpenFlow12")) {
+        return OFP12_VERSION;
+    }
+    return 0;
+}
+
+static bool
+is_delimiter(char c)
+{
+    return isspace(c) || c == ',';
+}
+
+uint32_t
+ofputil_versions_from_string(const char *s)
+{
+    size_t i = 0;
+    uint32_t bitmap = 0;
+
+    while (s[i]) {
+        size_t j;
+        int version;
+        char *key;
+
+        if (is_delimiter(s[i])) {
+            i++;
+            continue;
+        }
+        j = 0;
+        while (s[i + j] && !is_delimiter(s[i + j])) {
+            j++;
+        }
+        key = xmemdup0(s + i, j);
+        version = ofputil_version_from_string(key);
+        if (!version) {
+            VLOG_FATAL("Unknown OpenFlow version: \"%s\"", key);
+        }
+        free(key);
+        bitmap |= 1u << version;
+        i += j;
+    }
+
+    return bitmap;
+}
+
+uint32_t
+ofputil_versions_from_strings(char ** const s, size_t count)
+{
+    uint32_t bitmap = 0;
+
+    while (count--) {
+        int version = ofputil_version_from_string(s[count]);
+        if (!version) {
+            VLOG_WARN("Unknown OpenFlow version: \"%s\"", s[count]);
+        } else {
+            bitmap |= 1u << version;
+        }
+    }
+
+    return bitmap;
+}
+
+const char *
+ofputil_version_to_string(enum ofp_version ofp_version)
+{
+    switch (ofp_version) {
+    case OFP10_VERSION:
+        return "OpenFlow10";
+    case OFP11_VERSION:
+        return "OpenFlow11";
+    case OFP12_VERSION:
+        return "OpenFlow12";
+    default:
+        NOT_REACHED();
+    }
+}
+
 bool
 ofputil_packet_in_format_is_valid(enum nx_packet_in_format packet_in_format)
 {
@@ -892,6 +979,16 @@ regs_fully_wildcarded(const struct flow_wildcards *wc)
     return true;
 }
 
+static bool
+tun_parms_fully_wildcarded(const struct flow_wildcards *wc)
+{
+    return (!wc->masks.tunnel.ip_src &&
+            !wc->masks.tunnel.ip_dst &&
+            !wc->masks.tunnel.ip_ttl &&
+            !wc->masks.tunnel.ip_tos &&
+            !wc->masks.tunnel.flags);
+}
+
 /* Returns a bit-mask of ofputil_protocols that can be used for sending 'match'
  * to a switch (e.g. to add or remove a flow).  Only NXM can handle tunnel IDs,
  * registers, or fixing the Ethernet multicast bit.  Otherwise, it's better to
@@ -901,111 +998,283 @@ ofputil_usable_protocols(const struct match *match)
 {
     const struct flow_wildcards *wc = &match->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
 
-    /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
+    /* tunnel params other than tun_id can't be sent in a flow_mod */
+    if (!tun_parms_fully_wildcarded(wc)) {
+        return OFPUTIL_P_NONE;
+    }
+
+    /* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */
     if (!eth_mask_is_exact(wc->masks.dl_src)
         && !eth_addr_is_zero(wc->masks.dl_src)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
     if (!eth_mask_is_exact(wc->masks.dl_dst)
         && !eth_addr_is_zero(wc->masks.dl_dst)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* NXM and OF1.1+ support matching metadata. */
+    /* NXM, OXM, and OF1.1+ support matching metadata. */
     if (wc->masks.metadata != htonll(0)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching ARP hardware addresses. */
+    /* NXM and OXM support matching ARP hardware addresses. */
     if (!eth_addr_is_zero(wc->masks.arp_sha) ||
         !eth_addr_is_zero(wc->masks.arp_tha)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching IPv6 traffic. */
+    /* NXM and OXM support matching IPv6 traffic. */
     if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching registers. */
+    /* NXM and OXM support matching registers. */
     if (!regs_fully_wildcarded(wc)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching tun_id. */
+    /* NXM and OXM support matching tun_id. */
     if (wc->masks.tunnel.tun_id != htonll(0)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching fragments. */
+    /* NXM and OXM support matching fragments. */
     if (wc->masks.nw_frag) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching IPv6 flow label. */
+    /* NXM and OXM support matching IPv6 flow label. */
     if (wc->masks.ipv6_label) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching IP ECN bits. */
+    /* NXM and OXM support matching IP ECN bits. */
     if (wc->masks.nw_tos & IP_ECN_MASK) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports matching IP TTL/hop limit. */
+    /* NXM and OXM support matching IP TTL/hop limit. */
     if (wc->masks.nw_ttl) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports non-CIDR IPv4 address masks. */
+    /* NXM and OXM support non-CIDR IPv4 address masks. */
     if (!ip_is_cidr(wc->masks.nw_src) || !ip_is_cidr(wc->masks.nw_dst)) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
-    /* Only NXM supports bitwise matching on transport port. */
+    /* NXM and OXM support bitwise matching on transport port. */
     if ((wc->masks.tp_src && wc->masks.tp_src != htons(UINT16_MAX)) ||
         (wc->masks.tp_dst && wc->masks.tp_dst != htons(UINT16_MAX))) {
-        return OFPUTIL_P_NXM_ANY;
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
 
     /* Other formats can express this rule. */
     return OFPUTIL_P_ANY;
 }
 
+void
+ofputil_format_version(struct ds *msg, enum ofp_version version)
+{
+    ds_put_format(msg, "0x%02x", version);
+}
+
+void
+ofputil_format_version_name(struct ds *msg, enum ofp_version version)
+{
+    ds_put_cstr(msg, ofputil_version_to_string(version));
+}
+
+static void
+ofputil_format_version_bitmap__(struct ds *msg, uint32_t bitmap,
+                                void (*format_version)(struct ds *msg,
+                                                       enum ofp_version))
+{
+    while (bitmap) {
+        format_version(msg, raw_ctz(bitmap));
+        bitmap = zero_rightmost_1bit(bitmap);
+        if (bitmap) {
+            ds_put_cstr(msg, ", ");
+        }
+    }
+}
+
+void
+ofputil_format_version_bitmap(struct ds *msg, uint32_t bitmap)
+{
+    ofputil_format_version_bitmap__(msg, bitmap, ofputil_format_version);
+}
+
+void
+ofputil_format_version_bitmap_names(struct ds *msg, uint32_t bitmap)
+{
+    ofputil_format_version_bitmap__(msg, bitmap, ofputil_format_version_name);
+}
+
+static bool
+ofputil_decode_hello_bitmap(const struct ofp_hello_elem_header *oheh,
+                            uint32_t *allowed_versionsp)
+{
+    uint16_t bitmap_len = ntohs(oheh->length) - sizeof *oheh;
+    const ovs_be32 *bitmap = (const ovs_be32 *) (oheh + 1);
+    uint32_t allowed_versions;
+
+    if (!bitmap_len || bitmap_len % sizeof *bitmap) {
+        return false;
+    }
+
+    /* Only use the first 32-bit element of the bitmap as that is all the
+     * current implementation supports.  Subsequent elements are ignored which
+     * should have no effect on session negotiation until Open vSwtich supports
+     * wire-protocol versions greater than 31.
+     */
+    allowed_versions = ntohl(bitmap[0]);
+
+    if (allowed_versions & 1) {
+        /* There's no OpenFlow version 0. */
+        VLOG_WARN_RL(&bad_ofmsg_rl, "peer claims to support invalid OpenFlow "
+                     "version 0x00");
+        allowed_versions &= ~1u;
+    }
+
+    if (!allowed_versions) {
+        VLOG_WARN_RL(&bad_ofmsg_rl, "peer does not support any OpenFlow "
+                     "version (between 0x01 and 0x1f)");
+        return false;
+    }
+
+    *allowed_versionsp = allowed_versions;
+    return true;
+}
+
+static uint32_t
+version_bitmap_from_version(uint8_t ofp_version)
+{
+    return ((ofp_version < 32 ? 1u << ofp_version : 0) - 1) << 1;
+}
+
+/* Decodes OpenFlow OFPT_HELLO message 'oh', storing into '*allowed_versions'
+ * the set of OpenFlow versions for which 'oh' announces support.
+ *
+ * Because of how OpenFlow defines OFPT_HELLO messages, this function is always
+ * successful, and thus '*allowed_versions' is always initialized.  However, it
+ * returns false if 'oh' contains some data that could not be fully understood,
+ * true if 'oh' was completely parsed. */
+bool
+ofputil_decode_hello(const struct ofp_header *oh, uint32_t *allowed_versions)
+{
+    struct ofpbuf msg;
+    bool ok = true;
+
+    ofpbuf_use_const(&msg, oh, ntohs(oh->length));
+    ofpbuf_pull(&msg, sizeof *oh);
+
+    *allowed_versions = version_bitmap_from_version(oh->version);
+    while (msg.size) {
+        const struct ofp_hello_elem_header *oheh;
+        unsigned int len;
+
+        if (msg.size < sizeof *oheh) {
+            return false;
+        }
+
+        oheh = msg.data;
+        len = ntohs(oheh->length);
+        if (len < sizeof *oheh || !ofpbuf_try_pull(&msg, ROUND_UP(len, 8))) {
+            return false;
+        }
+
+        if (oheh->type != htons(OFPHET_VERSIONBITMAP)
+            || !ofputil_decode_hello_bitmap(oheh, allowed_versions)) {
+            ok = false;
+        }
+    }
+
+    return ok;
+}
+
+/* Returns true if 'allowed_versions' needs to be accompanied by a version
+ * bitmap to be correctly expressed in an OFPT_HELLO message. */
+static inline bool
+should_send_version_bitmap(uint32_t allowed_versions)
+{
+    return !is_pow2((allowed_versions >> 1) + 1);
+}
+
+/* Create an OFPT_HELLO message that expresses support for the OpenFlow
+ * versions in the 'allowed_versions' bitmaps and returns the message. */
+struct ofpbuf *
+ofputil_encode_hello(uint32_t allowed_versions)
+{
+    enum ofp_version ofp_version;
+    struct ofpbuf *msg;
+
+    ofp_version = leftmost_1bit_idx(allowed_versions);
+    msg = ofpraw_alloc(OFPRAW_OFPT_HELLO, ofp_version, 0);
+
+    if (should_send_version_bitmap(allowed_versions)) {
+        struct ofp_hello_elem_header *oheh;
+        uint16_t map_len;
+
+        map_len = sizeof allowed_versions;
+        oheh = ofpbuf_put_zeros(msg, ROUND_UP(map_len + sizeof *oheh, 8));
+        oheh->type = htons(OFPHET_VERSIONBITMAP);
+        oheh->length = htons(map_len + sizeof *oheh);
+        *(ovs_be32 *)(oheh + 1) = htonl(allowed_versions);
+
+        ofpmsg_update_length(msg);
+    }
+
+    return msg;
+}
+
 /* Returns an OpenFlow message that, sent on an OpenFlow connection whose
  * protocol is 'current', at least partly transitions the protocol to 'want'.
  * Stores in '*next' the protocol that will be in effect on the OpenFlow
  * connection if the switch processes the returned message correctly.  (If
  * '*next != want' then the caller will have to iterate.)
  *
- * If 'current == want', returns NULL and stores 'current' in '*next'. */
+ * If 'current == want', or if it is not possible to transition from 'current'
+ * to 'want' (because, for example, 'current' and 'want' use different OpenFlow
+ * protocol versions), returns NULL and stores 'current' in '*next'. */
 struct ofpbuf *
 ofputil_encode_set_protocol(enum ofputil_protocol current,
                             enum ofputil_protocol want,
                             enum ofputil_protocol *next)
 {
+    enum ofp_version cur_version, want_version;
     enum ofputil_protocol cur_base, want_base;
     bool cur_tid, want_tid;
 
+    cur_version = ofputil_protocol_to_ofp_version(current);
+    want_version = ofputil_protocol_to_ofp_version(want);
+    if (cur_version != want_version) {
+        *next = current;
+        return NULL;
+    }
+
     cur_base = ofputil_protocol_to_base(current);
     want_base = ofputil_protocol_to_base(want);
     if (cur_base != want_base) {
         *next = ofputil_protocol_set_base(current, want_base);
 
         switch (want_base) {
-        case OFPUTIL_P_NXM:
+        case OFPUTIL_P_OF10_NXM:
             return ofputil_encode_nx_set_flow_format(NXFF_NXM);
 
-        case OFPUTIL_P_OF10:
+        case OFPUTIL_P_OF10_STD:
             return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW10);
 
-        case OFPUTIL_P_OF12:
-            return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW12);
+        case OFPUTIL_P_OF12_OXM:
+            /* There's only one OpenFlow 1.2 protocol and we already verified
+             * above that we're not trying to change versions. */
+            NOT_REACHED();
 
-        case OFPUTIL_P_OF10_TID:
-        case OFPUTIL_P_NXM_TID:
+        case OFPUTIL_P_OF10_STD_TID:
+        case OFPUTIL_P_OF10_NXM_TID:
             NOT_REACHED();
         }
     }
@@ -1047,13 +1316,10 @@ ofputil_nx_flow_format_to_protocol(enum nx_flow_format flow_format)
 {
     switch (flow_format) {
     case NXFF_OPENFLOW10:
-        return OFPUTIL_P_OF10;
+        return OFPUTIL_P_OF10_STD;
 
     case NXFF_NXM:
-        return OFPUTIL_P_NXM;
-
-    case NXFF_OPENFLOW12:
-        return OFPUTIL_P_OF12;
+        return OFPUTIL_P_OF10_NXM;
 
     default:
         return 0;
@@ -1077,8 +1343,6 @@ ofputil_nx_flow_format_to_string(enum nx_flow_format flow_format)
         return "openflow10";
     case NXFF_NXM:
         return "nxm";
-    case NXFF_OPENFLOW12:
-        return "openflow12";
     default:
         NOT_REACHED();
     }
@@ -1278,7 +1542,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
     struct ofpbuf *msg;
 
     switch (protocol) {
-    case OFPUTIL_P_OF12: {
+    case OFPUTIL_P_OF12_OXM: {
         struct ofp11_flow_mod *ofm;
 
         msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, OFP12_VERSION,
@@ -1304,8 +1568,8 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         break;
     }
 
-    case OFPUTIL_P_OF10:
-    case OFPUTIL_P_OF10_TID: {
+    case OFPUTIL_P_OF10_STD:
+    case OFPUTIL_P_OF10_STD_TID: {
         struct ofp10_flow_mod *ofm;
 
         msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
@@ -1324,8 +1588,8 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         break;
     }
 
-    case OFPUTIL_P_NXM:
-    case OFPUTIL_P_NXM_TID: {
+    case OFPUTIL_P_OF10_NXM:
+    case OFPUTIL_P_OF10_NXM_TID: {
         struct nx_flow_mod *nfm;
         int match_len;
 
@@ -1376,12 +1640,11 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
             usable_protocols &= OFPUTIL_P_TID;
         }
 
-        /* Matching of the cookie is only supported through NXM. */
+        /* Matching of the cookie is only supported through NXM or OF1.1+. */
         if (fm->cookie_mask != htonll(0)) {
-            usable_protocols &= OFPUTIL_P_NXM_ANY;
+            usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
         }
     }
-    assert(usable_protocols);
 
     return usable_protocols;
 }
@@ -1499,7 +1762,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
     enum ofpraw raw;
 
     switch (protocol) {
-    case OFPUTIL_P_OF12: {
+    case OFPUTIL_P_OF12_OXM: {
         struct ofp11_flow_stats_request *ofsr;
 
         raw = (fsr->aggregate
@@ -1516,8 +1779,8 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
         break;
     }
 
-    case OFPUTIL_P_OF10:
-    case OFPUTIL_P_OF10_TID: {
+    case OFPUTIL_P_OF10_STD:
+    case OFPUTIL_P_OF10_STD_TID: {
         struct ofp10_flow_stats_request *ofsr;
 
         raw = (fsr->aggregate
@@ -1531,8 +1794,8 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
         break;
     }
 
-    case OFPUTIL_P_NXM:
-    case OFPUTIL_P_NXM_TID: {
+    case OFPUTIL_P_OF10_NXM:
+    case OFPUTIL_P_OF10_NXM_TID: {
         struct nx_flow_stats_request *nfsr;
         int match_len;
 
@@ -1570,7 +1833,7 @@ ofputil_flow_stats_request_usable_protocols(
 
     usable_protocols = ofputil_usable_protocols(&fsr->match);
     if (fsr->cookie_mask != htonll(0)) {
-        usable_protocols &= OFPUTIL_P_NXM_ANY;
+        usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
     }
     return usable_protocols;
 }
@@ -1982,7 +2245,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     struct ofpbuf *msg;
 
     switch (protocol) {
-    case OFPUTIL_P_OF12: {
+    case OFPUTIL_P_OF12_OXM: {
         struct ofp12_flow_removed *ofr;
 
         msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
@@ -2003,8 +2266,8 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         break;
     }
 
-    case OFPUTIL_P_OF10:
-    case OFPUTIL_P_OF10_TID: {
+    case OFPUTIL_P_OF10_STD:
+    case OFPUTIL_P_OF10_STD_TID: {
         struct ofp_flow_removed *ofr;
 
         msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
@@ -2022,8 +2285,8 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         break;
     }
 
-    case OFPUTIL_P_NXM:
-    case OFPUTIL_P_NXM_TID: {
+    case OFPUTIL_P_OF10_NXM:
+    case OFPUTIL_P_OF10_NXM_TID: {
         struct nx_flow_removed *nfr;
         int match_len;
 
@@ -2175,7 +2438,7 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
     struct ofpbuf *packet;
 
     /* Add OFPT_PACKET_IN. */
-    if (protocol == OFPUTIL_P_OF12) {
+    if (protocol == OFPUTIL_P_OF12_OXM) {
         struct ofp12_packet_in *opi;
         struct match match;
 
@@ -2421,8 +2684,8 @@ ofputil_decode_ofp10_phy_port(struct ofputil_phy_port *pp,
     pp->supported = netdev_port_features_from_ofp10(opp->supported);
     pp->peer = netdev_port_features_from_ofp10(opp->peer);
 
-    pp->curr_speed = netdev_features_to_bps(pp->curr) / 1000;
-    pp->max_speed = netdev_features_to_bps(pp->supported) / 1000;
+    pp->curr_speed = netdev_features_to_bps(pp->curr, 0) / 1000;
+    pp->max_speed = netdev_features_to_bps(pp->supported, 0) / 1000;
 
     return 0;
 }