Signed-off-by: Joe Stringer <j...@wand.net.nz>
---
v2: Uses only OXM_OF_METADATA

I've added to flow_extract() so it sets the metadata field in the rule.

ofproto-dpif.c, handle_miss_upcalls() - Question. I've made this function set
the metadata based on the miss structure, is this sufficient? Do I need to
change anything about how the miss structure interacts with the new metadata
field?

Also in ofproto-dpif.c, in ofproto_unixctl_trace() I've added an extra argument
to specify the metadata, is there some corresponding documentation that I
should change along with this?
---
 lib/classifier.c       |   30 ++++++++++++++++++++++++-
 lib/classifier.h       |    3 ++
 lib/dpif-linux.c       |    2 +-
 lib/dpif-netdev.c      |    4 +-
 lib/flow.c             |   40 +++++++++++++++++++++++-----------
 lib/flow.h             |   17 +++++++++-----
 lib/learn.c            |    2 +-
 lib/learning-switch.c  |    2 +-
 lib/meta-flow.c        |   30 +++++++++++++++++++++++++
 lib/meta-flow.h        |    1 +
 lib/nx-match.c         |    5 +++-
 lib/nx-match.h         |    5 ++-
 lib/ofp-print.c        |    2 +-
 lib/ofp-util.c         |   18 +++++++++------
 ofproto/ofproto-dpif.c |   15 +++++++-----
 ofproto/ofproto.c      |    4 +-
 tests/ofp-print.at     |    4 +-
 tests/ofproto-dpif.at  |   56 ++++++++++++++++++++++++------------------------
 tests/ofproto.at       |   10 ++++----
 tests/ovs-ofctl.at     |   36 ++++++++++++++++++++++++++++--
 tests/test-flows.c     |    2 +-
 21 files changed, 204 insertions(+), 84 deletions(-)

diff --git a/lib/classifier.c b/lib/classifier.c
index d19840c..0541b5c 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -119,6 +119,20 @@ cls_rule_set_reg_masked(struct cls_rule *rule, unsigned 
int reg_idx,
 }
 
 void
+cls_rule_set_metadata(struct cls_rule *rule, ovs_be64 metadata)
+{
+    cls_rule_set_metadata_masked(rule, metadata, htonll(UINT64_MAX));
+}
+
+void
+cls_rule_set_metadata_masked(struct cls_rule *rule, ovs_be64 metadata,
+                             ovs_be64 mask)
+{
+    rule->wc.metadata_mask = mask;
+    rule->flow.metadata = metadata & mask;
+}
+
+void
 cls_rule_set_tun_id(struct cls_rule *rule, ovs_be64 tun_id)
 {
     cls_rule_set_tun_id_masked(rule, tun_id, htonll(UINT64_MAX));
@@ -525,7 +539,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     if (rule->priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%d,", rule->priority);
@@ -595,6 +609,17 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
                       ntohll(f->tun_id), ntohll(wc->tun_id_mask));
         break;
     }
+    switch (wc->metadata_mask) {
+    case 0:
+        break;
+    case CONSTANT_HTONLL(UINT64_MAX):
+        ds_put_format(s, "metadata=%#"PRIx64",", ntohll(f->metadata));
+        break;
+    default:
+        ds_put_format(s, "metadata=%#"PRIx64"/%#"PRIx64",",
+                      ntohll(f->metadata), ntohll(wc->metadata_mask));
+        break;
+    }
     if (!(w & FWW_IN_PORT)) {
         ds_put_format(s, "in_port=%"PRIu16",", f->in_port);
     }
