Signed-off-by: Ben Pfaff <b...@nicira.com>
---
 lib/meta-flow.c       | 122 ++++++++++++++++++++++++++----------------------
 lib/meta-flow.h       |  13 +++++-
 lib/nx-match.c        | 125 ++++++++++++++++++++++++++++----------------------
 lib/nx-match.h        |   2 +-
 lib/ofp-actions.c     |   7 +--
 lib/ofp-util.c        |   9 ++--
 lib/ofp-util.h        |   2 +
 tests/ovs-ofctl.at    |   6 +--
 utilities/ovs-ofctl.c |  26 +++++++----
 9 files changed, 178 insertions(+), 134 deletions(-)

diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 6ef564e..5803ded 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         false,
         NXM_NX_DP_HASH, "NXM_NX_DP_HASH",
-        NXM_NX_DP_HASH, "NXM_NX_DP_HASH",
+        NXM_NX_DP_HASH, "NXM_NX_DP_HASH", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -71,7 +71,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         false,
         NXM_NX_RECIRC_ID, "NXM_NX_RECIRC_ID",
-        NXM_NX_RECIRC_ID, "NXM_NX_RECIRC_ID",
+        NXM_NX_RECIRC_ID, "NXM_NX_RECIRC_ID", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -83,7 +83,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_NX_TUN_ID, "NXM_NX_TUN_ID",
-        OXM_OF_TUNNEL_ID, "OXM_OF_TUNNEL_ID",
+        OXM_OF_TUNNEL_ID, "OXM_OF_TUNNEL_ID", OFP13_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         FLOW_U32OFS(tunnel.tun_id),
@@ -95,7 +95,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
-        NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
+        NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         FLOW_U32OFS(tunnel.ip_src),
@@ -107,7 +107,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
-        NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
+        NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         FLOW_U32OFS(tunnel.ip_dst),
@@ -119,7 +119,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         false,
         0, NULL,
-        0, NULL,
+        0, NULL, 0,
         OFPUTIL_P_NONE,
         OFPUTIL_P_NONE,
         -1,
@@ -131,7 +131,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         false,
         0, NULL,
-        0, NULL,
+        0, NULL, 0,
         OFPUTIL_P_NONE,
         OFPUTIL_P_NONE,
         -1,
@@ -143,7 +143,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         false,
         0, NULL,
-        0, NULL,
+        0, NULL, 0,
         OFPUTIL_P_NONE,
         OFPUTIL_P_NONE,
         -1,
@@ -155,7 +155,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         OXM_OF_METADATA, "OXM_OF_METADATA",
-        OXM_OF_METADATA, "OXM_OF_METADATA",
+        OXM_OF_METADATA, "OXM_OF_METADATA", OFP12_VERSION,
         OFPUTIL_P_NXM_OF11_UP,
         OFPUTIL_P_NXM_OF11_UP,
         -1,
@@ -167,7 +167,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_OF_IN_PORT, "NXM_OF_IN_PORT",
-        NXM_OF_IN_PORT, "NXM_OF_IN_PORT",
+        NXM_OF_IN_PORT, "NXM_OF_IN_PORT", 0,
         OFPUTIL_P_ANY,   /* OF11+ via mapping to 32 bits. */
         OFPUTIL_P_NONE,
         -1,
@@ -179,7 +179,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         OXM_OF_IN_PORT, "OXM_OF_IN_PORT",
-        OXM_OF_IN_PORT, "OXM_OF_IN_PORT",
+        OXM_OF_IN_PORT, "OXM_OF_IN_PORT", OFP12_VERSION,
         OFPUTIL_P_OF11_UP,
         OFPUTIL_P_NONE,
         -1,
@@ -191,7 +191,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         false,
         0, NULL,
-        0, NULL,
+        0, NULL, 0,
         OFPUTIL_P_NONE,
         OFPUTIL_P_NONE,
         -1,
@@ -203,7 +203,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_NX_PKT_MARK, "NXM_NX_PKT_MARK",
-        NXM_NX_PKT_MARK, "NXM_NX_PKT_MARK",
+        NXM_NX_PKT_MARK, "NXM_NX_PKT_MARK", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -218,7 +218,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,                               \
         true,                                   \
         NXM_NX_REG(IDX), "NXM_NX_REG" #IDX,     \
-        NXM_NX_REG(IDX), "NXM_NX_REG" #IDX,     \
+        NXM_NX_REG(IDX), "NXM_NX_REG" #IDX, 0,  \
         OFPUTIL_P_NXM_OXM_ANY,                  \
         OFPUTIL_P_NXM_OXM_ANY,                  \
         -1,                                     \
@@ -263,7 +263,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_OF_ETH_SRC, "NXM_OF_ETH_SRC",
-        OXM_OF_ETH_SRC, "OXM_OF_ETH_SRC",
+        OXM_OF_ETH_SRC, "OXM_OF_ETH_SRC", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
         -1,
@@ -275,7 +275,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_OF_ETH_DST, "NXM_OF_ETH_DST",
-        OXM_OF_ETH_DST, "OXM_OF_ETH_DST",
+        OXM_OF_ETH_DST, "OXM_OF_ETH_DST", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
         -1,
@@ -287,7 +287,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         false,
         NXM_OF_ETH_TYPE, "NXM_OF_ETH_TYPE",
-        OXM_OF_ETH_TYPE, "OXM_OF_ETH_TYPE",
+        OXM_OF_ETH_TYPE, "OXM_OF_ETH_TYPE", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -301,7 +301,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
-        NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
+        NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI", 0,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -313,7 +313,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         0, NULL,
-        0, NULL,
+        0, NULL, 0,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -325,7 +325,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
-        OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
+        OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -337,7 +337,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_NONE,
         true,
         0, NULL,
