[ovs-dev] [PATCH 3/3] lib: Check for usable protocols for actions and matches.

Jarno Rajahalme jarno.rajahalme at nsn.com
Fri Jun 28 16:44:05 UTC 2013


Keep track of usable protocols while parsing, rather than checking for them
afterwards.  Check the usable protocols for actions as well as matches.
This fixes silently discarded meter and goto table instructions when not
explicitly specifying the protocol to use.

Signed-off-by: Jarno Rajahalme <jarno.rajahalme at nsn.com>
---
 lib/learning-switch.c      |   11 ++-
 lib/learning-switch.h      |    2 +
 lib/meta-flow.c            |  120 ++++++++++++++++++++++++++--
 lib/meta-flow.h            |   21 ++++-
 lib/ofp-actions.c          |   15 +++-
 lib/ofp-actions.h          |   90 +++++++++++----------
 lib/ofp-parse.c            |   61 ++++++++++++---
 lib/ofp-parse.h            |   22 +++---
 lib/ofp-util.c             |  187 --------------------------------------------
 lib/ofp-util.h             |   16 ++--
 ofproto/ofproto.c          |    7 +-
 utilities/ovs-controller.c |    7 +-
 utilities/ovs-ofctl.c      |   51 ++++++------
 13 files changed, 304 insertions(+), 306 deletions(-)

diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 426cb37..f2d2ede 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -89,6 +89,7 @@ struct lswitch {
      * to set up the flow table. */
     const struct ofputil_flow_mod *default_flows;
     size_t n_default_flows;
+    enum ofputil_protocol usable_protocols;
 };
 
 /* The log messages here could actually be useful in debugging, so keep the
@@ -161,6 +162,7 @@ lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg)
 
     sw->default_flows = cfg->default_flows;
     sw->n_default_flows = cfg->n_default_flows;
+    sw->usable_protocols = cfg->usable_protocols;
 
     sw->queued = rconn_packet_counter_create();
 
@@ -176,7 +178,6 @@ lswitch_handshake(struct lswitch *sw)
 
     protocol = ofputil_protocol_from_ofp_version(rconn_get_version(sw->rconn));
     if (sw->default_flows) {
-        enum ofputil_protocol usable_protocols;
         struct ofpbuf *msg = NULL;
         int error = 0;
         size_t i;
@@ -188,10 +189,8 @@ lswitch_handshake(struct lswitch *sw)
          * This could be improved by actually negotiating a mutually acceptable
          * flow format with the switch, but that would require an asynchronous
          * state machine.  This version ought to work fine in practice. */