@@ -1188,7 +1213,7 @@ flow_equal_except(const struct flow *a, const struct flow 
*b,
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
@@ -1197,6 +1222,7 @@ flow_equal_except(const struct flow *a, const struct flow 
*b,
     }
 
     return (!((a->tun_id ^ b->tun_id) & wildcards->tun_id_mask)
+            && !((a->metadata ^ b->metadata) & wildcards->metadata_mask)
             && !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask)
             && !((a->nw_dst ^ b->nw_dst) & wildcards->nw_dst_mask)
             && (wc & FWW_IN_PORT || a->in_port == b->in_port)
diff --git a/lib/classifier.h b/lib/classifier.h
index 9e4b33e..ec7316c 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -90,6 +90,9 @@ void cls_rule_zero_wildcarded_fields(struct cls_rule *);
 void cls_rule_set_reg(struct cls_rule *, unsigned int reg_idx, uint32_t value);
 void cls_rule_set_reg_masked(struct cls_rule *, unsigned int reg_idx,
                              uint32_t value, uint32_t mask);
+void cls_rule_set_metadata(struct cls_rule *, ovs_be64 metadata);
+void cls_rule_set_metadata_masked(struct cls_rule *, ovs_be64 metadata,
+                                  ovs_be64 mask);
 void cls_rule_set_tun_id(struct cls_rule *, ovs_be64 tun_id);
 void cls_rule_set_tun_id_masked(struct cls_rule *,
                                 ovs_be64 tun_id, ovs_be64 mask);
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 62f6917..ee4da19 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1378,7 +1378,7 @@ dpif_linux_vport_send(int dp_ifindex, uint32_t port_no,
     uint64_t action;
 
     ofpbuf_use_const(&packet, data, size);
-    flow_extract(&packet, 0, htonll(0), 0, &flow);
+    flow_extract(&packet, 0, htonll(0), htonll(0), 0, &flow);
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, &flow);
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index cade79e..a0c26e1 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -904,7 +904,7 @@ dpif_netdev_execute(struct dpif *dpif, const struct 
dpif_execute *execute)
     ofpbuf_reserve(&copy, DP_NETDEV_HEADROOM);
     ofpbuf_put(&copy, execute->packet->data, execute->packet->size);
 
-    flow_extract(&copy, 0, 0, -1, &key);
+    flow_extract(&copy, 0, 0, 0, -1, &key);
     error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
                                           &key);
     if (!error) {
@@ -1002,7 +1002,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct 
dp_netdev_port *port,
     if (packet->size < ETH_HEADER_LEN) {
         return;
     }
-    flow_extract(packet, 0, 0, port->port_no, &key);
+    flow_extract(packet, 0, 0, 0, port->port_no, &key);
     flow = dp_netdev_lookup_flow(dp, &key);
     if (flow) {
         dp_netdev_flow_used(flow, &key, packet);
diff --git a/lib/flow.c b/lib/flow.c
index 46e0e2d..ee0a87e 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -312,8 +312,8 @@ invalid:
 
 }
 
-/* Initializes 'flow' members from 'packet', 'skb_priority', 'tun_id', and
- * 'ofp_in_port'.
+/* Initializes 'flow' members from 'packet', 'skb_priority', 'tun_id',
+ * 'metadata' and 'ofp_in_port'.
  *
  * Initializes 'packet' header pointers as follows:
  *
@@ -331,7 +331,7 @@ invalid:
  */
 void
 flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id,
-             uint16_t ofp_in_port, struct flow *flow)
+             ovs_be64 metadata, uint16_t ofp_in_port, struct flow *flow)
 {
     struct ofpbuf b = *packet;
     struct eth_header *eth;
@@ -340,6 +340,7 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, 
ovs_be64 tun_id,
 
     memset(flow, 0, sizeof *flow);
     flow->tun_id = tun_id;
+    flow->metadata = metadata;
     flow->in_port = ofp_in_port;
     flow->skb_priority = skb_priority;
 
@@ -444,12 +445,13 @@ flow_zero_wildcards(struct flow *flow, const struct 
flow_wildcards *wildcards)
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         flow->regs[i] &= wildcards->reg_masks[i];
     }
     flow->tun_id &= wildcards->tun_id_mask;