-        0, NULL,
+        0, NULL, 0,
         OFPUTIL_P_ANY,   /* Will be mapped to NXM and OXM. */
         OFPUTIL_P_NONE,
         -1,
@@ -349,7 +349,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_VLAN_VID,
         true,
         OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
-        OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
+        OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP", OFP12_VERSION,
         OFPUTIL_P_ANY,   /* Will be mapped to OF10 and NXM. */
         OFPUTIL_P_NONE,
         -1,
@@ -366,7 +366,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_MPLS,
         true,
         OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
-        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
+        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL", OFP12_VERSION,
         OFPUTIL_P_NXM_OF11_UP,
         OFPUTIL_P_NONE,
         -1,
@@ -378,7 +378,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_MPLS,
         true,
         OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
-        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
+        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC", OFP12_VERSION,
         OFPUTIL_P_NXM_OF11_UP,
         OFPUTIL_P_NONE,
         -1,
@@ -390,7 +390,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_MPLS,
         false,
         OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
-        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
+        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS", OFP13_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -408,7 +408,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IPV4,
         true,
         NXM_OF_IP_SRC, "NXM_OF_IP_SRC",
-        OXM_OF_IPV4_SRC, "OXM_OF_IPV4_SRC",
+        OXM_OF_IPV4_SRC, "OXM_OF_IPV4_SRC", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OF11_UP,
         FLOW_U32OFS(nw_src),
@@ -420,7 +420,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IPV4,
         true,
         NXM_OF_IP_DST, "NXM_OF_IP_DST",
-        OXM_OF_IPV4_DST, "OXM_OF_IPV4_DST",
+        OXM_OF_IPV4_DST, "OXM_OF_IPV4_DST", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OF11_UP,
         FLOW_U32OFS(nw_dst),
@@ -434,7 +434,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IPV6,
         true,
         NXM_NX_IPV6_SRC, "NXM_NX_IPV6_SRC",
-        OXM_OF_IPV6_SRC, "OXM_OF_IPV6_SRC",
+        OXM_OF_IPV6_SRC, "OXM_OF_IPV6_SRC", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         FLOW_U32OFS(ipv6_src),
@@ -446,7 +446,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IPV6,
         true,
         NXM_NX_IPV6_DST, "NXM_NX_IPV6_DST",
-        OXM_OF_IPV6_DST, "OXM_OF_IPV6_DST",
+        OXM_OF_IPV6_DST, "OXM_OF_IPV6_DST", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         FLOW_U32OFS(ipv6_dst),
@@ -459,7 +459,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IPV6,
         false,
         NXM_NX_IPV6_LABEL, "NXM_NX_IPV6_LABEL",
-        OXM_OF_IPV6_FLABEL, "OXM_OF_IPV6_FLABEL",
+        OXM_OF_IPV6_FLABEL, "OXM_OF_IPV6_FLABEL", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -473,7 +473,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IP_ANY,
         false,
         NXM_OF_IP_PROTO, "NXM_OF_IP_PROTO",
-        OXM_OF_IP_PROTO, "OXM_OF_IP_PROTO",
+        OXM_OF_IP_PROTO, "OXM_OF_IP_PROTO", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -485,7 +485,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IP_ANY,
         true,
         NXM_OF_IP_TOS, "NXM_OF_IP_TOS",
-        NXM_OF_IP_TOS, "NXM_OF_IP_TOS",
+        NXM_OF_IP_TOS, "NXM_OF_IP_TOS", 0,
         OFPUTIL_P_ANY,   /* Will be shifted for OXM. */
         OFPUTIL_P_NONE,
         -1,
@@ -497,7 +497,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IP_ANY,
         true,
         OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP",
-        OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP",
+        OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP", OFP12_VERSION,
         OFPUTIL_P_ANY,   /* Will be shifted for non-OXM. */
         OFPUTIL_P_NONE,
         -1,
@@ -509,7 +509,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IP_ANY,
         true,
         NXM_NX_IP_ECN, "NXM_NX_IP_ECN",
-        OXM_OF_IP_ECN, "OXM_OF_IP_ECN",
+        OXM_OF_IP_ECN, "OXM_OF_IP_ECN", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -521,7 +521,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IP_ANY,
         true,
         NXM_NX_IP_TTL, "NXM_NX_IP_TTL",
-        NXM_NX_IP_TTL, "NXM_NX_IP_TTL",
+        NXM_NX_IP_TTL, "NXM_NX_IP_TTL", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -533,7 +533,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_IP_ANY,
         false,
         NXM_NX_IP_FRAG, "NXM_NX_IP_FRAG",
-        NXM_NX_IP_FRAG, "NXM_NX_IP_FRAG",
+        NXM_NX_IP_FRAG, "NXM_NX_IP_FRAG", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -547,7 +547,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ARP,
         true,
         NXM_OF_ARP_OP, "NXM_OF_ARP_OP",
-        OXM_OF_ARP_OP, "OXM_OF_ARP_OP",
+        OXM_OF_ARP_OP, "OXM_OF_ARP_OP", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -559,7 +559,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ARP,
         true,
         NXM_OF_ARP_SPA, "NXM_OF_ARP_SPA",
-        OXM_OF_ARP_SPA, "OXM_OF_ARP_SPA",
+        OXM_OF_ARP_SPA, "OXM_OF_ARP_SPA", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OF11_UP,
         -1,
@@ -571,7 +571,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ARP,
         true,
         NXM_OF_ARP_TPA, "NXM_OF_ARP_TPA",
-        OXM_OF_ARP_TPA, "OXM_OF_ARP_TPA",
+        OXM_OF_ARP_TPA, "OXM_OF_ARP_TPA", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OF11_UP,
         -1,