-        usable_protocols = ofputil_flow_mod_usable_protocols(
-            sw->default_flows, sw->n_default_flows);
-        if (!(protocol & usable_protocols)) {
-            enum ofputil_protocol want = rightmost_1bit(usable_protocols);
+        if (!(protocol & sw->usable_protocols)) {
+            enum ofputil_protocol want = rightmost_1bit(sw->usable_protocols);
             while (!error) {
                 msg = ofputil_encode_set_protocol(protocol, want, &protocol);
                 if (!msg) {
@@ -200,7 +199,7 @@ lswitch_handshake(struct lswitch *sw)
                 error = rconn_send(sw->rconn, msg, NULL);
             }
         }
-        if (protocol & usable_protocols) {
+        if (protocol & sw->usable_protocols) {
             for (i = 0; !error && i < sw->n_default_flows; i++) {
                 msg = ofputil_encode_flow_mod(&sw->default_flows[i], protocol);
                 error = rconn_send(sw->rconn, msg, NULL);
diff --git a/lib/learning-switch.h b/lib/learning-switch.h
index dcfb5a2..b3a5d13 100644
--- a/lib/learning-switch.h
+++ b/lib/learning-switch.h
@@ -20,6 +20,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
+#include "ofp-util.h"
 
 struct ofpbuf;
 struct rconn;
@@ -50,6 +51,7 @@ struct lswitch_config {
      * to set up the flow table. */
     const struct ofputil_flow_mod *default_flows;
     size_t n_default_flows;
+    enum ofputil_protocol usable_protocols;
 
     /* The OpenFlow queue to use by default.  Use UINT32_MAX to avoid
      * specifying a particular queue. */
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 0677202..76f2269 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -54,6 +54,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_NX_TUN_ID, "NXM_NX_TUN_ID",
         OXM_OF_TUNNEL_ID, "OXM_OF_TUNNEL_ID",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_TUN_SRC, "tun_src", NULL,
         MF_FIELD_SIZES(be32),
@@ -63,6 +65,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
         NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_TUN_DST, "tun_dst", NULL,
         MF_FIELD_SIZES(be32),
@@ -72,6 +76,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
         NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_TUN_FLAGS, "tun_flags", NULL,
         MF_FIELD_SIZES(be16),
@@ -81,6 +87,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         0, NULL,
         0, NULL,
+        OFPUTIL_P_NONE,
+        OFPUTIL_P_NONE,
     }, {
         MFF_TUN_TOS, "tun_tos", NULL,
         MF_FIELD_SIZES(u8),
@@ -90,6 +98,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         0, NULL,
         0, NULL,
+        OFPUTIL_P_NONE,
+        OFPUTIL_P_NONE,
     }, {
         MFF_TUN_TTL, "tun_ttl", NULL,
         MF_FIELD_SIZES(u8),
@@ -99,6 +109,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         0, NULL,
         0, NULL,
+        OFPUTIL_P_NONE,
+        OFPUTIL_P_NONE,
     }, {
         MFF_METADATA, "metadata", NULL,
         MF_FIELD_SIZES(be64),
@@ -108,6 +120,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         OXM_OF_METADATA, "OXM_OF_METADATA",
         OXM_OF_METADATA, "OXM_OF_METADATA",
+        OFPUTIL_P_NXM_OF11_UP,
+        OFPUTIL_P_NXM_OF11_UP,
     }, {
         MFF_IN_PORT, "in_port", NULL,
         MF_FIELD_SIZES(be16),
@@ -117,6 +131,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_IN_PORT, "NXM_OF_IN_PORT",
         NXM_OF_IN_PORT, "NXM_OF_IN_PORT",
+        OFPUTIL_P_ANY,   /* OF11+ via mapping to 32 bits. */
+        OFPUTIL_P_NONE,
     }, {
         MFF_IN_PORT_OXM, "in_port_oxm", NULL,
         MF_FIELD_SIZES(be32),
@@ -126,6 +142,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         OXM_OF_IN_PORT, "OXM_OF_IN_PORT",
         OXM_OF_IN_PORT, "OXM_OF_IN_PORT",
+        OFPUTIL_P_OF11_UP,
+        OFPUTIL_P_NONE,
     }, {
         MFF_SKB_PRIORITY, "skb_priority", NULL,
         MF_FIELD_SIZES(be32),
@@ -135,6 +153,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         0, NULL,
         0, NULL,
+        OFPUTIL_P_NONE,
+        OFPUTIL_P_NONE,
     }, {
         MFF_SKB_MARK, "skb_mark", NULL,
         MF_FIELD_SIZES(be32),
@@ -144,6 +164,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         0, NULL,
         0, NULL,
+        OFPUTIL_P_NONE,
+        OFPUTIL_P_NONE,
     },
 
 #define REGISTER(IDX)                           \
@@ -156,6 +178,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,                                   \
         NXM_NX_REG(IDX), "NXM_NX_REG" #IDX,     \
         NXM_NX_REG(IDX), "NXM_NX_REG" #IDX,     \
+        OFPUTIL_P_NXM_OXM_ANY,                  \
+        OFPUTIL_P_NXM_OXM_ANY,                  \
     }
 #if FLOW_N_REGS > 0
     REGISTER(0),
@@ -198,6 +222,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_ETH_SRC, "NXM_OF_ETH_SRC",
         OXM_OF_ETH_SRC, "OXM_OF_ETH_SRC",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
     }, {
         MFF_ETH_DST, "eth_dst", "dl_dst",
         MF_FIELD_SIZES(mac),
@@ -207,6 +233,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_ETH_DST, "NXM_OF_ETH_DST",
         OXM_OF_ETH_DST, "OXM_OF_ETH_DST",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
     }, {
         MFF_ETH_TYPE, "eth_type", "dl_type",
         MF_FIELD_SIZES(be16),
@@ -216,6 +244,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_OF_ETH_TYPE, "NXM_OF_ETH_TYPE",
         OXM_OF_ETH_TYPE, "OXM_OF_ETH_TYPE",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NONE,
     },
 
     {
@@ -227,6 +257,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
         NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_DL_VLAN, "dl_vlan", NULL,
         sizeof(ovs_be16), 12,
@@ -236,6 +268,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         0, NULL,
         0, NULL,
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_VLAN_VID, "vlan_vid", NULL,
         sizeof(ovs_be16), 12,
@@ -245,6 +279,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
         OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_DL_VLAN_PCP, "dl_vlan_pcp", NULL,
         1, 3,
@@ -254,6 +290,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         0, NULL,
         0, NULL,
+        OFPUTIL_P_ANY,   /* Will be mapped to NXM and OXM. */
+        OFPUTIL_P_NONE,
     }, {
         MFF_VLAN_PCP, "vlan_pcp", NULL,
         1, 3,
@@ -263,6 +301,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
         OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
+        OFPUTIL_P_ANY,   /* Will be mapped to OF10 and NXM. */
+        OFPUTIL_P_NONE,
     },
 
     /* ## ---- ## */
@@ -277,6 +317,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
         OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
+        OFPUTIL_P_NXM_OF11_UP,
+        OFPUTIL_P_NONE,
     }, {
         MFF_MPLS_TC, "mpls_tc", NULL,
         1, 3,
@@ -286,6 +328,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
         OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
+        OFPUTIL_P_NXM_OF11_UP,
+        OFPUTIL_P_NONE,
     }, {
         MFF_MPLS_BOS, "mpls_bos", NULL,
         1, 1,
@@ -295,6 +339,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
         OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
     },
 
     /* ## -- ## */
@@ -310,6 +356,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_IP_SRC, "NXM_OF_IP_SRC",
         OXM_OF_IPV4_SRC, "OXM_OF_IPV4_SRC",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OF11_UP,
     }, {
         MFF_IPV4_DST, "ip_dst", "nw_dst",
         MF_FIELD_SIZES(be32),
@@ -319,6 +367,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_IP_DST, "NXM_OF_IP_DST",
         OXM_OF_IPV4_DST, "OXM_OF_IPV4_DST",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OF11_UP,
     },
 
     {
@@ -330,6 +380,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_NX_IPV6_SRC, "NXM_NX_IPV6_SRC",
         OXM_OF_IPV6_SRC, "OXM_OF_IPV6_SRC",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_IPV6_DST, "ipv6_dst", NULL,
         MF_FIELD_SIZES(ipv6),
@@ -339,6 +391,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_NX_IPV6_DST, "NXM_NX_IPV6_DST",
         OXM_OF_IPV6_DST, "OXM_OF_IPV6_DST",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     },
     {
         MFF_IPV6_LABEL, "ipv6_label", NULL,
@@ -349,6 +403,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_IPV6_LABEL, "NXM_NX_IPV6_LABEL",
         OXM_OF_IPV6_FLABEL, "OXM_OF_IPV6_FLABEL",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     },
 
     {
@@ -360,6 +416,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_OF_IP_PROTO, "NXM_OF_IP_PROTO",
         OXM_OF_IP_PROTO, "OXM_OF_IP_PROTO",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NONE,
     }, {
         MFF_IP_DSCP, "nw_tos", NULL,
         MF_FIELD_SIZES(u8),
@@ -369,6 +427,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_IP_TOS, "NXM_OF_IP_TOS",
         NXM_OF_IP_TOS, "NXM_OF_IP_TOS",
+        OFPUTIL_P_ANY,   /* Will be shifted for OXM. */
+        OFPUTIL_P_NONE,
     }, {
         MFF_IP_DSCP_SHIFTED, "nw_tos_shifted", NULL,
         MF_FIELD_SIZES(u8),
@@ -378,6 +438,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP",
         OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP",
+        OFPUTIL_P_ANY,   /* Will be shifted for non-OXM. */
+        OFPUTIL_P_NONE,
     }, {
         MFF_IP_ECN, "nw_ecn", NULL,
         1, 2,
@@ -387,6 +449,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_NX_IP_ECN, "NXM_NX_IP_ECN",
         OXM_OF_IP_ECN, "OXM_OF_IP_ECN",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
     }, {
         MFF_IP_TTL, "nw_ttl", NULL,
         MF_FIELD_SIZES(u8),
@@ -396,6 +460,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_NX_IP_TTL, "NXM_NX_IP_TTL",
         NXM_NX_IP_TTL, "NXM_NX_IP_TTL",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
     }, {
         MFF_IP_FRAG, "ip_frag", NULL,
         1, 2,
@@ -405,6 +471,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_IP_FRAG, "NXM_NX_IP_FRAG",
         NXM_NX_IP_FRAG, "NXM_NX_IP_FRAG",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     },
 
     {
@@ -416,6 +484,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_OF_ARP_OP, "NXM_OF_ARP_OP",
         OXM_OF_ARP_OP, "OXM_OF_ARP_OP",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NONE,
     }, {
         MFF_ARP_SPA, "arp_spa", NULL,
         MF_FIELD_SIZES(be32),
@@ -425,6 +495,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_OF_ARP_SPA, "NXM_OF_ARP_SPA",
         OXM_OF_ARP_SPA, "OXM_OF_ARP_SPA",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OF11_UP,
     }, {
         MFF_ARP_TPA, "arp_tpa", NULL,
         MF_FIELD_SIZES(be32),
@@ -434,6 +506,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_OF_ARP_TPA, "NXM_OF_ARP_TPA",
         OXM_OF_ARP_TPA, "OXM_OF_ARP_TPA",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OF11_UP,
     }, {
         MFF_ARP_SHA, "arp_sha", NULL,
         MF_FIELD_SIZES(mac),
@@ -443,6 +517,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_ARP_SHA, "NXM_NX_ARP_SHA",
         OXM_OF_ARP_SHA, "OXM_OF_ARP_SHA",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_ARP_THA, "arp_tha", NULL,
         MF_FIELD_SIZES(mac),
@@ -452,6 +528,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_ARP_THA, "NXM_NX_ARP_THA",
         OXM_OF_ARP_THA, "OXM_OF_ARP_THA",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     },
 
     /* ## -- ## */
@@ -467,6 +545,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_TCP_SRC, "NXM_OF_TCP_SRC",
         OXM_OF_TCP_SRC, "OXM_OF_TCP_SRC",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_TCP_DST, "tcp_dst", "tp_dst",
         MF_FIELD_SIZES(be16),
@@ -476,6 +556,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_TCP_DST, "NXM_OF_TCP_DST",
         OXM_OF_TCP_DST, "OXM_OF_TCP_DST",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     },
 
     {
@@ -487,6 +569,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_UDP_SRC, "NXM_OF_UDP_SRC",
         OXM_OF_UDP_SRC, "OXM_OF_UDP_SRC",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_UDP_DST, "udp_dst", NULL,
         MF_FIELD_SIZES(be16),
@@ -496,6 +580,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         true,
         NXM_OF_UDP_DST, "NXM_OF_UDP_DST",
         OXM_OF_UDP_DST, "OXM_OF_UDP_DST",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     },
 
     {
@@ -507,6 +593,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_OF_ICMP_TYPE, "NXM_OF_ICMP_TYPE",
         OXM_OF_ICMPV4_TYPE, "OXM_OF_ICMPV4_TYPE",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NONE,
     }, {
         MFF_ICMPV4_CODE, "icmp_code", NULL,
         MF_FIELD_SIZES(u8),
@@ -516,6 +604,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_OF_ICMP_CODE, "NXM_OF_ICMP_CODE",
         OXM_OF_ICMPV4_CODE, "OXM_OF_ICMPV4_CODE",
+        OFPUTIL_P_ANY,
+        OFPUTIL_P_NONE,
     },
 
     {
@@ -527,6 +617,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_ICMPV6_TYPE, "NXM_NX_ICMPV6_TYPE",
         OXM_OF_ICMPV6_TYPE, "OXM_OF_ICMPV6_TYPE",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
     }, {
         MFF_ICMPV6_CODE, "icmpv6_code", NULL,
         MF_FIELD_SIZES(u8),
@@ -536,6 +628,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_ICMPV6_CODE, "NXM_NX_ICMPV6_CODE",
         OXM_OF_ICMPV6_CODE, "OXM_OF_ICMPV6_CODE",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
     },
 
     /* ## ---- ## */