+    flow->metadata &= wildcards->metadata_mask;
     flow->nw_src &= wildcards->nw_src_mask;
     flow->nw_dst &= wildcards->nw_dst_mask;
     if (wc & FWW_IN_PORT) {
@@ -498,11 +500,14 @@ flow_zero_wildcards(struct flow *flow, const struct 
flow_wildcards *wildcards)
 void
 flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     fmd->tun_id = flow->tun_id;
     fmd->tun_id_mask = htonll(UINT64_MAX);
 
+    fmd->metadata = flow->metadata;
+    fmd->metadata_mask = htonll(UINT64_MAX);
+
     memcpy(fmd->regs, flow->regs, sizeof fmd->regs);
     memset(fmd->reg_masks, 0xff, sizeof fmd->reg_masks);
 
@@ -522,9 +527,11 @@ flow_format(struct ds *ds, const struct flow *flow)
 {
     ds_put_format(ds, "priority:%"PRIu32
                       ",tunnel:%#"PRIx64
+                      ",metadata:%#"PRIx64
                       ",in_port:%04"PRIx16,
                       flow->skb_priority,
                       ntohll(flow->tun_id),
+                      ntohll(flow->metadata),
                       flow->in_port);
 
     ds_put_format(ds, ",tci(");
@@ -587,7 +594,7 @@ flow_print(FILE *stream, const struct flow *flow)
 void
 flow_wildcards_init_catchall(struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     wc->wildcards = FWW_ALL;
     wc->tun_id_mask = htonll(0);
@@ -597,6 +604,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
     wc->ipv6_dst_mask = in6addr_any;
     wc->nd_target_mask = in6addr_any;
     memset(wc->reg_masks, 0, sizeof wc->reg_masks);
+    wc->metadata_mask = htonll(0);
     wc->vlan_tci_mask = htons(0);
     wc->nw_frag_mask = 0;
     wc->tp_src_mask = htons(0);
@@ -611,7 +619,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
 void
 flow_wildcards_init_exact(struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     wc->wildcards = 0;
     wc->tun_id_mask = htonll(UINT64_MAX);
@@ -621,6 +629,7 @@ flow_wildcards_init_exact(struct flow_wildcards *wc)
     wc->ipv6_dst_mask = in6addr_exact;
     wc->nd_target_mask = in6addr_exact;
     memset(wc->reg_masks, 0xff, sizeof wc->reg_masks);
+    wc->metadata_mask = htonll(UINT64_MAX);
     wc->vlan_tci_mask = htons(UINT16_MAX);
     wc->nw_frag_mask = UINT8_MAX;
     wc->tp_src_mask = htons(UINT16_MAX);
@@ -637,7 +646,7 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     if (wc->wildcards
         || wc->tun_id_mask != htonll(UINT64_MAX)
@@ -646,6 +655,7 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
         || wc->tp_src_mask != htons(UINT16_MAX)
         || wc->tp_dst_mask != htons(UINT16_MAX)
         || wc->vlan_tci_mask != htons(UINT16_MAX)
+        || wc->metadata_mask != htonll(UINT64_MAX)
         || !eth_mask_is_exact(wc->dl_src_mask)
         || !eth_mask_is_exact(wc->dl_dst_mask)
         || !ipv6_mask_is_exact(&wc->ipv6_src_mask)
@@ -671,7 +681,7 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     if (wc->wildcards != FWW_ALL
         || wc->tun_id_mask != htonll(0)
@@ -680,6 +690,7 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
         || wc->tp_src_mask != htons(0)
         || wc->tp_dst_mask != htons(0)
         || wc->vlan_tci_mask != htons(0)
+        || wc->metadata_mask != htonll(0)
         || !eth_addr_is_zero(wc->dl_src_mask)
         || !eth_addr_is_zero(wc->dl_dst_mask)
         || !ipv6_mask_is_any(&wc->ipv6_src_mask)
@@ -708,7 +719,7 @@ flow_wildcards_combine(struct flow_wildcards *dst,
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     dst->wildcards = src1->wildcards | src2->wildcards;
     dst->tun_id_mask = src1->tun_id_mask & src2->tun_id_mask;
@@ -723,6 +734,7 @@ flow_wildcards_combine(struct flow_wildcards *dst,
     for (i = 0; i < FLOW_N_REGS; i++) {
         dst->reg_masks[i] = src1->reg_masks[i] & src2->reg_masks[i];
     }
+    dst->metadata_mask = src1->metadata_mask & src2->metadata_mask;
     dst->vlan_tci_mask = src1->vlan_tci_mask & src2->vlan_tci_mask;
     dst->tp_src_mask = src1->tp_src_mask & src2->tp_src_mask;
     dst->tp_dst_mask = src1->tp_dst_mask & src2->tp_dst_mask;
@@ -737,7 +749,7 @@ flow_wildcards_hash(const struct flow_wildcards *wc, 
uint32_t basis)
     /* If you change struct flow_wildcards and thereby trigger this
      * assertion, please check that the new struct flow_wildcards has no holes
      * in it before you update the assertion. */
-    BUILD_ASSERT_DECL(sizeof *wc == 88 + FLOW_N_REGS * 4);
+    BUILD_ASSERT_DECL(sizeof *wc == 96 + FLOW_N_REGS * 4);
     return hash_bytes(wc, sizeof *wc, basis);
 }
 
@@ -749,13 +761,14 @@ flow_wildcards_equal(const struct flow_wildcards *a,
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     if (a->wildcards != b->wildcards
         || a->tun_id_mask != b->tun_id_mask
         || a->nw_src_mask != b->nw_src_mask
         || a->nw_dst_mask != b->nw_dst_mask
         || a->vlan_tci_mask != b->vlan_tci_mask
+        || a->metadata_mask != b->metadata_mask
         || !ipv6_addr_equals(&a->ipv6_src_mask, &b->ipv6_src_mask)
         || !ipv6_addr_equals(&a->ipv6_dst_mask, &b->ipv6_dst_mask)
         || !ipv6_addr_equals(&a->nd_target_mask, &b->nd_target_mask)
@@ -785,7 +798,7 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
     uint8_t eth_masked[ETH_ADDR_LEN];
     struct in6_addr ipv6_masked;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         if ((a->reg_masks[i] & b->reg_masks[i]) != b->reg_masks[i]) {
@@ -823,6 +836,7 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
             || (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask
             || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask
             || (a->vlan_tci_mask & b->vlan_tci_mask) != b->vlan_tci_mask
+            || (a->metadata_mask & b->metadata_mask) != b->metadata_mask
             || (a->tp_src_mask & b->tp_src_mask) != b->tp_src_mask
             || (a->tp_dst_mask & b->tp_dst_mask) != b->tp_dst_mask);
 }
diff --git a/lib/flow.h b/lib/flow.h
index 2958ff5..7fd4553 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -34,7 +34,7 @@ struct ofpbuf;
 /* This sequence number should be incremented whenever anything involving flows
  * or the wildcarding of flows changes.  This will cause build assertion
  * failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 11
+#define FLOW_WC_SEQ 12
 
 #define FLOW_N_REGS 8
 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -53,6 +53,7 @@ BUILD_ASSERT_DECL(FLOW_NW_FRAG_LATER == NX_IP_FRAG_LATER);
 
 struct flow {
     ovs_be64 tun_id;            /* Encapsulating tunnel ID. */
+    ovs_be64 metadata;          /* OpenFlow Metadata. */
     struct in6_addr ipv6_src;   /* IPv6 source address. */
     struct in6_addr ipv6_dst;   /* IPv6 destination address. */
     struct in6_addr nd_target;  /* IPv6 neighbor discovery (ND) target. */
@@ -84,6 +85,9 @@ struct flow_metadata {
     ovs_be64 tun_id;                 /* Encapsulating tunnel ID. */
     ovs_be64 tun_id_mask;            /* 1-bit in each significant tun_id bit.*/
 
+    ovs_be64 metadata;               /* OpenFlow 1.1+ Metadata field. */
+    ovs_be64 metadata_mask;          /* 1-bit in each significant tun_id bit.*/
+
     uint32_t regs[FLOW_N_REGS];      /* Registers. */
     uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */
 
@@ -92,17 +96,17 @@ struct flow_metadata {
 
 /* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct
  * flow", followed by FLOW_PAD_SIZE bytes of padding. */
-#define FLOW_SIG_SIZE (110 + FLOW_N_REGS * 4)
+#define FLOW_SIG_SIZE (118 + FLOW_N_REGS * 4)
 #define FLOW_PAD_SIZE 2
 BUILD_ASSERT_DECL(offsetof(struct flow, nw_frag) == FLOW_SIG_SIZE - 1);
 BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_frag) == 1);
 BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 142 && FLOW_WC_SEQ == 11);
+BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 150 && FLOW_WC_SEQ == 12);
 
 void flow_extract(struct ofpbuf *, uint32_t priority, ovs_be64 tun_id,
-                  uint16_t in_port, struct flow *);
+                  ovs_be64 metadata, uint16_t in_port, struct flow *);
 void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
 void flow_get_metadata(const struct flow *, struct flow_metadata *);
 
@@ -158,7 +162,7 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t;
 #define FWW_ALL         ((OVS_FORCE flow_wildcards_t) (((1 << 9)) - 1))
 
 /* Remember to update FLOW_WC_SEQ when adding or removing FWW_*. */
-BUILD_ASSERT_DECL(FWW_ALL == ((1 << 9) - 1) && FLOW_WC_SEQ == 11);
+BUILD_ASSERT_DECL(FWW_ALL == ((1 << 9) - 1) && FLOW_WC_SEQ == 12);
 
 /* Information on wildcards for a flow, as a supplement to "struct flow".
  *
@@ -166,6 +170,7 @@ BUILD_ASSERT_DECL(FWW_ALL == ((1 << 9) - 1) && FLOW_WC_SEQ 
== 11);
  * the rest of the members. */
 struct flow_wildcards {
     ovs_be64 tun_id_mask;       /* 1-bit in each significant tun_id bit. */
+    ovs_be64 metadata_mask;     /* 1-bit in each significant metadata bit. */
     flow_wildcards_t wildcards; /* 1-bit in each FWW_* wildcarded field. */
     uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */
     ovs_be32 nw_src_mask;       /* 1-bit in each significant nw_src bit. */
@@ -184,7 +189,7 @@ struct flow_wildcards {
 };
 
 /* Remember to update FLOW_WC_SEQ when updating struct flow_wildcards. */
-BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 120 && FLOW_WC_SEQ == 11);
+BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 128 && FLOW_WC_SEQ == 12);
 
 void flow_wildcards_init_catchall(struct flow_wildcards *);
 void flow_wildcards_init_exact(struct flow_wildcards *);
diff --git a/lib/learn.c b/lib/learn.c
index cbecb10..5478b74 100644
--- a/lib/learn.c
+++ b/lib/learn.c
@@ -184,7 +184,7 @@ learn_check(const struct nx_action_learn *learn, const 
struct flow *flow)
                      * prerequisites.  No prerequisite depends on the value of
                      * a field that is wider than 64 bits.  So just skip
                      * setting it entirely. */
-                    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+                    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
                 }
             }
         }
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 6b74f82..bba663b 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -465,7 +465,7 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn,
     pkt_ofs = offsetof(struct ofp_packet_in, data);
     pkt_len = ntohs(opi->header.length) - pkt_ofs;
     ofpbuf_use_const(&pkt, opi->data, pkt_len);
-    flow_extract(&pkt, 0, 0, in_port, &flow);
+    flow_extract(&pkt, 0, htonll(0), htonll(0), in_port, &flow);
 
     /* Choose output port. */
     out_port = lswitch_choose_destination(sw, &flow);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index b3a4bff..2d67869 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -56,6 +56,15 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         NXM_NX_TUN_ID, "NXM_NX_TUN_ID",
         0, NULL,
     }, {
+        MFF_METADATA, "metadata", NULL,
+        MF_FIELD_SIZES(be64),
+        MFM_FULLY, 0,
+        MFS_HEXADECIMAL,
+        MFP_NONE,
+        true,
+        0, NULL,
+        OXM_OF_METADATA, "OXM_OF_METADATA",
+    }, {
         MFF_IN_PORT, "in_port", NULL,
         MF_FIELD_SIZES(be16),
         MFM_NONE, FWW_IN_PORT,
@@ -590,6 +599,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct 
flow_wildcards *wc)
 
     case MFF_TUN_ID:
         return !wc->tun_id_mask;
+    case MFF_METADATA:
+        return !wc->metadata_mask;
 
 #if FLOW_N_REGS > 0
     case MFF_REG0:
@@ -700,6 +711,9 @@ mf_get_mask(const struct mf_field *mf, const struct 
flow_wildcards *wc,
     case MFF_TUN_ID:
         mask->be64 = wc->tun_id_mask;
         break;
+    case MFF_METADATA:
+        mask->be64 = wc->metadata_mask;
+        break;
 
 #if FLOW_N_REGS > 0
     case MFF_REG0:
@@ -899,6 +913,7 @@ mf_is_value_valid(const struct mf_field *mf, const union 
mf_value *value)
 {
     switch (mf->id) {
     case MFF_TUN_ID:
+    case MFF_METADATA:
     case MFF_IN_PORT:
 #if FLOW_N_REGS > 0
     case MFF_REG0:
@@ -989,6 +1004,9 @@ mf_get_value(const struct mf_field *mf, const struct flow 
*flow,
     case MFF_TUN_ID:
         value->be64 = flow->tun_id;
         break;
+    case MFF_METADATA:
+        value->be64 = flow->metadata;
+        break;
 
     case MFF_IN_PORT:
         value->be16 = htons(flow->in_port);
@@ -1157,6 +1175,9 @@ mf_set_value(const struct mf_field *mf,
     case MFF_TUN_ID:
         cls_rule_set_tun_id(rule, value->be64);
         break;
+    case MFF_METADATA:
+        cls_rule_set_metadata(rule, value->be64);
+        break;
 
     case MFF_IN_PORT:
         cls_rule_set_in_port(rule, ntohs(value->be16));
@@ -1327,6 +1348,9 @@ mf_set_flow_value(const struct mf_field *mf,
     case MFF_TUN_ID:
         flow->tun_id = value->be64;
         break;
+    case MFF_METADATA:
+        flow->metadata = value->be64;
+        break;
 
     case MFF_IN_PORT:
         flow->in_port = ntohs(value->be16);
@@ -1506,6 +1530,8 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule 
*rule)
     case MFF_TUN_ID:
         cls_rule_set_tun_id_masked(rule, htonll(0), htonll(0));
         break;
+    case MFF_METADATA:
+        cls_rule_set_metadata_masked(rule, htonll(0), htonll(0));
 
     case MFF_IN_PORT:
         rule->wc.wildcards |= FWW_IN_PORT;
@@ -1725,6 +1751,9 @@ mf_set(const struct mf_field *mf,
     case MFF_TUN_ID:
         cls_rule_set_tun_id_masked(rule, value->be64, mask->be64);
         break;
+    case MFF_METADATA:
+        cls_rule_set_metadata_masked(rule, value->be64, mask->be64);
+        break;
 
 #if FLOW_N_REGS > 0
     case MFF_REG0:
@@ -1884,6 +1913,7 @@ mf_random_value(const struct mf_field *mf, union mf_value 
*value)
 
     switch (mf->id) {
     case MFF_TUN_ID:
+    case MFF_METADATA:
     case MFF_IN_PORT:
 #if FLOW_N_REGS > 0
     case MFF_REG0:
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index ffde5cc..287ad67 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -32,6 +32,7 @@ struct ds;
 enum mf_field_id {
     /* Metadata. */
     MFF_TUN_ID,                 /* be64 */
+    MFF_METADATA,               /* be64 */
     MFF_IN_PORT,                /* be16 */
 
 #if FLOW_N_REGS > 0
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 920184c..92e94f8 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -487,7 +487,7 @@ nx_put_match(struct ofpbuf *b, bool oxm, const struct 
cls_rule *cr,
     int match_len;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     /* Metadata. */
     if (!(wc & FWW_IN_PORT)) {
@@ -584,6 +584,9 @@ nx_put_match(struct ofpbuf *b, bool oxm, const struct 
cls_rule *cr,
                     htonl(flow->regs[i]), htonl(cr->wc.reg_masks[i]));
     }
 
+    /* OpenFlow 1.1+ Metadata. */
+    nxm_put_64m(b, OXM_OF_METADATA, flow->metadata, cr->wc.metadata_mask);
+
     /* Cookie. */
     nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask);
 
diff --git a/lib/nx-match.h b/lib/nx-match.h
index 22db477..ea6047c 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -90,7 +90,7 @@ void nxm_decode(struct mf_subfield *, ovs_be32 header, 
ovs_be16 ofs_nbits);
 void nxm_decode_discrete(struct mf_subfield *, ovs_be32 header,
                          ovs_be16 ofs, ovs_be16 n_bits);
 
-BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 /* Upper bound on the length of an nx_match.  The longest nx_match (an
  * IPV6 neighbor discovery message using 5 registers) would be:
  *
@@ -111,6 +111,7 @@ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
  *  NXM_OF_IPV6_LABEL   4       4    --      8
  *  NXM_OF_ICMP_TYPE    4       1    --      5
  *  NXM_OF_ICMP_CODE    4       1    --      5
+ *  NXM_OF_METADATA     4       8     8     20
  *  NXM_NX_ND_TARGET    4      16    16     36
  *  NXM_NX_ND_SLL       4       6    --     10
  *  NXM_NX_REG_W(0)     4       4     4     12
@@ -123,7 +124,7 @@ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
  *  NXM_NX_REG_W(7)     4       4     4     12
  *  NXM_NX_TUN_ID_W     4       8     8     20
  *  -------------------------------------------
- *  total                                  333
+ *  total                                  353
  *
  * So this value is conservative.
  */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 9f77c5a..3916934 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -61,7 +61,7 @@ ofp_packet_to_string(const void *data, size_t len)
     struct flow flow;
 
     ofpbuf_use_const(&buf, data, len);
-    flow_extract(&buf, 0, 0, 0, &flow);
+    flow_extract(&buf, 0, htonll(0), htonll(0), 0, &flow);
     flow_format(&ds, &flow);
 
     if (buf.l7) {
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 6d820b2..776f167 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -103,7 +103,7 @@ static const flow_wildcards_t WC_INVARIANTS = 0
 void
 ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     /* Initialize most of rule->wc. */
     flow_wildcards_init_catchall(wc);
@@ -416,9 +416,8 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match 
*match,
     }
 
     if (match->metadata_mask != htonll(UINT64_MAX)) {
-        /* Metadata field not yet supported because we haven't decided how to
-         * map it onto our existing fields (or whether to add a new field). */
-        return OFPERR_OFPBMC_BAD_FIELD;
+        cls_rule_set_metadata_masked(rule, match->metadata,
+                                     ~match->metadata_mask);
     }
 
     return 0;
@@ -512,8 +511,8 @@ ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule,
     wc |= OFPFW11_MPLS_LABEL;
     wc |= OFPFW11_MPLS_TC;
 
-    /* Metadata field not yet supported */
-    match->metadata_mask = htonll(UINT64_MAX);
+    match->metadata = rule->flow.metadata;
+    match->metadata_mask = ~rule->wc.metadata_mask;
 
     match->wildcards = htonl(wc);
 }
@@ -1442,7 +1441,7 @@ ofputil_usable_protocols(const struct cls_rule *rule)
 {
     const struct flow_wildcards *wc = &rule->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
     if (!eth_mask_is_exact(wc->dl_src_mask)
@@ -1454,6 +1453,11 @@ ofputil_usable_protocols(const struct cls_rule *rule)
         return OFPUTIL_P_NXM_ANY;
     }
 
+    /* NXM and OF1.1+ support matching metadata. */
+    if (wc->metadata_mask != htonll(0)) {
+        return OFPUTIL_P_NXM_ANY;
+    }
+
     /* Only NXM supports matching ARP hardware addresses. */
     if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) {
         return OFPUTIL_P_NXM_ANY;
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 962df15..55abff8 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -3044,7 +3044,8 @@ handle_miss_upcalls(struct ofproto_dpif *ofproto, struct 
dpif_upcall *upcalls,
             continue;
         }
         flow_extract(upcall->packet, miss->flow.skb_priority,
-                     miss->flow.tun_id, miss->flow.in_port, &miss->flow);
+                     miss->flow.tun_id, miss->flow.metadata,
+                     miss->flow.in_port, &miss->flow);
 
         /* Add other packets to a to-do list. */
         hash = flow_hash(&miss->flow, 0);
@@ -4673,7 +4674,7 @@ send_packet(const struct ofport_dpif *ofport, struct 
ofpbuf *packet)
     struct flow flow;
     int error;
 
-    flow_extract((struct ofpbuf *) packet, 0, 0, 0, &flow);
+    flow_extract((struct ofpbuf *) packet, 0, 0, 0, 0, &flow);
     odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
                                       flow.vlan_tci);
     if (odp_port != ofport->odp_port) {
@@ -6652,14 +6653,16 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int 
argc, const char *argv[],
             packet = ofpbuf_new(0);
             flow_compose(packet, &flow);
         }
-    } else if (argc == 6) {
+    } else if (argc == 7) {
         /* ofproto/trace dpname priority tun_id in_port packet */
         const char *priority_s = argv[2];
         const char *tun_id_s = argv[3];
-        const char *in_port_s = argv[4];
-        const char *packet_s = argv[5];
+        const char *metadata_s = argv[4];
+        const char *in_port_s = argv[5];
+        const char *packet_s = argv[6];
         uint16_t in_port = ofp_port_to_odp_port(atoi(in_port_s));
         ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0));
+        ovs_be64 metadata = htonll(strtoull(metadata_s, NULL, 0));
         uint32_t priority = atoi(priority_s);
         const char *msg;
 
@@ -6674,7 +6677,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int 
argc, const char *argv[],
         ds_put_cstr(&result, s);
         free(s);
 
-        flow_extract(packet, priority, tun_id, in_port, &flow);
+        flow_extract(packet, priority, tun_id, metadata, in_port, &flow);
         initial_tci = flow.vlan_tci;
     } else {
         unixctl_command_reply_error(conn, "Bad command syntax");
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index f538869..4c6a9b8 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1872,7 +1872,7 @@ rule_execute(struct rule *rule, uint16_t in_port, struct 
ofpbuf *packet)
 
     assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
 
-    flow_extract(packet, 0, 0, in_port, &flow);
+    flow_extract(packet, 0, 0, 0, in_port, &flow);
     return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
 }
 
@@ -2039,7 +2039,7 @@ handle_packet_out(struct ofconn *ofconn, const struct 
ofp_packet_out *opo)
     }
 
     /* Send out packet. */
-    flow_extract(payload, 0, 0, po.in_port, &flow);
+    flow_extract(payload, 0, 0, 0, po.in_port, &flow);
     error = p->ofproto_class->packet_out(p, payload, &flow,
                                          po.actions, po.n_actions);
     ofpbuf_delete(payload);
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index b302dee..844e538 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -278,7 +278,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \
 50 00 02 00 26 e8 00 00 00 00 00 00 00 00 \
 "], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 
buffer=0x00000111
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:06) type:0800 proto:6 tos:0 ttl:64 
ip(192.168.0.1->192.168.0.2) port(10031->0) tcp_csum:26e8
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:06) type:0800 proto:6 tos:0 ttl:64 
ip(192.168.0.1->192.168.0.2) port(10031->0) tcp_csum:26e8
 ])
 AT_CLEANUP
 