@@ -583,7 +583,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ARP,
         true,
         NXM_NX_ARP_SHA, "NXM_NX_ARP_SHA",
-        OXM_OF_ARP_SHA, "OXM_OF_ARP_SHA",
+        OXM_OF_ARP_SHA, "OXM_OF_ARP_SHA", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -595,7 +595,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ARP,
         true,
         NXM_NX_ARP_THA, "NXM_NX_ARP_THA",
-        OXM_OF_ARP_THA, "OXM_OF_ARP_THA",
+        OXM_OF_ARP_THA, "OXM_OF_ARP_THA", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -613,7 +613,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_TCP,
         true,
         NXM_OF_TCP_SRC, "NXM_OF_TCP_SRC",
-        OXM_OF_TCP_SRC, "OXM_OF_TCP_SRC",
+        OXM_OF_TCP_SRC, "OXM_OF_TCP_SRC", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -625,7 +625,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_TCP,
         true,
         NXM_OF_TCP_DST, "NXM_OF_TCP_DST",
-        OXM_OF_TCP_DST, "OXM_OF_TCP_DST",
+        OXM_OF_TCP_DST, "OXM_OF_TCP_DST", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -637,7 +637,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_TCP,
         false,
         NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS",
-        NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS",
+        NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS", 0,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -651,7 +651,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_UDP,
         true,
         NXM_OF_UDP_SRC, "NXM_OF_UDP_SRC",
-        OXM_OF_UDP_SRC, "OXM_OF_UDP_SRC",
+        OXM_OF_UDP_SRC, "OXM_OF_UDP_SRC", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -663,7 +663,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_UDP,
         true,
         NXM_OF_UDP_DST, "NXM_OF_UDP_DST",
-        OXM_OF_UDP_DST, "OXM_OF_UDP_DST",
+        OXM_OF_UDP_DST, "OXM_OF_UDP_DST", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -677,7 +677,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_SCTP,
         true,
         OXM_OF_SCTP_SRC, "OXM_OF_SCTP_SRC",
-        OXM_OF_SCTP_SRC, "OXM_OF_SCTP_SRC",
+        OXM_OF_SCTP_SRC, "OXM_OF_SCTP_SRC", OFP12_VERSION,
         OFPUTIL_P_NXM_OF11_UP,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -689,7 +689,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_SCTP,
         true,
         OXM_OF_SCTP_DST, "OXM_OF_SCTP_DST",
-        OXM_OF_SCTP_DST, "OXM_OF_SCTP_DST",
+        OXM_OF_SCTP_DST, "OXM_OF_SCTP_DST", OFP12_VERSION,
         OFPUTIL_P_NXM_OF11_UP,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -703,7 +703,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ICMPV4,
         false,
         NXM_OF_ICMP_TYPE, "NXM_OF_ICMP_TYPE",
-        OXM_OF_ICMPV4_TYPE, "OXM_OF_ICMPV4_TYPE",
+        OXM_OF_ICMPV4_TYPE, "OXM_OF_ICMPV4_TYPE", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -715,7 +715,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ICMPV4,
         false,
         NXM_OF_ICMP_CODE, "NXM_OF_ICMP_CODE",
-        OXM_OF_ICMPV4_CODE, "OXM_OF_ICMPV4_CODE",
+        OXM_OF_ICMPV4_CODE, "OXM_OF_ICMPV4_CODE", OFP12_VERSION,
         OFPUTIL_P_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -729,7 +729,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ICMPV6,
         false,
         NXM_NX_ICMPV6_TYPE, "NXM_NX_ICMPV6_TYPE",
-        OXM_OF_ICMPV6_TYPE, "OXM_OF_ICMPV6_TYPE",
+        OXM_OF_ICMPV6_TYPE, "OXM_OF_ICMPV6_TYPE", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -741,7 +741,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ICMPV6,
         false,
         NXM_NX_ICMPV6_CODE, "NXM_NX_ICMPV6_CODE",
-        OXM_OF_ICMPV6_CODE, "OXM_OF_ICMPV6_CODE",
+        OXM_OF_ICMPV6_CODE, "OXM_OF_ICMPV6_CODE", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NONE,
         -1,
@@ -759,7 +759,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ND,
         false,
         NXM_NX_ND_TARGET, "NXM_NX_ND_TARGET",
-        OXM_OF_IPV6_ND_TARGET, "OXM_OF_IPV6_ND_TARGET",
+        OXM_OF_IPV6_ND_TARGET, "OXM_OF_IPV6_ND_TARGET", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -771,7 +771,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ND_SOLICIT,
         false,
         NXM_NX_ND_SLL, "NXM_NX_ND_SLL",
-        OXM_OF_IPV6_ND_SLL, "OXM_OF_IPV6_ND_SLL",
+        OXM_OF_IPV6_ND_SLL, "OXM_OF_IPV6_ND_SLL", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -783,7 +783,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFP_ND_ADVERT,
         false,
         NXM_NX_ND_TLL, "NXM_NX_ND_TLL",
-        OXM_OF_IPV6_ND_TLL, "OXM_OF_IPV6_ND_TLL",
+        OXM_OF_IPV6_ND_TLL, "OXM_OF_IPV6_ND_TLL", OFP12_VERSION,
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
@@ -894,6 +894,16 @@ mf_from_nxm_header__(uint32_t header)
     return NULL;
 }
 