@@ -551,6 +645,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_ND_TARGET, "NXM_NX_ND_TARGET",
         OXM_OF_IPV6_ND_TARGET, "OXM_OF_IPV6_ND_TARGET",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_ND_SLL, "nd_sll", NULL,
         MF_FIELD_SIZES(mac),
@@ -560,6 +656,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_ND_SLL, "NXM_NX_ND_SLL",
         OXM_OF_IPV6_ND_SLL, "OXM_OF_IPV6_ND_SLL",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }, {
         MFF_ND_TLL, "nd_tll", NULL,
         MF_FIELD_SIZES(mac),
@@ -569,6 +667,8 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         false,
         NXM_NX_ND_TLL, "NXM_NX_ND_TLL",
         OXM_OF_IPV6_ND_TLL, "OXM_OF_IPV6_ND_TLL",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NXM_OXM_ANY,
     }
 };
 
@@ -1759,17 +1859,17 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
  *
  * 'mask' must be a valid mask for 'mf' (see mf_is_mask_valid()).  The caller
  * is responsible for ensuring that 'match' meets 'mf''s prerequisites. */
-void
+enum ofputil_protocol
 mf_set(const struct mf_field *mf,
        const union mf_value *value, const union mf_value *mask,
        struct match *match)
 {
     if (!mask || is_all_ones((const uint8_t *) mask, mf->n_bytes)) {
         mf_set_value(mf, value, match);
-        return;
+        return mf->usable_protocols;
     } else if (is_all_zeros((const uint8_t *) mask, mf->n_bytes)) {
         mf_set_wild(mf, match);
-        return;
+        return OFPUTIL_P_ANY;
     }
 
     switch (mf->id) {
@@ -1852,11 +1952,11 @@ mf_set(const struct mf_field *mf,
 
     case MFF_IPV4_SRC:
         match_set_nw_src_masked(match, value->be32, mask->be32);
-        break;
+        goto cidr_check;
 
     case MFF_IPV4_DST:
         match_set_nw_dst_masked(match, value->be32, mask->be32);
-        break;
+        goto cidr_check;
 
     case MFF_IPV6_SRC:
         match_set_ipv6_src_masked(match, &value->ipv6, &mask->ipv6);
@@ -1884,11 +1984,11 @@ mf_set(const struct mf_field *mf,
 
     case MFF_ARP_SPA:
         match_set_nw_src_masked(match, value->be32, mask->be32);
-        break;
+        goto cidr_check;
 
     case MFF_ARP_TPA:
         match_set_nw_dst_masked(match, value->be32, mask->be32);
-        break;
+        goto cidr_check;
 
     case MFF_TCP_SRC:
     case MFF_UDP_SRC:
@@ -1904,6 +2004,12 @@ mf_set(const struct mf_field *mf,
     default:
         NOT_REACHED();
     }
+
+    return mf->usable_protocols_bitwise;
+
+cidr_check:
+    return ip_is_cidr(mask->be32) ? mf->usable_protocols :
+            mf->usable_protocols_bitwise;
 }
 
 static enum ofperr
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index a85a193..7dfd64a 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -22,6 +22,7 @@
 #include <netinet/ip6.h>
 #include "flow.h"
 #include "ofp-errors.h"
+#include "ofp-util.h"
 #include "packets.h"
 
 struct ds;
@@ -277,6 +278,17 @@ struct mf_field {
     const char *nxm_name;       /* The nxm_header constant's name. */
     uint32_t oxm_header;        /* An OXM_* (or NXM_*) constant. */
     const char *oxm_name;	    /* The oxm_header constant's name */
+
+    /* Usable protocols.
+     * NXM and OXM are extensible, allowing later extensions to be sent in
+     * earlier protocol versions, so this does not necessarily correspond to
+     * the OpenFlow protocol version the field was introduced in.
+     * Also, some field types are tranparently mapped to each other via the
+     * struct flow (like vlan and dscp/tos fields), so each variant supports
+     * all protocols. */
+    enum ofputil_protocol usable_protocols; /* If fully/cidr masked. */
+    /* If partially/non-cidr masked. */
+    enum ofputil_protocol usable_protocols_bitwise;
 };
 
 /* The representation of a field's value. */
@@ -340,9 +352,12 @@ bool mf_is_zero(const struct mf_field *, const struct flow *);
 
 void mf_get(const struct mf_field *, const struct match *,
             union mf_value *value, union mf_value *mask);
-void mf_set(const struct mf_field *,
-            const union mf_value *value, const union mf_value *mask,
-            struct match *);
+
+/* Returns the set of usable protocols. */
+enum ofputil_protocol mf_set(const struct mf_field *,
+                             const union mf_value *value,
+                             const union mf_value *mask,
+                             struct match *);
 
 void mf_set_wild(const struct mf_field *, struct match *);
 
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 8f80758..9bf6a97 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -31,6 +31,13 @@
 
 VLOG_DEFINE_THIS_MODULE(ofp_actions);
 
+/* Array of usable protocols for each OFPACT */
+static const enum ofputil_protocol ofpact_usable_protocols[N_OFPACTS] = {
+#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER, PROTO) PROTO,
+    OFPACTS
+#undef DEFINE_OFPACT
+};
+
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
 /* Converting OpenFlow 1.0 to ofpacts. */
@@ -1253,17 +1260,23 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
  * May temporarily modify 'flow', but restores the changes before returning. */
 enum ofperr
 ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
-              struct flow *flow, ofp_port_t max_ports, uint8_t table_id)
+              struct flow *flow, ofp_port_t max_ports, uint8_t table_id,
+              enum ofputil_protocol *protocols)
 {
     const struct ofpact *a;
     ovs_be16 dl_type = flow->dl_type;
     enum ofperr error = 0;
+    enum ofputil_protocol usable_protocols = OFPUTIL_P_ANY;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         error = ofpact_check__(a, flow, max_ports, table_id);
         if (error) {
             break;
         }
+        usable_protocols &= ofpact_usable_protocols[a->type];
+    }
+    if (protocols) {
+        *protocols &= usable_protocols;
     }
     flow->dl_type = dl_type; /* Restore. */
     return error;
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index aacd30c..98b2226 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -47,65 +47,68 @@
  *
  *        - If "struct <STRUCT>" is variable-length, it must be the name of the
  *          flexible array member.
+ *
+ * 4. <PROTO>, which is a set of OFPUTIL_P_* values for protocols that
+ *    can carry this action.
  */
 #define OFPACTS                                                     \
     /* Output. */                                                   \
-    DEFINE_OFPACT(OUTPUT,          ofpact_output,        ofpact)    \
-    DEFINE_OFPACT(CONTROLLER,      ofpact_controller,    ofpact)    \
-    DEFINE_OFPACT(ENQUEUE,         ofpact_enqueue,       ofpact)    \
-    DEFINE_OFPACT(OUTPUT_REG,      ofpact_output_reg,    ofpact)    \
-    DEFINE_OFPACT(BUNDLE,          ofpact_bundle,        slaves)    \
+    DEFINE_OFPACT(OUTPUT,          ofpact_output,        ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(CONTROLLER,      ofpact_controller,    ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(ENQUEUE,         ofpact_enqueue,       ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(OUTPUT_REG,      ofpact_output_reg,    ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(BUNDLE,          ofpact_bundle,        slaves, OFPUTIL_P_ANY) \
                                                                     \
     /* Header changes. */                                           \
-    DEFINE_OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,      ofpact)    \
-    DEFINE_OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,      ofpact)    \
-    DEFINE_OFPACT(STRIP_VLAN,      ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(PUSH_VLAN,       ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(SET_ETH_SRC,     ofpact_mac,           ofpact)    \
-    DEFINE_OFPACT(SET_ETH_DST,     ofpact_mac,           ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_SRC,    ofpact_ipv4,          ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_DST,    ofpact_ipv4,          ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_DSCP,   ofpact_dscp,          ofpact)    \
-    DEFINE_OFPACT(SET_L4_SRC_PORT, ofpact_l4_port,       ofpact)    \
-    DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port,       ofpact)    \
-    DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact)    \
-    DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact)    \
-    DEFINE_OFPACT(STACK_PUSH,      ofpact_stack,         ofpact)    \
-    DEFINE_OFPACT(STACK_POP,       ofpact_stack,         ofpact)    \
-    DEFINE_OFPACT(DEC_TTL,         ofpact_cnt_ids,       cnt_ids)   \
-    DEFINE_OFPACT(SET_MPLS_TTL,    ofpact_mpls_ttl,      ofpact)    \
-    DEFINE_OFPACT(DEC_MPLS_TTL,    ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(PUSH_MPLS,       ofpact_push_mpls,     ofpact)    \
-    DEFINE_OFPACT(POP_MPLS,        ofpact_pop_mpls,      ofpact)    \
+    DEFINE_OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,      ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,      ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(STRIP_VLAN,      ofpact_null,          ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(PUSH_VLAN,       ofpact_null,          ofpact, OFPUTIL_P_OF11_UP) \
+    DEFINE_OFPACT(SET_ETH_SRC,     ofpact_mac,           ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_ETH_DST,     ofpact_mac,           ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_IPV4_SRC,    ofpact_ipv4,          ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_IPV4_DST,    ofpact_ipv4,          ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_IPV4_DSCP,   ofpact_dscp,          ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_L4_SRC_PORT, ofpact_l4_port,       ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port,       ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(STACK_PUSH,      ofpact_stack,         ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(STACK_POP,       ofpact_stack,         ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(DEC_TTL,         ofpact_cnt_ids,       cnt_ids, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_MPLS_TTL,    ofpact_mpls_ttl,      ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(DEC_MPLS_TTL,    ofpact_null,          ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(PUSH_MPLS,       ofpact_push_mpls,     ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(POP_MPLS,        ofpact_pop_mpls,      ofpact, OFPUTIL_P_ANY) \
                                                                     \
     /* Metadata. */                                                 \
-    DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
-    DEFINE_OFPACT(SET_QUEUE,       ofpact_queue,         ofpact)    \
-    DEFINE_OFPACT(POP_QUEUE,       ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout,   ofpact)    \
+    DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SET_QUEUE,       ofpact_queue,         ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(POP_QUEUE,       ofpact_null,          ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout,   ofpact, OFPUTIL_P_ANY) \
                                                                     \
     /* Flow table interaction. */                                   \
-    DEFINE_OFPACT(RESUBMIT,        ofpact_resubmit,      ofpact)    \
-    DEFINE_OFPACT(LEARN,           ofpact_learn,         specs)     \
+    DEFINE_OFPACT(RESUBMIT,        ofpact_resubmit,      ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(LEARN,           ofpact_learn,         specs,  OFPUTIL_P_ANY) \
                                                                     \
     /* Arithmetic. */                                               \
-    DEFINE_OFPACT(MULTIPATH,       ofpact_multipath,     ofpact)    \
+    DEFINE_OFPACT(MULTIPATH,       ofpact_multipath,     ofpact, OFPUTIL_P_ANY) \
                                                                     \
     /* Other. */                                                    \
-    DEFINE_OFPACT(NOTE,            ofpact_note,          data)      \
-    DEFINE_OFPACT(EXIT,            ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(SAMPLE,          ofpact_sample,        ofpact)    \
+    DEFINE_OFPACT(NOTE,            ofpact_note,          data,   OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(EXIT,            ofpact_null,          ofpact, OFPUTIL_P_ANY) \
+    DEFINE_OFPACT(SAMPLE,          ofpact_sample,        ofpact, OFPUTIL_P_ANY) \
                                                                     \
     /* Instructions */                                              \
-    DEFINE_OFPACT(METER,           ofpact_meter,         ofpact)    \
+    DEFINE_OFPACT(METER,           ofpact_meter,         ofpact, OFPUTIL_P_OF13_UP) \
     /* XXX Write-Actions */                                         \
-    DEFINE_OFPACT(CLEAR_ACTIONS,   ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(WRITE_METADATA,  ofpact_metadata,      ofpact)    \
-    DEFINE_OFPACT(GOTO_TABLE,      ofpact_goto_table,    ofpact)
+    DEFINE_OFPACT(CLEAR_ACTIONS,   ofpact_null,          ofpact, OFPUTIL_P_OF11_UP) \
+    DEFINE_OFPACT(WRITE_METADATA,  ofpact_metadata,      ofpact, OFPUTIL_P_ANY)    \
+    DEFINE_OFPACT(GOTO_TABLE,      ofpact_goto_table,    ofpact, OFPUTIL_P_OF11_UP)
 
 /* enum ofpact_type, with a member OFPACT_<ENUM> for each action. */
 enum OVS_PACKED_ENUM ofpact_type {
-#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) OFPACT_##ENUM,
+#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER, PROTO) OFPACT_##ENUM,
     OFPACTS
 #undef DEFINE_OFPACT
 };
@@ -113,7 +116,7 @@ enum OVS_PACKED_ENUM ofpact_type {
 /* N_OFPACTS, the number of values of "enum ofpact_type". */
 enum {
     N_OFPACTS =
-#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) + 1
+#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER, PROTO) + 1
     OFPACTS
 #undef DEFINE_OFPACT
 };
@@ -502,7 +505,8 @@ enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
                                                  struct ofpbuf *ofpacts);
 enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len,
                           struct flow *, ofp_port_t max_ports,
-                          uint8_t table_id);
+                          uint8_t table_id,
+                          enum ofputil_protocol *usable_protocols);
 enum ofperr ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len);
 
 /* Converting ofpacts to OpenFlow. */
@@ -567,7 +571,7 @@ void *ofpact_put(struct ofpbuf *, enum ofpact_type, size_t len);
  *     An integer constant, the value of OFPACT_<ENUM>_RAW_SIZE rounded up to a
  *     multiple of OFPACT_ALIGNTO.
  */
-#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER)                             \
+#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER, PROTO)                      \
     BUILD_ASSERT_DECL(offsetof(struct STRUCT, ofpact) == 0);            \
                                                                         \
     enum { OFPACT_##ENUM##_RAW_SIZE                                     \
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 089df6d..1024b80 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -826,7 +826,7 @@ ofp_fatal(const char *flow, bool verbose, const char *format, ...)
     ovs_fatal_valist(0, format, args);
 }
 
-static void
+static enum ofputil_protocol
 parse_field(const struct mf_field *mf, const char *s, struct match *match)
 {
     union mf_value value, mask;
@@ -837,7 +837,7 @@ parse_field(const struct mf_field *mf, const char *s, struct match *match)
         ovs_fatal(0, "%s", error);
     }
 
-    mf_set(mf, &value, &mask, match);
+    return mf_set(mf, &value, &mask, match);
 }
 
 /* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
@@ -847,11 +847,15 @@ parse_field(const struct mf_field *mf, const char *s, struct match *match)
  *
  * To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_*
  * constant for 'command'.  To parse syntax for an OFPST_FLOW or
- * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'. */
-void
+ * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'.
+ *
+ * Returns a set of protocols that can be used to communicate the 'fm' to an
+ * OpenFlow switch. */
+enum ofputil_protocol
 parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
               bool verbose)
 {
+    enum ofputil_protocol usable_protocols = OFPUTIL_P_ANY;
     enum {
         F_OUT_PORT = 1 << 0,
         F_ACTIONS = 1 << 1,
@@ -939,10 +943,13 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
             fm->flags |= OFPFF_CHECK_OVERLAP;
         } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) {
             fm->flags |= OFPFF12_RESET_COUNTS;
+            usable_protocols &= OFPUTIL_P_OF12_UP;
         } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) {
             fm->flags |= OFPFF13_NO_PKT_COUNTS;
+            usable_protocols &= OFPUTIL_P_OF13_UP;
         } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
             fm->flags |= OFPFF13_NO_BYT_COUNTS;
+            usable_protocols &= OFPUTIL_P_OF13_UP;
         } else {
             char *value;
 
@@ -953,6 +960,9 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
 
             if (!strcmp(name, "table")) {
                 fm->table_id = str_to_u8(value, name);
+                if (fm->table_id != 0xff) {
+                    usable_protocols &= OFPUTIL_P_TID;
+                }
             } else if (!strcmp(name, "out_port")) {
                 if (!ofputil_port_from_string(value, &fm->out_port)) {
                     ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port",
@@ -976,6 +986,12 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
                     *mask = '\0';
                     fm->cookie = htonll(str_to_u64(value));
                     fm->cookie_mask = htonll(str_to_u64(mask+1));
+
+                    /* Matching of the cookie is only supported through NXM or
+                     * OF1.1+. */
+                    if (fm->cookie_mask != htonll(0)) {
+                        usable_protocols &= OFPUTIL_P_NXM_OF11_UP;
+                    }
                 } else {
                     /* No mask means that the cookie is being set. */
                     if (command != OFPFC_ADD && command != OFPFC_MODIFY
@@ -985,7 +1001,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
                     fm->new_cookie = htonll(str_to_u64(value));
                 }
             } else if (mf_from_name(name)) {
-                parse_field(mf_from_name(name), value, &fm->match);
+                usable_protocols &= parse_field(mf_from_name(name), value, &fm->match);
             } else if (!strcmp(name, "duration")
                        || !strcmp(name, "n_packets")
                        || !strcmp(name, "n_bytes")
@@ -1016,17 +1032,18 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
         fm->ofpacts = ofpbuf_steal_data(&ofpacts);
 
         err = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
-                            OFPP_MAX, 0);
+                            OFPP_MAX, 0, &usable_protocols);
         if (err) {
             exit(EXIT_FAILURE);
         }
-
     } else {
         fm->ofpacts_len = 0;
         fm->ofpacts = NULL;
     }
 
     free(string);
+
+    return usable_protocols;
 }
 
 /* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
@@ -1298,25 +1315,30 @@ parse_ofpacts(const char *s_, struct ofpbuf *ofpacts)
 
 /* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command'
  * (one of OFPFC_*) into 'fm'. */
-void
+enum ofputil_protocol
 parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
                        uint16_t command, bool verbose)
 {
+    enum ofputil_protocol usable_protocols;
+
     struct match match_copy;
 
-    parse_ofp_str(fm, command, string, verbose);
+    usable_protocols = parse_ofp_str(fm, command, string, verbose);
 
     /* Normalize a copy of the match.  This ensures that non-normalized flows
      * get logged but doesn't affect what gets sent to the switch, so that the
      * switch can do whatever it likes with the flow. */
     match_copy = fm->match;
     ofputil_normalize_match(&match_copy);
+
+    return usable_protocols;
 }
 
-void
+enum ofputil_protocol
 parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
                         struct ofputil_flow_mod **fms, size_t *n_fms)
 {
+    enum ofputil_protocol usable_protocols = OFPUTIL_P_ANY;
     size_t allocated_fms;
     FILE *stream;
     struct ds s;
@@ -1332,7 +1354,8 @@ parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
         if (*n_fms >= allocated_fms) {
             *fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms);
         }
-        parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command, false);
+        usable_protocols &= parse_ofp_flow_mod_str(&(*fms)[*n_fms],
+                                                   ds_cstr(&s), command, false);
         *n_fms += 1;
     }
     ds_destroy(&s);
@@ -1340,21 +1363,33 @@ parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
     if (stream != stdin) {
         fclose(stream);
     }
+    return usable_protocols;
 }
 
-void
+enum ofputil_protocol
 parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
                                  bool aggregate, const char *string)
 {
+    enum ofputil_protocol usable_protocols;
     struct ofputil_flow_mod fm;
 
-    parse_ofp_str(&fm, -1, string, false);
+    usable_protocols = parse_ofp_str(&fm, -1, string, false);
+    /* Special table ID support not required for stats requests. */
+    if (usable_protocols & OFPUTIL_P_OF10_STD_TID) {
+        usable_protocols |= OFPUTIL_P_OF10_STD;
+    }
+    if (usable_protocols & OFPUTIL_P_OF10_NXM_TID) {
+        usable_protocols |= OFPUTIL_P_OF10_NXM;
+    }
+
     fsr->aggregate = aggregate;
     fsr->cookie = fm.cookie;
     fsr->cookie_mask = fm.cookie_mask;
     fsr->match = fm.match;
     fsr->out_port = fm.out_port;
     fsr->table_id = fm.table_id;
+
+    return usable_protocols;
 }
 
 /* Parses a specification of a flow from 's' into 'flow'.  's' must take the
diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
index 6ee25a4..bb8d4ae 100644
--- a/lib/ofp-parse.h
+++ b/lib/ofp-parse.h
@@ -30,16 +30,20 @@ struct ofputil_flow_monitor_request;
 struct ofputil_flow_stats_request;
 struct ofputil_meter_mod;
 
-void parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_,
-                   bool verbose);
+enum ofputil_protocol parse_ofp_str(struct ofputil_flow_mod *, int command,
+                                    const char *str_, bool verbose);
 
-void parse_ofp_flow_mod_str(struct ofputil_flow_mod *, const char *string,
-                            uint16_t command, bool verbose);
-void parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
-                             struct ofputil_flow_mod **fms, size_t *n_fms);
+enum ofputil_protocol parse_ofp_flow_mod_str(struct ofputil_flow_mod *,
+                                             const char *string,
+                                             uint16_t command, bool verbose);
+enum ofputil_protocol parse_ofp_flow_mod_file(const char *file_name,
+                                              uint16_t command,
+                                              struct ofputil_flow_mod **fms,
+                                              size_t *n_fms);
 
-void parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *,
-                                      bool aggregate, const char *string);
+enum ofputil_protocol parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *,
+                                                       bool aggregate,
+                                                       const char *string);
 
 
 void parse_ofpacts(const char *, struct ofpbuf *ofpacts);
@@ -47,7 +51,7 @@ void parse_ofpacts(const char *, struct ofpbuf *ofpacts);
 char *parse_ofp_exact_flow(struct flow *, const char *);
 
 void parse_ofp_meter_mod_str(struct ofputil_meter_mod *, const char *string,
-			      int command, bool verbose);
+                             int command, bool verbose);
 
 void parse_flow_monitor_request(struct ofputil_flow_monitor_request *,
                                 const char *);
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 53ee7ff..c691e2a 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -1026,144 +1026,6 @@ ofputil_packet_in_format_from_string(const char *s)
             : -1);
 }
 
-static bool
-regs_fully_wildcarded(const struct flow_wildcards *wc)
-{
-    int i;
-
-    for (i = 0; i < FLOW_N_REGS; i++) {
-        if (wc->masks.regs[i] != 0) {
-            return false;
-        }
-    }
-    return true;
-}
-
-/* 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
- * use OpenFlow 1.0 protocol for backward compatibility. */
-enum ofputil_protocol
-ofputil_usable_protocols(const struct match *match)
-{
-    const struct flow_wildcards *wc = &match->wc;
-
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
-
-    /* These tunnel params can't be sent in a flow_mod */
-    if (wc->masks.tunnel.ip_ttl
-        || wc->masks.tunnel.ip_tos || wc->masks.tunnel.flags) {
-        return OFPUTIL_P_NONE;
-    }
-
-    /* skb_mark and skb_priority can't be sent in a flow_mod */
-    if (wc->masks.skb_mark || wc->masks.skb_priority) {
-        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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-    if (!eth_mask_is_exact(wc->masks.dl_dst)
-        && !eth_addr_is_zero(wc->masks.dl_dst)) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM, OXM, and OF1.1+ support matching metadata. */
-    if (wc->masks.metadata != htonll(0)) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* 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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OXM support matching registers. */
-    if (!regs_fully_wildcarded(wc)) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OXM support matching tun_id, tun_src, and tun_dst. */
-    if (wc->masks.tunnel.tun_id != htonll(0)
-        || wc->masks.tunnel.ip_src != htonl(0)
-        || wc->masks.tunnel.ip_dst != htonl(0)) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OXM support matching fragments. */
-    if (wc->masks.nw_frag) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OXM support matching IPv6. */
-    if (!ipv6_mask_is_any(&wc->masks.ipv6_src) ||
-        !ipv6_mask_is_any(&wc->masks.ipv6_dst) ||
-        !ipv6_mask_is_any(&wc->masks.nd_target) ||
-        wc->masks.ipv6_label) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OXM support matching IP ECN bits. */
-    if (wc->masks.nw_tos & IP_ECN_MASK) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OXM support matching IP TTL/hop limit. */
-    if (wc->masks.nw_ttl) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* 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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* 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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OF1.1+ support matching MPLS label */
-    if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OF1.1+ support matching MPLS TC */
-    if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* NXM and OF1.3+ support matching MPLS stack flag */
-    /* Allow for OF1.2 as there doesn't seem to be a
-     * particularly good reason not to */
-    if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
-        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-
-    /* Other formats can express this rule. */
-    return OFPUTIL_P_ANY;
-}
-
 void
 ofputil_format_version(struct ds *msg, enum ofp_version version)
 {
@@ -2086,37 +1948,6 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
     return msg;
 }
 
-/* Returns a bitmask with a 1-bit for each protocol that could be used to
- * send all of the 'n_fm's flow table modification requests in 'fms', and a
- * 0-bit for each protocol that is inadequate.
- *
- * (The return value will have at least one 1-bit.) */
-enum ofputil_protocol
-ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
-                                  size_t n_fms)
-{
-    enum ofputil_protocol usable_protocols;
-    size_t i;
-
-    usable_protocols = OFPUTIL_P_ANY;
-    for (i = 0; i < n_fms; i++) {
-        const struct ofputil_flow_mod *fm = &fms[i];
-
-        usable_protocols &= ofputil_usable_protocols(&fm->match);
-        if (fm->table_id != 0xff) {
-            usable_protocols &= OFPUTIL_P_TID;
-        }
-
-        /* Matching of the cookie is only supported through NXM or OF1.1+. */
-        if (fm->cookie_mask != htonll(0)) {
-            usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-                | OFPUTIL_P_OF13_OXM;
-        }
-    }
-
-    return usable_protocols;
-}
-
 static enum ofperr
 ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr,
                                     const struct ofp10_flow_stats_request *ofsr,