@@ -775,7 +775,7 @@ ff ff ff ff 00 40 01 07 00 00 00 00 00 00 00 09 \
 31 6d 00 00 00 00 00 00 00 00 \
 "], [0], [dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) 
data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
 ])
 AT_CLEANUP
 
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 9c3e0dc..fe76fcd 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -97,7 +97,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 
'in_port(1),eth(src=50:54:00:00:00:05,dst
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): table_id=1 total_len=42 in_port=1 tun_id=0x0 reg0=0x0 
reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 (via 
invalid_ttl) data_len=42 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:1 tos:0 ttl:1 
ip(192.168.0.1->192.168.0.2)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:1 tos:0 ttl:1 
ip(192.168.0.1->192.168.0.2)
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -262,13 +262,13 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
 ])
 
 dnl Singleton controller action.
@@ -281,13 +281,13 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
 ])
 
 dnl Modified controller action.
@@ -300,13 +300,13 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:15,pcp:0) 
mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:15,pcp:0) 
mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:15,pcp:0) 
mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:15,pcp:0) 
mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:15,pcp:0) 
mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:15,pcp:0) 
mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
 ])
 
 dnl Checksum TCP.
@@ -319,31 +319,31 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 reg0=0x0 
reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 (via action) 
data_len=60 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->192.168.0.2) port(8->11) tcp_csum:1a03
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->192.168.0.2) port(8->11) tcp_csum:1a03
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(8->11) tcp_csum:3205
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(8->11) tcp_csum:3205
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->11) tcp_csum:31b8
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->11) tcp_csum:31b8
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
 ])
 
 dnl Checksum UDP.
