[ovs-dev] [PATCH 2/2] Adds parsing of OpenFlow 1.1+ Metadata

Joe Stringer joe at wand.net.nz
Wed Jun 27 03:21:36 UTC 2012


On 27 June 2012 01:09, Joe Stringer <joe at wand.net.nz> wrote:
> Signed-off-by: Joe Stringer <joe at wand.net.nz>
> ---
> v3: Add test to see that metadata gets encoded in NXAST packet_in messages.
> ---
>  lib/classifier.c      |   30 ++++++++++++++-
>  lib/classifier.h      |    3 ++
>  lib/flow.c            |   33 ++++++++++++-----
>  lib/flow.h            |   15 +++++---
>  lib/learn.c           |    2 +-
>  lib/meta-flow.c       |   30 +++++++++++++++
>  lib/meta-flow.h       |    1 +
>  lib/nx-match.c        |    5 ++-
>  lib/nx-match.h        |    2 +-
>  lib/ofp-print.c       |    7 ++++
>  lib/ofp-util.c        |   24 +++++++++----
>  tests/ofp-print.at    |   13 ++++---
>  tests/ofproto-dpif.at |   94 ++++++++++++++++++++++++------------------------
>  tests/ofproto.at      |   38 +++++++++++++++++---
>  tests/ovs-ofctl.at    |   36 +++++++++++++++++--
>  15 files changed, 245 insertions(+), 88 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/flow.c b/lib/flow.c
> index 46e0e2d..d90a738 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -444,12 +444,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 +499,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 +526,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 +593,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 +603,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 +618,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 +628,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 +645,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 +654,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 +680,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 +689,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 +718,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 +733,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 +748,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 +760,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 +797,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 +835,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..0e01421 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;
> +    ovs_be64 metadata_mask;
> +
>     uint32_t regs[FLOW_N_REGS];      /* Registers. */
>     uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */
>
> @@ -92,14 +96,14 @@ 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 *);
> @@ -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/meta-flow.c b/lib/meta-flow.c
> index 27c97ec..3cb4578 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 05466ec..42bd73f 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..b8d194b 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:
>  *
> diff --git a/lib/ofp-print.c b/lib/ofp-print.c
> index 9f77c5a..cf9d93f 100644
> --- a/lib/ofp-print.c
> +++ b/lib/ofp-print.c
> @@ -113,6 +113,13 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
>         }
>     }
>
> +    if (pin.fmd.metadata_mask) {
> +        ds_put_format(string, " metadata=0x%"PRIx64, ntohll(pin.fmd.metadata));
> +        if (pin.fmd.metadata_mask != htonll(UINT64_MAX)) {
> +            ds_put_format(string, "/0x%"PRIx64, ntohll(pin.fmd.metadata_mask));
> +        }
> +    }
> +
>     for (i = 0; i < FLOW_N_REGS; i++) {
>         if (pin.fmd.reg_masks[i]) {
>             ds_put_format(string, " reg%d=0x%"PRIx32, i, pin.fmd.regs[i]);
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index cc3c9fd..0ad23c7 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;
> @@ -2371,6 +2375,9 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
>         pin->fmd.tun_id = rule.flow.tun_id;
>         pin->fmd.tun_id_mask = rule.wc.tun_id_mask;
>
> +        pin->fmd.metadata = rule.flow.metadata;
> +        pin->fmd.metadata_mask = rule.wc.metadata_mask;
> +
>         memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs);
>         memcpy(pin->fmd.reg_masks, rule.wc.reg_masks,
>                sizeof pin->fmd.reg_masks);
> @@ -2423,6 +2430,9 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
>         cls_rule_init_catchall(&rule, 0);
>         cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id,
>                                    pin->fmd.tun_id_mask);
> +        cls_rule_set_metadata_masked(&rule, pin->fmd.metadata,
> +                                   pin->fmd.metadata_mask);
> +
>
>         for (i = 0; i < FLOW_N_REGS; i++) {
>             cls_rule_set_reg_masked(&rule, i, pin->fmd.regs[i],
> diff --git a/tests/ofp-print.at b/tests/ofp-print.at
> index b302dee..c7b4ddb 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
>
> @@ -762,20 +762,21 @@ AT_CLEANUP
>  AT_SETUP([NXT_PACKET_IN])
>  AT_KEYWORDS([ofp-print])
>  AT_CHECK([ovs-ofctl ofp-print "\
> -01 04 00 aa 00 00 00 00 00 00 23 20 00 00 00 11 \
> +01 04 00 ba 00 00 00 00 00 00 23 20 00 00 00 11 \
>  ff ff ff ff 00 40 01 07 00 00 00 00 00 00 00 09 \
> -00 3a 00 00 00 00 00 00 00 00 00 02 00 01 00 01 \
> +00 4e 00 00 00 00 00 00 00 00 00 02 00 01 00 01 \
>  20 08 00 00 00 00 00 00 00 06 00 01 00 04 00 00 \
>  00 01 00 01 02 04 00 00 00 02 00 01 04 04 00 00 \
>  00 03 00 01 06 04 00 00 00 04 00 01 08 04 00 00 \
> -00 05 00 00 00 00 00 00 00 00 82 82 82 82 82 82 \
> +00 05 80 00 05 10 5a 5a 5a 5a 5a 5a 5a 5a ff ff \
> +00 00 ff ff 00 00 00 00 00 00 82 82 82 82 82 82 \
>  80 81 81 81 81 81 81 00 00 50 08 00 45 00 00 28 \
>  00 00 00 00 00 06 32 05 53 53 53 53 54 54 54 54 \
>  00 55 00 56 00 00 00 00 00 00 00 00 50 00 00 00 \
>  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
> +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x5a5a00005a5a0000/0xffff0000ffff0000 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
> +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..924e97a 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -96,8 +96,8 @@ AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --pidfile 2> ofctl_mo
>  AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
>  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)
> +NXT_PACKET_IN (xid=0x0): table_id=1 total_len=42 in_port=1 tun_id=0x0 metadata=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,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.
> @@ -318,32 +318,32 @@ 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
> +NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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
> +NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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
> +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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
> +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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.
> @@ -355,32 +355,32 @@ 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
> +NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 tun_id=0x0 metadata=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,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
> +NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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
> +NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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
> +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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
> +NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x0 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,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..28adf74 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,37 @@ 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:
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +dnl This test checks that metadata is encoded in packet_in structures,
> +dnl supported by NXAST.
> +AT_SETUP([ofproto - packet-out with metadata (NXM)])
> +OVS_VSWITCHD_START
> +
> +# Start a monitor listening for packet-ins.
> +AT_CHECK([ovs-ofctl -P nxm monitor br0 --detach --no-chdir --pidfile])
> +ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
> +ovs-appctl -t ovs-ofctl ofctl/barrier
> +ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
> +AT_CAPTURE_FILE([monitor.log])
> +
> +# Send a packet-out with a load action to set some metadata, and forward to controller
> +AT_CHECK([ovs-ofctl packet-out br0 none 'load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]), controller' '0001020304050010203040501234'])
> +
> +# Stop the monitor and check its output.
> +ovs-appctl -t ovs-ofctl ofctl/barrier
> +ovs-appctl -t ovs-ofctl exit
> +
> +AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
> +NXT_PACKET_IN: total_len=14 in_port=NONE tun_id=0x0 metadata=0xfafafafa5a5a5a5a reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 (via action) data_len=14 (unbuffered)
> +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_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)
> --
> 1.7.2.5
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev

I've just checked this against Ben's newer OXM field names patch, just
need to change the 0,NULL below NXM_NX_TUN_ID and above
OXM_OF_METADATA to fix:
        http://openvswitch.org/pipermail/dev/2012-June/018354.html

Cheers,
Joe



More information about the dev mailing list