@@ -2291,24 +2122,6 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
     return msg;
 }
 
-/* Returns a bitmask with a 1-bit for each protocol that could be used to
- * accurately encode 'fsr', and a 0-bit for each protocol that is inadequate.
- *
- * (The return value will have at least one 1-bit.) */
-enum ofputil_protocol
-ofputil_flow_stats_request_usable_protocols(
-    const struct ofputil_flow_stats_request *fsr)
-{
-    enum ofputil_protocol usable_protocols;
-
-    usable_protocols = ofputil_usable_protocols(&fsr->match);
-    if (fsr->cookie_mask != htonll(0)) {
-        usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
-            | OFPUTIL_P_OF13_OXM;
-    }
-    return usable_protocols;
-}
-
 /* Converts an OFPST_FLOW or NXST_FLOW reply in 'msg' into an abstract
  * ofputil_flow_stats in 'fs'.
  *
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 57d35c4..bef8c56 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -92,6 +92,16 @@ enum ofputil_protocol {
     OFPUTIL_P_OF13_OXM      = 1 << 5,
 #define OFPUTIL_P_ANY_OXM (OFPUTIL_P_OF12_OXM | OFPUTIL_P_OF13_OXM)
 
+#define OFPUTIL_P_NXM_OF11_UP (OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_ANY_OXM)
+
+#define OFPUTIL_P_NXM_OXM_ANY (OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_ANY_OXM)
+
+#define OFPUTIL_P_OF11_UP (OFPUTIL_P_ANY_OXM)
+
+#define OFPUTIL_P_OF12_UP (OFPUTIL_P_ANY_OXM)
+
+#define OFPUTIL_P_OF13_UP (OFPUTIL_P_OF13_OXM)
+
     /* All protocols. */
 #define OFPUTIL_P_ANY ((1 << 6) - 1)
 