+uint32_t
+mf_oxm_header(enum mf_field_id id, enum ofp_version oxm_version)
+{
+    const struct mf_field *field = mf_from_id(id);
+
+    return (oxm_version >= field->oxm_version
+            ? field->oxm_header
+            : field->nxm_header);
+}
+
 /* Returns true if 'wc' wildcards all the bits in field 'mf', false if 'wc'
  * specifies at least one bit in the field.
  *
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index d02d320..7a4b8dc 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -276,6 +276,11 @@ struct mf_field {
      *
      *   - NXM and OXM both define such a field: nxm_header and oxm_header will
      *     both be nonzero and different, similarly for nxm_name and oxm_name.
+     *     In this case, 'oxm_version' is significant: if it is greater than
+     *     OFP12_VERSION, then only that version of OpenFlow introduced this
+     *     OXM header, so ovs-vswitchd should send 'nxm_header' instead with
+     *     earlier protocol versions to avoid confusing controllers that were
+     *     using a previous Open vSwitch extension.
      *
      *   - Only NXM or only OXM defines such a field: nxm_header and oxm_header
      *     will both have the same value (either an OXM_* or NXM_* value) and
@@ -285,11 +290,14 @@ struct mf_field {
      * NXM formatted match, since it will be an NXM_* constant when possible
      * for compatibility with OpenFlow implementations that expect that, with
      * OXM_* constants used for fields that OXM adds.  Conversely, 'oxm_header'
-     * is the header to use when outputting an OXM formatted match. */
+     * is the header to use when outputting an OXM formatted match to an
+     * OpenFlow connection of version 'oxm_version' or above (and otherwise
+     * 'nxm_header'). */
     uint32_t nxm_header;        /* An NXM_* (or OXM_*) constant. */
     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 */
+    enum ofp_version oxm_version; /* OpenFlow version that added oxm_header. */
 
     /* Usable protocols.
      * NXM and OXM are extensible, allowing later extensions to be sent in
@@ -352,6 +360,9 @@ mf_from_id(enum mf_field_id id)
     return &mf_fields[id];
 }
 
+/* NXM and OXM protocol headers. */
+uint32_t mf_oxm_header(enum mf_field_id, enum ofp_version oxm_version);
+
 /* Inspecting wildcarded bits. */
 bool mf_is_all_wild(const struct mf_field *, const struct flow_wildcards *);
 
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 957c82b..295eec0 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -499,19 +499,19 @@ nxm_put_frag(struct ofpbuf *b, const struct match *match)
 /* Appends to 'b' a set of OXM or NXM matches for the IPv4 or IPv6 fields in
  * 'match'.  */
 static void