@@ -356,31 +356,31 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 reg0=0x0 
reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 (via action) 
data_len=60 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 
tun_id=0x0 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x0 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->192.168.0.2) port(8->11) udp_csum:2c37
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->192.168.0.2) port(8->11) udp_csum:2c37
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(8->11) udp_csum:4439
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(8->11) udp_csum:4439
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->11) udp_csum:43ec
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->11) udp_csum:43ec
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 
tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 reg5=0x0 reg6=0x0 
reg7=0x0 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) 
mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 
ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
 ])
 
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
diff --git a/tests/ofproto.at b/tests/ofproto.at
index dbe31c4..8312ce5 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -580,21 +580,21 @@ check_async () {
     ovs-ofctl -v packet-out br0 none controller '0001020304050010203040501234'
     if test X"$1" = X"OFPR_ACTION"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via action) 
data_len=14 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)"
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)"
     fi
 
     # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
     ovs-ofctl -v packet-out br0 none 'controller(reason=no_match,id=123)' 
'0001020304050010203040501234'
     if test X"$1" = X"OFPR_NO_MATCH"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via 
no_match) data_len=14 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)"
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)"
     fi
 
     # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
     ovs-ofctl packet-out br0 none dec_ttl 
'002583dfb4000026b98cb0f908004500003fb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
     if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=76 in_port=NONE (via 
invalid_ttl) data_len=76 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(00:26:b9:8c:b0:f9->00:25:83:df:b4:00) type:0800 proto:17 tos:0 ttl:0 
ip(172.17.55.13->172.16.0.2) port(55155->53) udp_csum:8f6d"
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:26:b9:8c:b0:f9->00:25:83:df:b4:00) type:0800 proto:17 tos:0 ttl:0 
ip(172.17.55.13->172.16.0.2) port(55155->53) udp_csum:8f6d"
     fi
 
     # OFPT_PORT_STATUS, OFPPR_ADD