@@ -119,7 +129,6 @@ enum ofputil_protocol ofputil_protocol_set_base(
 const char *ofputil_protocol_to_string(enum ofputil_protocol);
 char *ofputil_protocols_to_string(enum ofputil_protocol);
 enum ofputil_protocol ofputil_protocols_from_string(const char *);
-enum ofputil_protocol ofputil_usable_protocols(const struct match *);
 
 void ofputil_format_version(struct ds *, enum ofp_version);
 void ofputil_format_version_name(struct ds *, enum ofp_version);
@@ -236,9 +245,6 @@ enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *,
 struct ofpbuf *ofputil_encode_flow_mod(const struct ofputil_flow_mod *,
                                        enum ofputil_protocol);
 
-enum ofputil_protocol ofputil_flow_mod_usable_protocols(
-    const struct ofputil_flow_mod *fms, size_t n_fms);
-
 /* Flow stats or aggregate stats request, independent of protocol. */
 struct ofputil_flow_stats_request {
     bool aggregate;             /* Aggregate results? */
@@ -253,8 +259,6 @@ enum ofperr ofputil_decode_flow_stats_request(
     struct ofputil_flow_stats_request *, const struct ofp_header *);
 struct ofpbuf *ofputil_encode_flow_stats_request(
     const struct ofputil_flow_stats_request *, enum ofputil_protocol);
-enum ofputil_protocol ofputil_flow_stats_request_usable_protocols(
-    const struct ofputil_flow_stats_request *);
 
 /* Flow stats reply, independent of protocol. */
 struct ofputil_flow_stats {
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index aa360a8..0dc53c9 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2415,7 +2415,8 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
     /* Verify actions against packet, then send packet if successful. */
     in_port_.ofp_port = po.in_port;
     flow_extract(payload, 0, 0, NULL, &in_port_, &flow);
-    error = ofpacts_check(po.ofpacts, po.ofpacts_len, &flow, p->max_ports, 0);
+    error = ofpacts_check(po.ofpacts, po.ofpacts_len, &flow, p->max_ports, 0,
+                          NULL);
     if (!error) {
         error = p->ofproto_class->packet_out(p, payload, &flow,
                                              po.ofpacts, po.ofpacts_len);
@@ -3266,7 +3267,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
 
     /* Verify actions. */
     error = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
-                          ofproto->max_ports, table_id);
+                          ofproto->max_ports, table_id, NULL);
     if (error) {
         return error;
     }
@@ -3403,7 +3404,7 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
 
         /* Verify actions. */
         error = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
-                              ofproto->max_ports, rule->table_id);
+                              ofproto->max_ports, rule->table_id, NULL);
         if (error) {
             return error;
         }