-nxm_put_ip(struct ofpbuf *b, const struct match *match, bool oxm)
+nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm)
 {
     const struct flow *flow = &match->flow;
 
     if (flow->dl_type == htons(ETH_TYPE_IP)) {
-        nxm_put_32m(b, oxm ? OXM_OF_IPV4_SRC : NXM_OF_IP_SRC,
+        nxm_put_32m(b, mf_oxm_header(MFF_IPV4_SRC, oxm),
                     flow->nw_src, match->wc.masks.nw_src);
-        nxm_put_32m(b, oxm ? OXM_OF_IPV4_DST : NXM_OF_IP_DST,
+        nxm_put_32m(b, mf_oxm_header(MFF_IPV4_DST, oxm),
                     flow->nw_dst, match->wc.masks.nw_dst);
     } else {
-        nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_SRC : NXM_NX_IPV6_SRC,
+        nxm_put_ipv6(b, mf_oxm_header(MFF_IPV6_SRC, oxm),
                      &flow->ipv6_src, &match->wc.masks.ipv6_src);
-        nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_DST : NXM_NX_IPV6_DST,
+        nxm_put_ipv6(b, mf_oxm_header(MFF_IPV6_DST, oxm),
                      &flow->ipv6_dst, &match->wc.masks.ipv6_dst);
     }
 
@@ -519,74 +519,74 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, 
bool oxm)
 
     if (match->wc.masks.nw_tos & IP_DSCP_MASK) {
         if (oxm) {
-            nxm_put_8(b, OXM_OF_IP_DSCP, flow->nw_tos >> 2);
+            nxm_put_8(b, mf_oxm_header(MFF_IP_DSCP_SHIFTED, oxm),
+                      flow->nw_tos >> 2);
         } else {
-            nxm_put_8(b, NXM_OF_IP_TOS, flow->nw_tos & IP_DSCP_MASK);
+            nxm_put_8(b, mf_oxm_header(MFF_IP_DSCP, oxm),
+                      flow->nw_tos & IP_DSCP_MASK);
         }
     }
 
     if (match->wc.masks.nw_tos & IP_ECN_MASK) {
-        nxm_put_8(b, oxm ? OXM_OF_IP_ECN : NXM_NX_IP_ECN,
+        nxm_put_8(b, mf_oxm_header(MFF_IP_ECN, oxm),
                   flow->nw_tos & IP_ECN_MASK);
     }
 
     if (!oxm && match->wc.masks.nw_ttl) {
-        nxm_put_8(b, NXM_NX_IP_TTL, flow->nw_ttl);
+        nxm_put_8(b, mf_oxm_header(MFF_IP_TTL, oxm), flow->nw_ttl);
     }
 
-    nxm_put_32m(b, oxm ? OXM_OF_IPV6_FLABEL : NXM_NX_IPV6_LABEL,
+    nxm_put_32m(b, mf_oxm_header(MFF_IPV6_LABEL, oxm),
                 flow->ipv6_label, match->wc.masks.ipv6_label);
 
     if (match->wc.masks.nw_proto) {
-        nxm_put_8(b, oxm ? OXM_OF_IP_PROTO : NXM_OF_IP_PROTO, flow->nw_proto);
+        nxm_put_8(b, mf_oxm_header(MFF_IP_PROTO, oxm), flow->nw_proto);
 
         if (flow->nw_proto == IPPROTO_TCP) {
-            nxm_put_16m(b, oxm ? OXM_OF_TCP_SRC : NXM_OF_TCP_SRC,
+            nxm_put_16m(b, mf_oxm_header(MFF_TCP_SRC, oxm),
                         flow->tp_src, match->wc.masks.tp_src);
-            nxm_put_16m(b, oxm ? OXM_OF_TCP_DST : NXM_OF_TCP_DST,
+            nxm_put_16m(b, mf_oxm_header(MFF_TCP_DST, oxm),
                         flow->tp_dst, match->wc.masks.tp_dst);
-            nxm_put_16m(b, NXM_NX_TCP_FLAGS,
+            nxm_put_16m(b, mf_oxm_header(MFF_TCP_FLAGS, oxm),
                         flow->tcp_flags, match->wc.masks.tcp_flags);
         } else if (flow->nw_proto == IPPROTO_UDP) {
-            nxm_put_16m(b, oxm ? OXM_OF_UDP_SRC : NXM_OF_UDP_SRC,
+            nxm_put_16m(b, mf_oxm_header(MFF_UDP_SRC, oxm),
                         flow->tp_src, match->wc.masks.tp_src);
-            nxm_put_16m(b, oxm ? OXM_OF_UDP_DST : NXM_OF_UDP_DST,
+            nxm_put_16m(b, mf_oxm_header(MFF_UDP_DST, oxm),
                         flow->tp_dst, match->wc.masks.tp_dst);
         } else if (flow->nw_proto == IPPROTO_SCTP) {
-            nxm_put_16m(b, OXM_OF_SCTP_SRC, flow->tp_src,
+            nxm_put_16m(b, mf_oxm_header(MFF_SCTP_SRC, oxm), flow->tp_src,
                         match->wc.masks.tp_src);
-            nxm_put_16m(b, OXM_OF_SCTP_DST, flow->tp_dst,
+            nxm_put_16m(b, mf_oxm_header(MFF_SCTP_DST, oxm), flow->tp_dst,
                         match->wc.masks.tp_dst);
         } else if (is_icmpv4(flow)) {
             if (match->wc.masks.tp_src) {
-                nxm_put_8(b, oxm ? OXM_OF_ICMPV4_TYPE : NXM_OF_ICMP_TYPE,
+                nxm_put_8(b, mf_oxm_header(MFF_ICMPV4_TYPE, oxm),
                           ntohs(flow->tp_src));
             }
             if (match->wc.masks.tp_dst) {
-                nxm_put_8(b, oxm ? OXM_OF_ICMPV4_CODE : NXM_OF_ICMP_CODE,
+                nxm_put_8(b, mf_oxm_header(MFF_ICMPV4_CODE, oxm),
                           ntohs(flow->tp_dst));
             }
         } else if (is_icmpv6(flow)) {
             if (match->wc.masks.tp_src) {
-                nxm_put_8(b, oxm ? OXM_OF_ICMPV6_TYPE : NXM_NX_ICMPV6_TYPE,
+                nxm_put_8(b, mf_oxm_header(MFF_ICMPV6_TYPE, oxm),
                           ntohs(flow->tp_src));
             }
             if (match->wc.masks.tp_dst) {
-                nxm_put_8(b, oxm ? OXM_OF_ICMPV6_CODE : NXM_NX_ICMPV6_CODE,
+                nxm_put_8(b, mf_oxm_header(MFF_ICMPV6_CODE, oxm),
                           ntohs(flow->tp_dst));
             }
             if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
                 flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
-                nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_ND_TARGET : NXM_NX_ND_TARGET,
+                nxm_put_ipv6(b, mf_oxm_header(MFF_ND_TARGET, oxm),
                              &flow->nd_target, &match->wc.masks.nd_target);
                 if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
-                    uint32_t field = oxm ? OXM_OF_IPV6_ND_SLL : NXM_NX_ND_SLL;
-                    nxm_put_eth_masked(b, field,
+                    nxm_put_eth_masked(b, mf_oxm_header(MFF_ND_SLL, oxm),
                                        flow->arp_sha, match->wc.masks.arp_sha);
                 }
                 if (flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
-                    uint32_t field = oxm ? OXM_OF_IPV6_ND_TLL : NXM_NX_ND_TLL;
-                    nxm_put_eth_masked(b, field,
+                    nxm_put_eth_masked(b, mf_oxm_header(MFF_ND_TLL, oxm),
                                        flow->arp_tha, match->wc.masks.arp_tha);
                 }
             }
@@ -598,6 +598,9 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, 
bool oxm)
  * Flow Stats Requests messages, a 'cookie' and 'cookie_mask' may be supplied.
  * Otherwise, 'cookie_mask' should be zero.
  *
+ * Specify 'oxm' as 0 to express the match in NXM format; otherwise, specify
+ * 'oxm' as the OpenFlow version number for the OXM format to use.
+ *
  * This function can cause 'b''s data to be reallocated.
  *
  * Returns the number of bytes appended to 'b', excluding padding.
@@ -605,7 +608,7 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, 
bool oxm)
  * If 'match' is a catch-all rule that matches every packet, then this function
  * appends nothing to 'b' and returns 0. */
 static int
-nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
+nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
            ovs_be64 cookie, ovs_be64 cookie_mask)
 {
     const struct flow *flow = &match->flow;
@@ -632,18 +635,20 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match 
*match,
     if (match->wc.masks.in_port.ofp_port) {
         ofp_port_t in_port = flow->in_port.ofp_port;
         if (oxm) {
-            nxm_put_32(b, OXM_OF_IN_PORT, ofputil_port_to_ofp11(in_port));
+            nxm_put_32(b, mf_oxm_header(MFF_IN_PORT_OXM, oxm),
+                       ofputil_port_to_ofp11(in_port));
         } else {
-            nxm_put_16(b, NXM_OF_IN_PORT, htons(ofp_to_u16(in_port)));
+            nxm_put_16(b, mf_oxm_header(MFF_IN_PORT, oxm),
+                       htons(ofp_to_u16(in_port)));
         }
     }
 
     /* Ethernet. */
-    nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_SRC : NXM_OF_ETH_SRC,
+    nxm_put_eth_masked(b, mf_oxm_header(MFF_ETH_SRC, oxm),
                        flow->dl_src, match->wc.masks.dl_src);
-    nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_DST : NXM_OF_ETH_DST,
+    nxm_put_eth_masked(b, mf_oxm_header(MFF_ETH_DST, oxm),
                        flow->dl_dst, match->wc.masks.dl_dst);
-    nxm_put_16m(b, oxm ? OXM_OF_ETH_TYPE : NXM_OF_ETH_TYPE,
+    nxm_put_16m(b, mf_oxm_header(MFF_ETH_TYPE, oxm),
                 ofputil_dl_type_to_openflow(flow->dl_type),
                 match->wc.masks.dl_type);
 
@@ -654,32 +659,35 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match 
*match,
         ovs_be16 mask = match->wc.masks.vlan_tci & VID_CFI_MASK;
 
         if (mask == htons(VLAN_VID_MASK | VLAN_CFI)) {
-            nxm_put_16(b, OXM_OF_VLAN_VID, vid);
+            nxm_put_16(b, mf_oxm_header(MFF_VLAN_VID, oxm), vid);
         } else if (mask) {
-            nxm_put_16m(b, OXM_OF_VLAN_VID, vid, mask);
+            nxm_put_16m(b, mf_oxm_header(MFF_VLAN_VID, oxm), vid, mask);
         }
 
         if (vid && vlan_tci_to_pcp(match->wc.masks.vlan_tci)) {
-            nxm_put_8(b, OXM_OF_VLAN_PCP, vlan_tci_to_pcp(flow->vlan_tci));
+            nxm_put_8(b, mf_oxm_header(MFF_VLAN_PCP, oxm),
+                      vlan_tci_to_pcp(flow->vlan_tci));
         }
 
     } else {
-        nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci,
+        nxm_put_16m(b, mf_oxm_header(MFF_VLAN_TCI, oxm), flow->vlan_tci,
                     match->wc.masks.vlan_tci);
     }
 
     /* MPLS. */
     if (eth_type_mpls(flow->dl_type)) {
         if (match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) {
-            nxm_put_8(b, OXM_OF_MPLS_TC, mpls_lse_to_tc(flow->mpls_lse[0]));
+            nxm_put_8(b, mf_oxm_header(MFF_MPLS_TC, oxm),
+                      mpls_lse_to_tc(flow->mpls_lse[0]));
         }
 
         if (match->wc.masks.mpls_lse[0] & htonl(MPLS_BOS_MASK)) {
-            nxm_put_8(b, OXM_OF_MPLS_BOS, mpls_lse_to_bos(flow->mpls_lse[0]));
+            nxm_put_8(b, mf_oxm_header(MFF_MPLS_BOS, oxm),
+                      mpls_lse_to_bos(flow->mpls_lse[0]));
         }
 
         if (match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK)) {
-            nxm_put_32(b, OXM_OF_MPLS_LABEL,
+            nxm_put_32(b, mf_oxm_header(MFF_MPLS_LABEL, oxm),
                        htonl(mpls_lse_to_label(flow->mpls_lse[0])));
         }
     }
@@ -691,41 +699,42 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match 
*match,
                flow->dl_type == htons(ETH_TYPE_RARP)) {
         /* ARP. */
         if (match->wc.masks.nw_proto) {
-            nxm_put_16(b, oxm ? OXM_OF_ARP_OP : NXM_OF_ARP_OP,
+            nxm_put_16(b, mf_oxm_header(MFF_ARP_OP, oxm),
                        htons(flow->nw_proto));
         }
-        nxm_put_32m(b, oxm ? OXM_OF_ARP_SPA : NXM_OF_ARP_SPA,
+        nxm_put_32m(b, mf_oxm_header(MFF_ARP_SPA, oxm),
                     flow->nw_src, match->wc.masks.nw_src);
-        nxm_put_32m(b, oxm ? OXM_OF_ARP_TPA : NXM_OF_ARP_TPA,
+        nxm_put_32m(b, mf_oxm_header(MFF_ARP_TPA, oxm),
                     flow->nw_dst, match->wc.masks.nw_dst);
-        nxm_put_eth_masked(b, oxm ? OXM_OF_ARP_SHA : NXM_NX_ARP_SHA,
+        nxm_put_eth_masked(b, mf_oxm_header(MFF_ARP_SHA, oxm),
                            flow->arp_sha, match->wc.masks.arp_sha);
-        nxm_put_eth_masked(b, oxm ? OXM_OF_ARP_THA : NXM_NX_ARP_THA,
+        nxm_put_eth_masked(b, mf_oxm_header(MFF_ARP_THA, oxm),
                            flow->arp_tha, match->wc.masks.arp_tha);
     }
 
     /* Tunnel ID. */
-    nxm_put_64m(b, oxm ? OXM_OF_TUNNEL_ID : NXM_NX_TUN_ID,
+    nxm_put_64m(b, mf_oxm_header(MFF_TUN_ID, oxm),
                 flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);
 
     /* Other tunnel metadata. */
-    nxm_put_32m(b, NXM_NX_TUN_IPV4_SRC,
+    nxm_put_32m(b, mf_oxm_header(MFF_TUN_SRC, oxm),
                 flow->tunnel.ip_src, match->wc.masks.tunnel.ip_src);
-    nxm_put_32m(b, NXM_NX_TUN_IPV4_DST,
+    nxm_put_32m(b, mf_oxm_header(MFF_TUN_DST, oxm),
                 flow->tunnel.ip_dst, match->wc.masks.tunnel.ip_dst);
 
     /* Registers. */
     for (i = 0; i < FLOW_N_REGS; i++) {
-        nxm_put_32m(b, NXM_NX_REG(i),
+        nxm_put_32m(b, mf_oxm_header(MFF_REG0 + i, oxm),
                     htonl(flow->regs[i]), htonl(match->wc.masks.regs[i]));
     }
 
     /* Mark. */
-    nxm_put_32m(b, NXM_NX_PKT_MARK, htonl(flow->pkt_mark),
+    nxm_put_32m(b, mf_oxm_header(MFF_PKT_MARK, oxm), htonl(flow->pkt_mark),
                 htonl(match->wc.masks.pkt_mark));
 
     /* OpenFlow 1.1+ Metadata. */
-    nxm_put_64m(b, OXM_OF_METADATA, flow->metadata, match->wc.masks.metadata);
+    nxm_put_64m(b, mf_oxm_header(MFF_METADATA, oxm),
+                flow->metadata, match->wc.masks.metadata);
 
     /* Cookie. */
     nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask);
@@ -748,23 +757,26 @@ int
 nx_put_match(struct ofpbuf *b, const struct match *match,
              ovs_be64 cookie, ovs_be64 cookie_mask)
 {
-    int match_len = nx_put_raw(b, false, match, cookie, cookie_mask);
+    int match_len = nx_put_raw(b, 0, match, cookie, cookie_mask);
 
     ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8));
     return match_len;
 }
 
-
-/* Appends to 'b' an struct ofp11_match_header followed by the oxm format that
+/* Appends to 'b' an struct ofp11_match_header followed by the OXM format that
  * expresses 'cr', plus enough zero bytes to pad the data appended out to a
  * multiple of 8.
  *
+ * OXM differs slightly among versions of OpenFlow.  Specify the OpenFlow
+ * version in use as 'version'.
+ *
  * This function can cause 'b''s data to be reallocated.
  *
  * Returns the number of bytes appended to 'b', excluding the padding.  Never
  * returns zero. */
 int
-oxm_put_match(struct ofpbuf *b, const struct match *match)
+oxm_put_match(struct ofpbuf *b, const struct match *match,
+              enum ofp_version version)
 {
     int match_len;
     struct ofp11_match_header *omh;
@@ -772,7 +784,8 @@ oxm_put_match(struct ofpbuf *b, const struct match *match)
     ovs_be64 cookie = htonll(0), cookie_mask = htonll(0);
 
     ofpbuf_put_uninit(b, sizeof *omh);
-    match_len = nx_put_raw(b, true, match, cookie, cookie_mask) + sizeof *omh;
+    match_len = (nx_put_raw(b, version, match, cookie, cookie_mask)
+                 + sizeof *omh);
     ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8));
 
     omh = ofpbuf_at(b, start_len, sizeof *omh);
diff --git a/lib/nx-match.h b/lib/nx-match.h
index edd7948..077f299 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -52,7 +52,7 @@ enum ofperr oxm_pull_match(struct ofpbuf *, struct match *);
 enum ofperr oxm_pull_match_loose(struct ofpbuf *, struct match *);
 int nx_put_match(struct ofpbuf *, const struct match *,
                  ovs_be64 cookie, ovs_be64 cookie_mask);
-int oxm_put_match(struct ofpbuf *, const struct match *);
+int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version);
 
 char *nx_match_to_string(const uint8_t *, unsigned int match_len);
 char *oxm_match_to_string(const struct ofpbuf *, unsigned int match_len);
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index ce14004..cc1f9a0 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -825,14 +825,15 @@ set_field_from_openflow(const struct 
ofp12_action_set_field *oasf,
 
 static void
 set_field_to_openflow12(const struct ofpact_set_field *sf,
-                        struct ofpbuf *openflow)
+                        struct ofpbuf *openflow,
+                        enum ofp_version version)
 {
     uint16_t padded_value_len = ROUND_UP(sf->field->n_bytes, 8);
     struct ofp12_action_set_field *oasf;
     char *value;
 
     oasf = ofputil_put_OFPAT12_SET_FIELD(openflow);
-    oasf->dst = htonl(sf->field->oxm_header);
+    oasf->dst = htonl(mf_oxm_header(sf->field->id, version));
     oasf->len = htons(sizeof *oasf + padded_value_len);
 
     value = ofpbuf_put_zeros(openflow, padded_value_len);
@@ -1080,7 +1081,7 @@ set_field_to_openflow(const struct ofpact_set_field *sf,
     struct ofp_header *oh = (struct ofp_header *)openflow->frame;
 
     if (oh->version >= OFP12_VERSION) {
-        set_field_to_openflow12(sf, openflow);
+        set_field_to_openflow12(sf, openflow, oh->version);
     } else if (oh->version == OFP11_VERSION) {
         set_field_to_openflow11(sf, openflow);
     } else if (oh->version == OFP10_VERSION) {
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 4bf101a..e29c454 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -665,7 +665,8 @@ ofputil_put_ofp11_match(struct ofpbuf *b, const struct 
match *match,
     case OFPUTIL_P_OF13_OXM:
     case OFPUTIL_P_OF14_OXM:
     case OFPUTIL_P_OF15_OXM:
-        return oxm_put_match(b, match);
+        return oxm_put_match(b, match,
+                             ofputil_protocol_to_ofp_version(protocol));
     }
 
     OVS_NOT_REACHED();
@@ -1068,7 +1069,7 @@ ofputil_protocols_from_string(const char *s)
     return protocols;
 }
 
-static int
+enum ofp_version
 ofputil_version_from_string(const char *s)
 {
     if (!strcasecmp(s, "OpenFlow10")) {
@@ -2929,7 +2930,7 @@ ofputil_append_flow_stats_reply(const struct 
ofputil_flow_stats *fs,
         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);
 
@@ -3473,7 +3474,7 @@ ofputil_encode_ofp12_packet_in(const struct 
ofputil_packet_in *pin,
                               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);
 
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index f0b6604..ce6045b 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -170,6 +170,8 @@ void ofputil_format_version_name(struct ds *, enum 
ofp_version);
 void ofputil_format_version_bitmap(struct ds *msg, uint32_t bitmap);
 void ofputil_format_version_bitmap_names(struct ds *msg, uint32_t bitmap);
 
+enum ofp_version ofputil_version_from_string(const char *s);
+
 uint32_t ofputil_protocols_to_version_bitmap(enum ofputil_protocol);
 enum ofputil_protocol ofputil_protocols_from_version_bitmap(uint32_t bitmap);
 
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index bda8666..88e4220 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -1890,7 +1890,7 @@ OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(3a) 
OXM_OF_ICMPV6_TYPE(88) OXM_OF_IPV6_ND_
 # Invalid field number.
 01020304(1111/2222)
 ])
-AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' --strict parse-oxm < oxm.txt],
+AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' --strict parse-oxm OpenFlow12 
< oxm.txt],
   [0], [dnl
 <any>
 
@@ -2123,11 +2123,11 @@ AT_DATA([oxm.txt], [dnl
 OXM_OF_IN_PORT(00000001), 01020304(1111/2222), OXM_OF_ETH_TYPE(0800)
 ])
 
-AT_CHECK([ovs-ofctl --strict parse-oxm < oxm.txt], [0], [dnl
+AT_CHECK([ovs-ofctl --strict parse-oxm OpenFlow12 < oxm.txt], [0], [dnl
 nx_pull_match() returned error OFPBMC_BAD_FIELD
 ])
 
-AT_CHECK([ovs-ofctl parse-oxm < oxm.txt], [0], [dnl
+AT_CHECK([ovs-ofctl parse-oxm OpenFlow12 < oxm.txt], [0], [dnl
 OXM_OF_IN_PORT(00000001), OXM_OF_ETH_TYPE(0800)
 ])
 AT_CLEANUP
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 986c18f..d62d328 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -2823,7 +2823,7 @@ ofctl_parse_flows(int argc OVS_UNUSED, char *argv[])
 }
 
 static void
-ofctl_parse_nxm__(bool oxm)
+ofctl_parse_nxm__(bool oxm, enum ofp_version version)
 {
     struct ds in;
 
@@ -2868,7 +2868,7 @@ ofctl_parse_nxm__(bool oxm)
             ofpbuf_uninit(&nx_match);
             ofpbuf_init(&nx_match, 0);
             if (oxm) {
-                match_len = oxm_put_match(&nx_match, &match);
+                match_len = oxm_put_match(&nx_match, &match, version);
                 out = oxm_match_to_string(&nx_match, match_len);
             } else {
                 match_len = nx_put_match(&nx_match, &match,
@@ -2894,16 +2894,22 @@ ofctl_parse_nxm__(bool oxm)
 static void
 ofctl_parse_nxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
-    return ofctl_parse_nxm__(false);
+    return ofctl_parse_nxm__(false, 0);
 }
 
-/* "parse-oxm": reads a series of OXM nx_match specifications as strings from
- * stdin, does some internal fussing with them, and then prints them back as
- * strings on stdout. */
+/* "parse-oxm VERSION": reads a series of OXM nx_match specifications as
+ * strings from stdin, does some internal fussing with them, and then prints
+ * them back as strings on stdout.  VERSION must specify an OpenFlow version,
+ * e.g. "OpenFlow12". */
 static void
-ofctl_parse_oxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+ofctl_parse_oxm(int argc OVS_UNUSED, char *argv[])
 {
-    return ofctl_parse_nxm__(true);
+    enum ofp_version version = ofputil_version_from_string(argv[1]);
+    if (version < OFP12_VERSION) {
+        ovs_fatal(0, "%s: not a valid version for OXM", argv[1]);
+    }
+
+    return ofctl_parse_nxm__(true, version);
 }
 
 static void
@@ -3349,7 +3355,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
 
     /* Convert to and from OXM. */
     ofpbuf_init(&nxm, 0);
-    nxm_match_len = oxm_put_match(&nxm, &match);
+    nxm_match_len = oxm_put_match(&nxm, &match, OFP12_VERSION);
     nxm_s = oxm_match_to_string(&nxm, nxm_match_len);
     error = oxm_pull_match(&nxm, &nxm_match);
     printf("OXM: %s -> ", nxm_s);
@@ -3539,7 +3545,7 @@ static const struct command all_commands[] = {
     { "parse-flows", 1, 1, ofctl_parse_flows },
     { "parse-nx-match", 0, 0, ofctl_parse_nxm },
     { "parse-nxm", 0, 0, ofctl_parse_nxm },
-    { "parse-oxm", 0, 0, ofctl_parse_oxm },
+    { "parse-oxm", 1, 1, ofctl_parse_oxm },
     { "parse-ofp10-actions", 0, 0, ofctl_parse_ofp10_actions },
     { "parse-ofp10-match", 0, 0, ofctl_parse_ofp10_match },
     { "parse-ofp11-match", 0, 0, ofctl_parse_ofp11_match },
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to