@@ -692,9 +692,9 @@ ovs-appctl -t ovs-ofctl exit
 
 AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
 OFPT_PACKET_IN: total_len=14 in_port=NONE (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)
 OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 
(unbuffered)
-priority:0,tunnel:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:5678 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:5678 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)
 OFPT_BARRIER_REPLY:
 ])
 
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index a4fa7e4..21b2711 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -931,12 +931,30 @@ dnl mpls_label and mpls_tc must be ignored if dl_type is 
not MPLS:
 0000 00 00 1234 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
 12345678 5a 000000 0000000000000000ffffffffffffffff
 
-dnl metadata match not yet supported:
-# bad ofp11_match: OFPBMC_BAD_FIELD
+dnl metadata match:
+# metadata=0x1234567890abcdef
+0000 0058 00000000 000003ff dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 1234567890abcdef0000000000000000
+
+dnl metadata match:
+# metadata=0x5555555555555555/0x5555555555555555
 0000 0058 00000000 000003ff dnl
 000000000000ffffffffffff 000000000000ffffffffffff dnl
 0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
-00000000 00 000000 0000000000000001fffffffffffffffe
+00000000 00 000000 5555555555555555aaaaaaaaaaaaaaaa
+
+dnl metadata match:
+# metadata=0x1234000090ab0000/0xffff0000ffff0000
+# 74: 56 -> 00
+# 75: 78 -> 00
+# 78: cd -> 00
+# 79: ef -> 00
+0000 0058 00000000 000003ff dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 1234567890abcdef0000ffff0000ffff
 
 ])
 sed '/^[[#&]]/d' < test-data > input.txt