diff --git a/utilities/ovs-controller.c b/utilities/ovs-controller.c
index 70bc2e6..f947126 100644
--- a/utilities/ovs-controller.c
+++ b/utilities/ovs-controller.c
@@ -83,6 +83,7 @@ static struct simap port_queues = SIMAP_INITIALIZER(&port_queues);
 /* --with-flows: Flows to send to switch. */
 static struct ofputil_flow_mod *default_flows;
 static size_t n_default_flows;
+static enum ofputil_protocol usable_protocols;
 
 /* --unixctl: Name of unixctl socket, or null to use the default. */
 static char *unixctl_path = NULL;
@@ -216,6 +217,7 @@ new_switch(struct switch_ *sw, struct vconn *vconn)
     cfg.max_idle = set_up_flows ? max_idle : -1;
     cfg.default_flows = default_flows;
     cfg.n_default_flows = n_default_flows;
+    cfg.usable_protocols = usable_protocols;
     cfg.default_queue = default_queue;
     cfg.port_queues = &port_queues;
     cfg.mute = mute;
@@ -327,8 +329,9 @@ parse_options(int argc, char *argv[])
             break;
 
         case OPT_WITH_FLOWS:
-            parse_ofp_flow_mod_file(optarg, OFPFC_ADD, &default_flows,
-                                    &n_default_flows);
+            usable_protocols = parse_ofp_flow_mod_file(optarg, OFPFC_ADD,
+                                                       &default_flows,
+                                                       &n_default_flows);
             break;
 
         case OPT_UNIXCTL:
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 2d6872b..2e5902e 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -867,9 +867,8 @@ prepare_dump_flows(int argc, char *argv[], bool aggregate,
     struct ofputil_flow_stats_request fsr;
     struct vconn *vconn;
 
-    parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "");
-    usable_protocols = ofputil_flow_stats_request_usable_protocols(&fsr);
-
+    usable_protocols = parse_ofp_flow_stats_request_str(&fsr, aggregate,
+                                                        argc > 2 ? argv[2] : "");
     protocol = open_vconn(argv[1], &vconn);
     protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
     *requestp = ofputil_encode_flow_stats_request(&fsr, protocol);
@@ -1023,17 +1022,13 @@ ofctl_queue_stats(int argc, char *argv[])
 }
 
 static enum ofputil_protocol
-open_vconn_for_flow_mod(const char *remote,
-                        const struct ofputil_flow_mod *fms, size_t n_fms,
-                        struct vconn **vconnp)
+open_vconn_for_flow_mod(const char *remote, struct vconn **vconnp,
+                        enum ofputil_protocol usable_protocols)
 {
-    enum ofputil_protocol usable_protocols;
     enum ofputil_protocol cur_protocol;
     char *usable_s;
     int i;
 
-    /* Figure out what flow formats will work. */
-    usable_protocols = ofputil_flow_mod_usable_protocols(fms, n_fms);
     if (!(usable_protocols & allowed_protocols)) {
         char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
         usable_s = ofputil_protocols_to_string(usable_protocols);
@@ -1065,13 +1060,13 @@ open_vconn_for_flow_mod(const char *remote,
 
 static void
 ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
-                 size_t n_fms)
+                 size_t n_fms, enum ofputil_protocol usable_protocols)
 {
     enum ofputil_protocol protocol;
     struct vconn *vconn;
     size_t i;
 
-    protocol = open_vconn_for_flow_mod(remote, fms, n_fms, &vconn);
+    protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
 
     for (i = 0; i < n_fms; i++) {
         struct ofputil_flow_mod *fm = &fms[i];
@@ -1085,23 +1080,27 @@ ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
 static void
 ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command)
 {
+    enum ofputil_protocol usable_protocols;
     struct ofputil_flow_mod *fms = NULL;
     size_t n_fms = 0;
 
-    parse_ofp_flow_mod_file(argv[2], command, &fms, &n_fms);
-    ofctl_flow_mod__(argv[1], fms, n_fms);
+    usable_protocols = parse_ofp_flow_mod_file(argv[2], command, &fms, &n_fms);
+    ofctl_flow_mod__(argv[1], fms, n_fms, usable_protocols);
     free(fms);
 }
 
 static void
 ofctl_flow_mod(int argc, char *argv[], uint16_t command)
 {
+    enum ofputil_protocol usable_protocols;
+
     if (argc > 2 && !strcmp(argv[2], "-")) {
         ofctl_flow_mod_file(argc, argv, command);
     } else {
         struct ofputil_flow_mod fm;
-        parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command, false);
-        ofctl_flow_mod__(argv[1], &fm, 1);
+        usable_protocols = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "",
+                                                  command, false);
+        ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols);
     }
 }
 