@@ -974,6 +992,12 @@ AT_DATA([oxm.txt], [dnl
 OXM_OF_IN_PORT(00000000)
 OXM_OF_IN_PORT(fffffffe)
 
+# metadata
+OXM_OF_METADATA(5a5a5a5a5a5a5a5a)
+OXM_OF_METADATA_W(0000000000000000/00000000ffffffff)
+OXM_OF_METADATA_W(1234567890abcdef/ffff0000ffff0000)
+OXM_OF_METADATA_W(1234567890abcdef/ffffffffffffffff)
+
 # eth dst
 OXM_OF_ETH_DST(0002e30f80a4)
 OXM_OF_ETH_DST_W(010000000000/010000000000)
@@ -1104,6 +1128,12 @@ AT_CHECK([ovs-ofctl --strict parse-oxm < oxm.txt], [0], 
[dnl
 OXM_OF_IN_PORT(00000000)
 OXM_OF_IN_PORT(fffffffe)
 
+# metadata
+OXM_OF_METADATA(5a5a5a5a5a5a5a5a)
+OXM_OF_METADATA_W(0000000000000000/00000000ffffffff)
+OXM_OF_METADATA_W(1234000090ab0000/ffff0000ffff0000)
+OXM_OF_METADATA(1234567890abcdef)
+
 # eth dst
 OXM_OF_ETH_DST(0002e30f80a4)
 OXM_OF_ETH_DST_W(010000000000/010000000000)
diff --git a/tests/test-flows.c b/tests/test-flows.c
index 33417e0..b36226b 100644
--- a/tests/test-flows.c
+++ b/tests/test-flows.c
@@ -68,7 +68,7 @@ main(int argc OVS_UNUSED, char *argv[])
             ovs_fatal(retval, "error reading pcap file");
         }
 
-        flow_extract(packet, 0, 0, 1, &flow);
+        flow_extract(packet, 0, 0, 0, 1, &flow);
         cls_rule_init_exact(&flow, 0, &rule);
         ofputil_cls_rule_to_ofp10_match(&rule, &extracted_match);
 
-- 
1.7.2.5

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

Reply via email to