@@ -1919,7 +1918,7 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
         struct fte_version *version;
         struct ofputil_flow_mod fm;
 
-        parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), true);
+        usable_protocols &= parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), true);
 
         version = xmalloc(sizeof *version);
         version->cookie = fm.new_cookie;
@@ -1929,8 +1928,6 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
         version->ofpacts = fm.ofpacts;
         version->ofpacts_len = fm.ofpacts_len;
 
-        usable_protocols &= ofputil_usable_protocols(&fm.match);
-
         fte_insert(cls, &fm.match, fm.priority, version, index);
     }
     ds_destroy(&s);
@@ -2189,14 +2186,13 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[])
 /* Undocumented commands for unit testing. */
 
 static void
-ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms)
+ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms,
+                    enum ofputil_protocol usable_protocols)
 {
-    enum ofputil_protocol usable_protocols;
     enum ofputil_protocol protocol = 0;
     char *usable_s;
     size_t i;
 
-    usable_protocols = ofputil_flow_mod_usable_protocols(fms, n_fms);
     usable_s = ofputil_protocols_to_string(usable_protocols);
     printf("usable protocols: %s\n", usable_s);
     free(usable_s);
@@ -2231,10 +2227,11 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms)
 static void
 ofctl_parse_flow(int argc OVS_UNUSED, char *argv[])
 {
+    enum ofputil_protocol usable_protocols;
     struct ofputil_flow_mod fm;
 
-    parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, false);
-    ofctl_parse_flows__(&fm, 1);
+    usable_protocols = parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, false);
+    ofctl_parse_flows__(&fm, 1, usable_protocols);
 }
 
 /* "parse-flows FILENAME": reads the named file as a sequence of flows (like
@@ -2242,11 +2239,13 @@ ofctl_parse_flow(int argc OVS_UNUSED, char *argv[])
 static void
 ofctl_parse_flows(int argc OVS_UNUSED, char *argv[])
 {
+    enum ofputil_protocol usable_protocols;
     struct ofputil_flow_mod *fms = NULL;
     size_t n_fms = 0;
 
-    parse_ofp_flow_mod_file(argv[1], OFPFC_ADD, &fms, &n_fms);
-    ofctl_parse_flows__(fms, n_fms);
+    usable_protocols = parse_ofp_flow_mod_file(argv[1], OFPFC_ADD, &fms,
+                                               &n_fms);
+    ofctl_parse_flows__(fms, n_fms, usable_protocols);
     free(fms);
 }
 
@@ -2644,7 +2643,7 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
             struct flow flow;
             memset(&flow, 0, sizeof flow);
             error = ofpacts_check(ofpacts.data, ofpacts.size, &flow, OFPP_MAX,
-                                  table_id ? atoi(table_id) : 0);
+                                  table_id ? atoi(table_id) : 0, NULL);
         }
         if (error) {
             printf("bad OF1.1 instructions: %s\n\n", ofperr_get_name(error));
-- 
1.7.10.4




More information about the dev mailing list